[comp.sources.amiga] v89i177: net - network

page%swap@Sun.COM (Bob Page) (09/15/89)

Submitted-by: sas!walker@mcnc.org (Doug Walker)
Posting-number: Volume 89, Issue 177
Archive-name: devices/net.4

# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
#	server/io.c
#	server/lock.c
#	server/main.c
#	server/makefile
#	server/netdnet.c
#	server/server.h
#	server/struct.h
#	server/volume.c
#	subs.c
#	timer.c
#	util/handd.c
#	util/netmount.c
#	util/netstat.c
#	util/netstat.h
#	util/shutdown.c
# This is archive 4 of a 4-part kit.
# This archive created: Fri Sep 15 00:24:40 1989
if `test ! -d server`
then
  mkdir server
  echo "mkdir server"
fi
echo "extracting server/io.c"
sed 's/^X//' << \SHAR_EOF > server/io.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* File Access:            */
X/* RmtRead RmtWrite RmtSeek RmtWaitForChar    */
X/* RmtFindwrite RmtFindin RmtFindout RmtEnd   */
X
X#include "server.h"
X
Xstatic long CurrentPos U_ARGS((GLOBAL, struct DosPacket *));
X
Xstatic long CurrentPos(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   pkt->dp_Type = ACTION_SEEK;
X   pkt->dp_Arg1 = ((struct FileHandle *)global->RP.Arg1)->fh_Arg1;
X   pkt->dp_Arg2 = 0L;
X   pkt->dp_Arg3 = OFFSET_CURRENT;
X   Dispatch(global);
X   return(pkt->dp_Res1);
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                 RmtRead( global, pkt )                                  */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid RmtRead(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X/* Arg1: APTR EFileHandle */
X/* Arg2: APTR Buffer      */
X/* Arg3: Length           */
X{
X   long toread, amount, total, offset;
X
X   BUG(("RmtRead of %d bytes\n", global->RP.Arg3));
X
X   /* 1. Seek 0 to get current position in file
X    * 2. Dispatch read (max NETBUFSIZE bytes)
X    * 3. If error, seek back to original pos
X    * 4. Reply to other side
X    * 5. If more to read, go back to (2)
X    */
X   if((offset = CurrentPos(global, pkt))<0)
X   {
X      BUG(("RmtRead: Seek failed, code %d\n", pkt->dp_Res2));
X      global->RP.Arg1 = pkt->dp_Res1;
X      global->RP.Arg2 = pkt->dp_Res2;
X      return;
X   }
X
X   BUG(("RmtRead: Seek done, position is %d\n", offset));
X
X   /* Arg1 was set by the CurrentPos function to be the filehandle */
X   pkt->dp_Type = ACTION_READ;
X   pkt->dp_Arg2 = (LONG)global->RP.Data;
X   toread       = global->RP.Arg3;
X
X   for(total=0; toread; total+=amount, toread-=amount)
X   {
X      /* If this isn't the first time, wait for confirmation */
X      if(total) GetRPacket(global, global->n.devptr);
X
X      pkt->dp_Arg3 = min(toread, NETBUFSIZE);
X      BUG(("RmtRead: Amount is %d, to read is %d\n", pkt->dp_Arg3, toread));
X      Dispatch(global);
X
X      global->RP.DLen = pkt->dp_Res1;
X      if(PutRPacket(global, global->n.devptr)) pkt->dp_Res1 = -1;
X
X      /* If there was EOF or some kind of error, quit */
X
X      if((amount=pkt->dp_Res1) == 0) break;  /* Normal EOF */
X
X      if(amount < 0)
X      {
X         if(offset >= 0)
X         {
X            /* Seek back to the original pos */
X            pkt->dp_Type = ACTION_SEEK;
X            pkt->dp_Arg2 = offset;
X            pkt->dp_Arg3 = OFFSET_BEGINNING;
X            Dispatch(global);
X         }
X         break;
X      }
X   }
X   BUG(("RmtRead: Done reading, returning\n"));
X   global->n.reply = 0;  /* Don't resend the last packet */
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                      RmtWrite( global, pkt )                            */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid RmtWrite(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X/* Arg1: APTR EFileHandle */
X/* Arg2: APTR Buffer */
X/* Arg3: Length */
X{
X   long offset;
X   BUG(("RmtWrite\n"));
X
X   if((offset = CurrentPos(global, pkt))<0)
X   {
X      BUG(("RmtWrite: Seek failed, code %d\n", pkt->dp_Res2));
X      global->RP.Arg1 = pkt->dp_Res1;
X      global->RP.Arg2 = pkt->dp_Res2;
X      return;
X   }
X
X   pkt->dp_Type = ACTION_WRITE;
X   pkt->dp_Arg2 = (LONG)global->RP.Data;
X
X   while(1)
X   {
X      pkt->dp_Arg3 = global->RP.Arg3;
X      Dispatch(global);
X
X      global->RP.DLen = 0;
X      if(PutRPacket(global, global->n.devptr)) pkt->dp_Res1 = -1;
X      if(pkt->dp_Res1 == -1)
X      {
X         if(offset >= 0)
X         {
X            /* Seek back to where we started */
X            pkt->dp_Type = ACTION_SEEK;
X            pkt->dp_Arg2 = offset;
X            pkt->dp_Arg3 = OFFSET_BEGINNING;
X            Dispatch(global);
X         }
X         break;
X      }
X      if(global->RP.Arg4 == 0) break;  /* no more to write */
X
X      GetRPacket(global, global->n.devptr);
X   }
X   global->n.reply = 0;  /* Don't reply twice */
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                       RmtSeek( global, pkt )                            */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid RmtSeek(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent      */
X/* Arg1: APTR EFileHandle */
X/* Arg2: Position */
X/* Arg3: Mode */
X{
X   BUG(("RmtSeek\n"));
X   pkt->dp_Arg1 = ((struct FileHandle *)global->RP.Arg1)->fh_Arg1;
X   pkt->dp_Arg2 = global->RP.Arg2;
X   pkt->dp_Arg3 = global->RP.Arg3;
X
X   Dispatch(global);
X
X   global->RP.DLen = 0;
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                    RmtFindwrite( global, pkt )                          */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid RmtFindwrite(global,pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X/* ARG1: FileHandle to fill in */
X/* ARG2: Lock for file relative to */
X/* Arg3: Name of file */
X{
X   struct FileHandle *fh;
X   BUG(("RmtFindwrite, lock %lx\n", global->RP.Arg2));
X   BUGBSTR("Filename = ", global->RP.Data);
X
X   if(!(fh=(struct FileHandle *)
X              DosAllocMem(global, sizeof(struct FileHandle))))
X   {
X      global->RP.Arg1 = DOS_FALSE;
X      global->RP.Arg2 = ERROR_NO_FREE_STORE;
X      return;
X   }
X   BUG(("Allocated FileHandle = %lx\n", fh));
X
X   pkt->dp_Arg1 = (LONG)MKBADDR(fh);
X   pkt->dp_Arg2 = global->RP.Arg2;
X   MBSTR(global->RP.Data, global->fib);
X   pkt->dp_Arg3 = (LONG)MKBADDR(global->fib);
X
X   Dispatch(global);
X
X   /* If the open was successful, return the allocated filehandle as Arg3 */
X   if(pkt->dp_Res1 == DOS_FALSE) DosFreeMem((char *)fh);
X   else global->RP.Arg3 = (LONG)fh;
X
X   global->RP.DLen = 0;
X}
X
X/*-------------------------------------------------------------------------*/
X/*                                                                         */
X/*                       RmtEnd( global, pkt )                             */
X/*                                                                         */
X/*-------------------------------------------------------------------------*/
X
Xvoid RmtEnd( global, pkt )
XGLOBAL global;
Xstruct DosPacket *pkt;              /* a pointer to the dos packet sent    */
X{
X   struct FileHandle *fh;
X   BUG(("RmtEnd, freeing %lx\n", global->RP.Arg1));
X
X   pkt->dp_Arg1 = (fh=(struct FileHandle *)global->RP.Arg1)->fh_Arg1;
X
X   Dispatch(global);
X
X   DosFreeMem((char *)fh);
X
X   global->RP.DLen = 0;
X}
SHAR_EOF
echo "extracting server/lock.c"
sed 's/^X//' << \SHAR_EOF > server/lock.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X/* Lock.c - lock manipulation */
X/* RmtLock, RmtDupLock, RmtUnLock */
X
X/*-------------------------------------------------------------------------*/
X/* Structure of a Lock:                                                    */
X/*   struct FileLock {                                                     */
X/*      BPTR fl_Link;             Next lock in the chain of device locks   */
X/*      LONG fl_Key;              Block number of directory or file header */
X/*      LONG fl_Access;           Shared Read (-2) or Exclusive Write (-1) */
X/*      struct MsgPort * fl_Task; Handler process for Lock (Us)            */
X/*      BPTR fl_Volume;           Node in DevInfo structure for Lock       */
X/*      };                                                                 */
X/*-------------------------------------------------------------------------*/
X#include "server.h"
X
Xvoid RmtLock(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   BUG(("RmtLock: lock %lx\n", global->RP.Arg1));
X   BUGBSTR("Locking filename = ", global->RP.Data);
X
X   pkt->dp_Arg1 = global->RP.Arg1;
X   MBSTR(global->RP.Data, global->fib);
X   pkt->dp_Arg2 = (LONG)MKBADDR(global->fib);
X   pkt->dp_Arg3 = global->RP.Arg3;        /* Mode             */
X
X   Dispatch(global);
X
X   global->RP.DLen = 0;
X}
X
Xvoid RmtDupLock(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   BUG(("RmtDupLock\n"));
X   pkt->dp_Arg1 = global->RP.Arg1;
X
X   Dispatch(global);
X
X   global->RP.DLen = 0;
X}
X
Xvoid RmtUnLock(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   BUG(("RmtUnLock\n"));
X   pkt->dp_Arg1 = global->RP.Arg1;
X
X   Dispatch(global);
X
X   global->RP.DLen = 0;
X}
SHAR_EOF
echo "extracting server/main.c"
sed 's/^X//' << \SHAR_EOF > server/main.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
X/* |. o.| || Reserved.  This program may not be distributed without the    */
X/* | .  | || permission of the authors:                            BBS:    */
X/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
X/* |  . |//                                                                */
X/* ======                                                                  */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "server.h"
X
X/* Eventually, make this table work for me - flag significant args,     */
X/* flag args that point into the data table.  This will take care of    */
X/* everything but Examine, ExNext, Read and Write with no special funcs */
X
X/******************************************************************************/
X/******************************************************************************/
X/********************* Dispatch table to handle all packets *******************/
X/******************************************************************************/
X/******************************************************************************/
X#define BP1 1
X#define BP2 2
X#define BP3 4
X#define BP4 8
X
Xtypedef void (*ifuncp)(GLOBAL, struct DosPacket *);
Xstruct LookupTable
X   {
X   ifuncp subr;
X   int flags;
X   };
X
X#define LO_FIRST 0
X#define LO_LAST  34
Xstruct LookupTable lowork[LO_LAST+1] = {
X   { NULL,              0  | 0  | 0  | 0   }, /*  0 - ACTION_NIL            */
X   { NULL,              0  | 0  | 0  | 0   }, /*  1 - Unknown               */
X   { NULL,              BP1| BP2| BP3| 0   }, /*  2 - ACTION_GET_BLOCK      */
X   { NULL,              0  | BP2| BP3| 0   }, /*  3 - Unknown               */
X   { NULL,              BP1| BP2| BP3| 0   }, /*  4 - ACTION_SET_MAP        */
X   { RmtDie,            0  | 0  | 0  | 0   }, /*  5 - ACTION_DIE            */
X   { NULL,              0  | 0  | 0  | 0   }, /*  6 - ACTION_EVENT          */
X   { NULL,              BP1| 0  | 0  | 0   }, /*  7 - ACTION_CURRENT_VOLUME */
X   { RmtLock,           BP1| BP2| 0  | 0   }, /*  8 - ACTION_LOCATE_OBJECT  */
X   { NULL,              BP1| BP2| 0  | 0   }, /*  9 - ACTION_RENAME_DISK    */
X   { NULL,              0  | 0  | 0  | 0   }, /* 10 - Unknown               */
X   { NULL,              0  | 0  | 0  | 0   }, /* 11 - Unknown               */
X   { NULL,              0  | 0  | 0  | 0   }, /* 12 - Unknown               */
X   { NULL,              0  | 0  | 0  | 0   }, /* 13 - Unknown               */
X   { NULL,              0  | 0  | 0  | 0   }, /* 14 - Unknown               */
X   { RmtUnLock,         BP1| 0  | 0  | 0   }, /* 15 - ACTION_FREE_LOCK      */
X   { RmtDelete,         BP1| BP2| 0  | 0   }, /* 16 - ACTION_DELETE_OBJECT  */
X   { RmtRename,         BP1| BP2| BP3| BP4 }, /* 17 - ACTION_RENAME_OBJECT  */
X   { NULL,              0  | 0  | 0  | 0   }, /* 18 - ACTION_MORE_CACHE     */
X   { RmtDupLock,        BP1| 0  | 0  | 0   }, /* 19 - ACTION_COPY_DIR       */
X   { NULL,              0  | 0  | 0  | 0   }, /* 20 - ACTION_WAIT_CHAR      */
X   { RmtSetProtection,  0  | BP2| BP3| 0   }, /* 21 - ACTION_SET_PROTECT    */
X   { RmtCreateDir,      BP1| BP2| 0  | 0   }, /* 22 - ACTION_CREATE_DIR     */
X   { RmtExamine,        BP1| BP2| 0  | 0   }, /* 23 - ACTION_EXAMINE_OBJECT */
X   { RmtExNext,         BP1| BP2| 0  | 0   }, /* 24 - ACTION_EXAMINE_NEXT   */
X   { NULL,              BP1| 0  | 0  | 0   }, /* 25 - ACTION_DISK_INFO      */
X   { RmtInfo,           BP1| BP2| 0  | 0   }, /* 26 - ACTION_INFO           */
X   { NULL,              0  | 0  | 0  | 0   }, /* 27 - ACTION_FLUSH          */
X   { RmtSetComment,     0  | BP2| BP3| BP4 }, /* 28 - ACTION_SET_COMMENT    */
X   { RmtParent,         BP1| 0  | 0  | 0   }, /* 29 - ACTION_PARENT         */
X   { NULL,              BP1| 0  | 0  | 0   }, /* 30 - ACTION_TIMER          */
X   { NULL,              0  | 0  | 0  | 0   }, /* 31 - ACTION_INHIBIT        */
X   { NULL,              BP1| 0  | 0  | 0   }, /* 32 - ACTION_DISK_TYPE      */
X   { NULL,              0  | 0  | 0  | 0   }, /* 33 - ACTION_DISK_CHANGE    */
X   { NULL,              0  | 0  | 0  | 0   }  /* 34 - ACTION_SET_FILE_DATE  */
X      };
X
X#define HI_FIRST 1004
X#define HI_LAST  1008
Xstruct LookupTable hiwork[5] = {
X   { RmtFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_WRITE  - 1004 */
X   { RmtFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_INPUT  - 1005 */
X   { RmtFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_OUTPUT - 1006 */
X   { RmtEnd,            0  | 0  | 0  | 0   }, /* ACTION_END         - 1007 */
X   { RmtSeek,           0  | 0  | 0  | 0   }  /* ACTION_SEEK        - 1008 */
X   };
X
X#define USER_FIRST 2010
X#define USER_LAST  2012
Xstruct LookupTable userwork[3] = {
X   { RmtSetDebug,       0  | 0  | 0  | 0   }, /* ACTION_HANDLER_DEBUG 2010 */
X   { NULL,              BP1| 0  | 0  | 0   }, /* ACTION_SET_TRANS_TYPE2011 */
X   { NULL,              BP1| 0  | 0  | 0   }, /* ACTION_NETWORK_HELLO 2012 */
X   };
X
Xstruct DosLibrary *DOSBase;
X
Xvoid _main(x)
Xchar *x;
X{
X   ifuncp             subr;
X   int                action;
X   struct global      global;
X
X   DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME,0);
X
X   /* Initialize our global data structure */
X   memset((char *)&global, 0, sizeof(struct global));
X   global.n.self   = (struct Process *) FindTask(0L);  /* find myself        */
X   global.n.run    = 1;
X   global.n.port   = &(global.n.self->pr_MsgPort);
X                 /* install our taskid ...   */
X   if(!(global.fib = (char *)
X             DosAllocMem(&global, 2*sizeof(struct FileInfoBlock))))
X   {
X      global.n.run = 0;
X   }
X
X   /* Initialize the intuitext structures for the requesters we might have   */
X   /* to display                                                             */
X   /* Because we have no scruples we can cheat and do this with a couple of  */
X   /* long word assignments.  We leave the acual C code commented out here   */
X   /* so that if this structure ever changed we will still be able to work   */
X#if 0
X   global.n.line1.FrontPen = global.n.line1.BackPen = -1;
X   global.n.line1.DrawMode = JAM1;
X   global.n.line1.LeftEdge = global.n.line1.TopEdge = 4;
X   global.n.line2 = global.n.line1;
X   global.n.line3 = global.n.line1;
X   global.n.retrytxt = global.n.line1;
X   global.n.canceltxt = global.n.line1;
X#else
X   *(long *)&global.n.line1.FrontPen     = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.line1.LeftEdge     = 0x00040004L;  /* 4,4  */
X   *(long *)&global.n.line2.FrontPen     = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.line2.LeftEdge     = 0x0004000EL;  /* 4,14 */
X   *(long *)&global.n.line3.FrontPen     = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.line3.LeftEdge     = 0x00040018L;  /* 4,24 */
X   *(long *)&global.n.retrytxt.FrontPen  = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.retrytxt.LeftEdge  = 0x00040004L;
X   *(long *)&global.n.canceltxt.FrontPen = 0x00010000L | (JAM1<<8);
X   *(long *)&global.n.canceltxt.LeftEdge = 0x00040004L;
X#endif
X   global.n.retrytxt.IText = "Retry";
X   global.n.canceltxt.IText = "Cancel";
X
X
X   /* Should get startup info from external config file */
X   if(InitDevice(&global))
X   {
X      BUG(("****** ERROR INITIALIZING\n"));
X#if DEBUG
X      /* Can't use BUGR - need &global, not global */       
X      request(&global, REQ_GENERAL, "Can't init");
X#endif
X   }
X   else
X   while(global.n.run)   /* start of the real work */
X   {
X      if(GetRPacket(&global, global.n.devptr))
X      {
X         if(!ReSync(&global, global.n.devptr)) continue;
X         break;
X      }
X
X      BUG(("Execute: action #%ld arg1 %lx\n", 
X           global.RP.Type, global.RP.Arg1));
X
X      switch(action = global.pkt->dp_Type = global.RP.Type)
X         {
X         case ACTION_NETWORK_KLUDGE:
X            subr = RmtNetKludge;
X            break;
X         
X         case ACTION_READ:
X            subr = RmtRead;
X            break;
X         case ACTION_WRITE:
X            subr = RmtWrite;
X            break;
X
X         case ACTION_SET_RAW_MODE:
X            subr = NULL;
X            break;
X
X         case ACTION_FIND_WRITE:  /* 1004 */
X         case ACTION_FIND_INPUT:  /* 1005 */
X         case ACTION_FIND_OUTPUT: /* 1006 */
X         case ACTION_END:         /* 1007 */
X         case ACTION_SEEK:        /* 1008 */
X            subr = hiwork[action-HI_FIRST].subr;
X            break;
X
X         case ACTION_HANDLER_DEBUG:  /* 2010 */
X         case ACTION_SET_TRANS_TYPE: /* 2011 */
X         case ACTION_NETWORK_HELLO:  /* 2012 */
X            subr = userwork[action-USER_FIRST].subr;
X            break;
X
X         default:            
X            if ((action >= LO_FIRST) && (action <= LO_LAST))
X               {
X               subr = lowork[action-LO_FIRST].subr;
X               }
X            else
X               subr = NULL;
X         }
X 
X      if(subr != NULL)
X      {
X         global.n.reply = 1;
X         (*subr)(&global, global.pkt);
X      }
X      else
X      {
X         global.RP.Arg1 = DOS_FALSE;
X         global.RP.Arg2 = ERROR_ACTION_NOT_KNOWN;
X         BUG(("Unknown packet type %ld\n",global.RP.Type));
X      }
X
X      /* Now return the packet to them */
X      if (global.n.reply && 
X          PutRPacket(&global, global.n.devptr) &&
X          ReSync(&global, global.n.devptr))
X         break;
X  
X      BUG(("-----\n"));
X   }
X
X   TermDevice(&global);
X
X   BUGTERM()  
X}
X
X#define DEBUG_SPECIAL 0x40000000   /* Mask for handler-defined dbg type*/
X#define DEBUG_SERVER  0x20000000   /* Mask indicating server command   */
X#define DEBUG_SERVWT  0x10000000   /* Wait for debugger to catch us    */
X
Xvoid RmtSetDebug(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X#if DEBUG
X   BUG(("RmtSetDebug: Entry, arg1 %lx\n", global->RP.Arg1))
X   if(global->RP.Arg1 == DEBUG_SERVWT) 
X      cprwait(global);
X   else if(global->RP.Arg1) 
X      BUGINIT()
X   else
X      BUGTERM()
X
X#endif
X   pkt->dp_Res1 = DOS_TRUE;
X}
SHAR_EOF
echo "extracting server/makefile"
sed 's/^X//' << \SHAR_EOF > server/makefile
X#DEBUG  = -dDEBUG=1
XDEBUG  =
X
X#LIBS   = lib:lc.lib lib:amiga.lib define _SysBase = _AbsExecBase
XLIBS   = lib:lc.lib lib:amiga.lib define _SysBase = 4
X
X#LC1FLAGS = -cwusf -b -d $(DEBUG) -d2
XLC1FLAGS =  -cwusf -b -d $(DEBUG) -i/
XLC2FLAGS = -v
X
Xnetdnet-server: netdnet-server.d
X   @blink from $+ to $@ nodebug
X
Xnetser-server: netser-server.d
X   @blink from $+ to $@ nodebug
X
Xnetpar-server: netpar-server.d
X   @blink from $+ to $@ nodebug
X
Xnetsing-server: netsing-server.d
X   @blink from $+ to $@ nodebug
X
Xnetdnet-server.d:  main.o /subs.o file.o dir.o io.o lock.o /sendpkt.o\
X       device.o volume.o dispatch.o netdnet.o /iodnet.o /dnetlib.o /debug.o\
X       /timer.o /request.o
X  @echo >ram:tmp.with "from $+"
X  @assign blinkwith:
X  @blink with ram:tmp.with SC SD VERBOSE BATCH to $@ lib $(LIBS)\
X         map netdnet-server.map hx
X
Xnetsing-server.d:  main.o /subs.o file.o dir.o io.o lock.o /sendpkt.o\
X             device.o volume.o dispatch.o netsing.o iosing.o /debug.o\
X             /timer.o /request.o
X  @echo >ram:tmp.with "from $+"
X  @assign blinkwith:
X  @blink with ram:tmp.with SC SD VERBOSE BATCH to $@ lib $(LIBS)
X
Xnetser-server.d:  main.o /subs.o file.o dir.o io.o lock.o /sendpkt.o\
X             device.o volume.o dispatch.o netser.o /ioser.o /debug.o /timer.o\
X             /request.o
X  @echo >ram:tmp.with "from $+"
X  @assign blinkwith:
X  @blink with ram:tmp.with SC SD VERBOSE BATCH to $@ lib $(LIBS)
X
Xnetpar-server.d:  main.o /subs.o file.o dir.o io.o lock.o /sendpkt.o\
X             device.o volume.o dispatch.o netpar.o /iopar.o /debug.o /timer.o\
X             /request.o
X  @echo >ram:tmp.with "from $+"
X  @assign blinkwith:
X  @blink with ram:tmp.with SC SD VERBOSE BATCH to $@ lib $(LIBS)
X
Xmain.o : main.c server.h /netcomm.h
X @echo "Compiling $<"
X @lc1 -. $(LC1FLAGS) -oram:temp.q $<
X @lc2 -. $(LC2FLAGS) -y -o$@ ram:temp.q
X
X/dnetlib.o : /dnetlib.c
X @echo "Compiling $<"
X @lc1 -. $(LC1FLAGS) -oram:temp.q $<
X @lc2 -. $(LC2FLAGS) -y -o$@ ram:temp.q
SHAR_EOF
echo "extracting server/netdnet.c"
sed 's/^X//' << \SHAR_EOF > server/netdnet.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
X* |_o_o|\\ Copyright (c) 1988 The Software Distillery.  All Rights Reserved *
X* |. o.| ||          Written by Doug Walker                                 *
X* | .  | ||          The Software Distillery                                *
X* | o  | ||          235 Trillingham Lane                                   *
X* |  . |//           Cary, NC 27513                                         *
X* ======             BBS:(919)-471-6436                                     *
X\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "netdnet.h"
X#include "server.h"
X
X#if CPR
Xchar *dbgwind = "CON:0/0/640/160/NETDNET-SERVER/a";
X#endif
X
X#if 0
Xint ReSync(global, ioptr)
XGLOBAL global;
XAPTR ioptr;
X{
X   char c;
X   BUG(("ReSync: Entry\n"))
X
X   if(ioptr)
X   {
X      DEof((struct DChannel *)ioptr);
X
X      if(DRead((struct DChannel *)ioptr, &c, 1) == 1) return(0);
X   }
X   WaitPort(global->n.d.LisPort);
X   if(!(global->n.devptr = (APTR)DAccept(global->n.d.LisPort)) )
X   {
X      BUG(("Failed\n"))
X      return(1);
X   }
X   BUG(("Succeeded!\n"))
X   return(0);
X}
X#else
Xint ReSync(global, ioptr)
XGLOBAL global;
XAPTR ioptr;
X{
X   return(1);
X}
X#endif
X
Xint InitRDevice(global)
XGLOBAL global;
X{
X   BUGP("InitRDevice: Entry")
X
X   global->n.d.LisPort = DListen(PORT_FHANDLER);
X
X   WaitPort(global->n.port);
X   ReplyMsg(GetMsg(global->n.port));  /* Tell DNET we are here */
X
X   if(!global->n.d.LisPort)
X   {
X      BUG(("InitRDevice: Can't init, LisPort %lx\n", global->n.d.LisPort));
X      BUGR("Null LisPort");
X      return(1);
X   }
X
X   /* Wait for a DNET request */
X   Wait(1<<global->n.d.LisPort->mp_SigBit);
X
X   if(!(global->n.devptr = (APTR)DAccept(global->n.d.LisPort)))
X   {
X      BUG(("InitRDevice: Can't DAccept\n"))
X      BUGR("No DAccept")
X   }
X
X   global->n.histimeout = DNETTIMEOUT;
X   global->n.mytimeout  = 0;
X
X   BUGP("InitRDevice: Exit")
X
X   return(0);
X}
X
Xint TermRDevice(global)
XGLOBAL global;
X{
X   
X   if(global->n.d.LisPort)
X   {
X      DNAAccept(global->n.d.LisPort);
X      DUnListen(global->n.d.LisPort);
X   }
X   DeletePort(global->n.devport);
X   return(0);
X}
X
SHAR_EOF
echo "extracting server/server.h"
sed 's/^X//' << \SHAR_EOF > server/server.h
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the authors:                                          BBS:      */
X/* | o  | ||   John Toebes     Dave Baker     John Mainwaring                */
X/* |  . |//                                                                  */
X/* ======                                                                    */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X
X#include "netcomm.h"
X
Xvoid checkdebug U_ARGS((void));
X
X#if DEBUG
X#define BUGCHECK() checkdebug();
X#define BUGINIT()  initdebug(NULL);
X#else
X#define BUGCHECK()
X#define BUGINIT()
X#endif
X
Xtypedef struct global
X   {
X   struct NetGlobal      n;          /* Globals in common with handler     */
X   struct RPacket       RP;          /* Data area for remote node          */
X   struct DosPacket     *pkt;        /* the packet we are processing       */
X   struct StandardPacket *stdpkt;    /* Packet to send to local handlers   */
X   struct MsgPort       *dosport;    /* msgport for DOS device to talk to  */
X   struct RPacket       *rpptr;      /* Points to msg for singlemachine v  */
X   char                 *fib;        /* For use by RmtExamine/RmtExNext    */
X   struct InfoData      *infodata;   /* For use by RmtInfo                 */
X   LONG   rootlock;                  /* Lock on root of ROOT:              */
X   }* GLOBAL;
X
X/* main.c */
Xvoid RmtSetDebug      U_ARGS((GLOBAL, struct DosPacket *));
X
X/* file.c */
Xvoid RmtDelete        U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtRename        U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtSetComment    U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtSetProtection U_ARGS((GLOBAL, struct DosPacket *));
X
X/* io.c */
Xvoid RmtFindwrite U_ARGS((GLOBAL, struct DosPacket *));
X#define RmtFindin RmtFindWrite
X#define RmtFindout RmtFindWrite
Xvoid RmtEnd       U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtRead      U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtWrite     U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtSeek      U_ARGS((GLOBAL, struct DosPacket *));
X
X/* dir.c */
Xvoid RmtCreateDir U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtExamine   U_ARGS((GLOBAL, struct DosPacket *));
X#define RmtExNext RmtExamine
Xvoid RmtParent    U_ARGS((GLOBAL, struct DosPacket *));
X
X/* lock.c */
Xvoid RmtLock    U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtDupLock U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtUnLock  U_ARGS((GLOBAL, struct DosPacket *));
X
X/* volume.c */
Xvoid RmtInfo       U_ARGS((GLOBAL, struct DosPacket *));
Xvoid RmtNetKludge  U_ARGS((GLOBAL, struct DosPacket *));
X
X/* device.c */
Xint InitDevice U_ARGS((GLOBAL));
Xint TermDevice U_ARGS((GLOBAL));
Xvoid RmtDie    U_ARGS((GLOBAL, struct DosPacket *));
X
X/* Dispatch.c */
Xvoid Dispatch    U_ARGS((GLOBAL));
X
X/* inhibit.c */
Xint inhibit  U_ARGS((struct MsgPort *, long));
Xlong sendpkt U_ARGS((struct MsgPort *, long, long*, long));
X
X/* volume.c */
Xvoid RmtInfo       U_ARGS((GLOBAL, struct DosPacket *));
X
X/* net#?.c */
Xint InitRDevice    U_ARGS((GLOBAL));
Xint TermRDevice    U_ARGS((GLOBAL));
X
X#include "/proto.h"
SHAR_EOF
echo "extracting server/struct.h"
sed 's/^X//' << \SHAR_EOF > server/struct.h
X#ifndef DSTRUCT
X#define DSTRUCT
X
X
Xstruct BUFDATA
X{
Xstruct Gadget Gadget1;
Xstruct Gadget Gadget2;
Xstruct Gadget Gadget3;
Xstruct PropInfo Gadget1SInfo;
Xint    pos;
Xint    size;
Xchar   buf[1];
X};
X
Xunion STDATA
X{
X   APTR data;
X   struct BUFDATA *bdata;
X   struct FileInfoBlock *fib;
X   struct FileHandle *fh;
X   struct FileLock *lock;
X   struct InfoData *info;
X};
X
X#define WNAMELEN 20
X
Xstruct STNODE
X{
X   struct STNODE *next, *prev;
X   int len;              /* Length of this allocation, for convenience   */
X   int num;              /* Number of the node within its type           */
X   int type;             /* One of the ST_ defines above                 */
X   union STDATA d;       /* Points to the mem allocted for the struct    */
X   char wname[WNAMELEN]; /* Name of the window                           */
X   char *oname;          /* Name of the object associated with it        */
X   struct Window *w;     /* Points to the window opened to display it    */
X};
X
Xstruct STGLOB
X{
X   struct STNODE *stlist;/* Linked list of STNODE structures             */
X   struct STNODE *unlist;/* Linked list of unlinked nodes                */
X   int count[ST_NUM];    /* How many of each type there are              */
X   struct MsgPort *Port; /* Message port to use for comm with Intuition  */
X};
X
X#define DOTEXT(y, format, val) \
X   sprintf(data, format, val); \
X   PrintIText(n->w->RPort, &IText, 0, y);
X
X
Xvoid stfhnew(struct NewWindow **, struct IntuiText **, struct STNODE *);
Xvoid stlocknew(struct NewWindow **, struct IntuiText **, struct STNODE *);
Xvoid stfibnew(struct NewWindow **, struct IntuiText **, struct STNODE *);
Xvoid stinfnew(struct NewWindow **, struct IntuiText **, struct STNODE *);
Xvoid stbufnew(struct NewWindow **, struct IntuiText **, struct STNODE *);
X
X
Xint stfhdisp(struct STNODE *);
Xint stlockdisp(struct STNODE *);
Xint stfibdisp(struct STNODE *);
Xint stinfdisp(struct STNODE *);
Xint stbufdisp(struct STNODE *);
Xint stbufmove(struct STNODE *, int);
X
X
X#endif
X
SHAR_EOF
echo "extracting server/volume.c"
sed 's/^X//' << \SHAR_EOF > server/volume.c
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the authors:                                          BBS:      */
X/* | o  | ||   John Toebes     Dave Baker                                    */
X/* |  . |//                                                                  */
X/* ======                                                                    */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* Volume Manipulation */
X/* RmtCurentVol  RmtRenameDisk RmtDiskInfo RmtInfo */
X
X#include "server.h"
X
Xvoid RmtInfo(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   BUG(("RmtInfo\n"));
X
X   if(!global->infodata &&
X      !(global->infodata = (struct InfoData *)
X             DosAllocMem(global, sizeof(struct InfoData))))
X   {
X      BUG(("******* OUT OF MEMORY - can't get InfoData\n"));
X      global->RP.Arg1 = DOS_FALSE;
X      global->RP.Arg2 = ERROR_NO_FREE_STORE;
X      return;
X   }
X   pkt->dp_Arg1 = global->RP.Arg1;
X   pkt->dp_Arg2 = (LONG)global->infodata;
X
X   Dispatch(global);
X
X   MQ(global->infodata, global->RP.Data, sizeof(struct InfoData));
X
X   global->RP.DLen = sizeof(struct InfoData);
X}
X
Xvoid RmtNetKludge(global, pkt)
XGLOBAL global;
Xstruct DosPacket *pkt;
X{
X   struct MsgPort *newport;
X
X   if(!(newport=(struct MsgPort *)DeviceProc(global->RP.Data)))
X   {
X      BUG(("********DeviceProc of %s Failed\n", global->RP.Data));
X      BUGGETC
X      pkt->dp_Res1 = DOS_FALSE;
X      pkt->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
X      return;
X   }
X   global->RP.RDevice = (RPTR)(global->dosport = newport);
X   pkt->dp_Res1 = DOS_TRUE;
X   pkt->dp_Res2 = 0L;
X
X   global->n.run++;
X
X   BUG(("RmtNetKludge: New RDevice %lx\n", newport));
X}
X
SHAR_EOF
echo "extracting subs.c"
sed 's/^X//' << \SHAR_EOF > subs.c
X/* Subs.c - Basic network handler support routines */
X
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the author.                                           BBS:      */
X/* | o  | ||   John Toebes                                   (919)-471-6436  */
X/* |  . |//                                                                  */
X/* ======                                                                    */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X#define NETCOMMON
X#include "netcomm.h"
X#include "proto.h"
X/* misc.c  - support routines - Phillip Lindsay (C) Commodore 1986  
X *  You may freely distribute this source and use it for Amiga Development -
X *  as long as the Copyright notice is left intact.
X *
X * 30-SEP-86
X */
X
X/* returnpkt() - packet support routine 
X * here is the guy who sends the packet back to the sender...
X */
X 
Xvoid retpkt(global, packet)
XNGLOBAL global;
Xstruct DosPacket *packet;
X{
X struct Message *mess;
X struct MsgPort *replyport;
X 
X replyport                = packet->dp_Port;
X mess                     = packet->dp_Link;
X packet->dp_Port          = global->n.port;
X 
X PutMsg(replyport,mess); 
X}
X
X/*
X * taskwait() ... Waits for a message to arrive at your port and 
X *   extracts the packet address which is returned to you.
X */
X
Xstruct DosPacket *taskwait(global)
XNGLOBAL global;
X{
X struct Message *mymess;
X
X WaitPort(global->n.port); /* wait for packet */
X mymess = (struct Message *) GetMsg(global->n.port);
X
X global->pkt = (struct DosPacket *) mymess->mn_Node.ln_Name;
X
X return(global->pkt);
X} 
X
Xchar *DosAllocMem(global, len)
XNGLOBAL global;
Xlong len;
X{
Xlong *p;
X
Xif (( p = (long *)AllocMem(len+4, MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
X   {
X   if (global->pkt != NULL)
X      {
X      global->pkt->dp_Res1 = DOS_FALSE;
X      global->pkt->dp_Res2 = ERROR_NO_FREE_STORE;
X      }
X   else
X      {
X      /* Gee.  Out of memory AND there is nobody to tell about it ...  */
X      /* Only choice is to GURU.  Maybe we could do something clever   */
X      /* but I doubt it...                                             */
X      BUG(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
X      BUG(("!!!!!!!!!!!!               !!!!!!!!\n"));
X      BUG(("!!!!!!!!!!!! OUT OF MEMORY !!!!!!!!\n"));
X      BUG(("!!!!!!!!!!!!               !!!!!!!!\n"));
X      BUG(("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"));
X      }
X   }
Xelse
X   *p++ = len;
X
Xreturn((char *)p);
X}
X
Xvoid DosFreeMem(p)
Xchar *p;
X{
Xlong *lp;
Xlong len;
X
X   lp = (long *)p;
X   len = *--lp;
X   FreeMem((char *)lp, len);
X}
X
XLONG checksum(c, len)
Xchar *c;
Xint len;
X{
X   int i, l;
X   LONG sum, *lptr;
X   unsigned char *uc;
X
X   l = len/sizeof(LONG);
X   lptr = (LONG *)c;
X   for(i=0, sum=0; i<l; i++, lptr++) sum += *lptr;
X
X   l = len % sizeof(LONG);
X   uc = (unsigned char *)lptr;
X   for(i=0; i<l; i++, uc++) sum += *uc;
X
X   return(sum);
X}
X
Xvoid CheckRP(r)
Xstruct RPacket *r;
X{
X#ifndef SMALLPACKET
X   /* Get checksum for RP */
X   if(r->DLen)
X      r->DCheck = checksum(r->Data, r->DLen);
X   else
X      r->DCheck = 0L;
X 
X   r->checksum = 0L;
X   r->checksum = checksum((char *)r, RPSIZE);
X#endif
X}
X
SHAR_EOF
echo "extracting timer.c"
sed 's/^X//' << \SHAR_EOF > timer.c
X/* Timer.c - Timer support routines */
X
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X/* |_o_o|\\ Copyright (c) 1987 The Software Distillery.  All Rights Reserved */
X/* |. o.| || This program may not be distributed without the permission of   */
X/* | .  | || the author.                                           BBS:      */
X/* | o  | ||   John Toebes    Dave Baker                     (919)-471-6436  */
X/* |  . |//                                                                  */
X/* ======                                                                    */
X/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
X#define NETCOMMON
X#include "netcomm.h"
X#include "proto.h"
X
Xint OpenTimer(global, port)
XNGLOBAL global;    
Xstruct MsgPort *port;
X{
X   int error;
X
X   /* assumes that a msg port has been allocated */   
X
X   if ((global->n.timerpkt = (struct TimerPacket *)
X                CreateExtIO(port, sizeof(struct TimerPacket)))== NULL)
X     return(1);
X
X   global->n.timerpkt->tm_req.tr_node.io_Message.mn_Node.ln_Name = 
X                              (char *)&(global->n.timerpkt->tm_pkt);
X   global->n.timerpkt->tm_pkt.dp_Link =
X                     &(global->n.timerpkt->tm_req.tr_node.io_Message);
X   global->n.timerpkt->tm_pkt.dp_Port = port;
X
X   error = OpenDevice(TIMERNAME, UNIT_MICROHZ, 
X                     (struct IORequest *)&(global->n.timerpkt->tm_req), 0);
X
X   return(error);
X}
X
Xvoid CloseTimer(global)
XNGLOBAL global;
X{
X   if (global->n.timerpkt != NULL)
X      {
X      CloseDevice((struct IORequest *)&(global->n.timerpkt->tm_req));
X      DeleteExtIO((struct IORequest *)global->n.timerpkt,
X                   sizeof(struct TimerPacket));
X      global->n.timerpkt = NULL;
X      }
X
X}
X
Xvoid PostTimerReq(global, time)
XNGLOBAL global;
Xint time;  /* tenths of a second */
X{
X   /* Fill in the timer packet values */
X   /* that is the fields required for the timer device timerequest struct */
X   /* and the necessary fields of the DosPacket struct                    */
X   /* nothing like using 35 meg of store to accomplish a simple task      */
X   /* oh well ! this is a 68K machine right ?                             */ 
X   /* some of them get trampled on so fill them all */
X
X   if (global->n.timerpkt != NULL)
X      {
X      time *= 100000;
X      global->n.timerpkt->tm_req.tr_node.io_Command = TR_ADDREQUEST;
X      global->n.timerpkt->tm_req.tr_time.tv_secs = time/100000;
X      global->n.timerpkt->tm_req.tr_time.tv_micro = time%100000;
X
X      global->n.timerpkt->tm_pkt.dp_Type = ACTION_TIMER;
X      
X      /* Async IO so we don't sleep here for the msg */
X     
X      SendIO((struct IORequest *)&global->n.timerpkt->tm_req);
X      }
X}
SHAR_EOF
if `test ! -d util`
then
  mkdir util
  echo "mkdir util"
fi
echo "extracting util/handd.c"
sed 's/^X//' << \SHAR_EOF > util/handd.c
X#include <exec/types.h>
X#include <exec/memory.h>
X#include <exec/nodes.h>
X#include <exec/lists.h>
X#include <exec/ports.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <libraries/filehandler.h>
X#include <string.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <proto/exec.h>
X#include <proto/dos.h>
X
X#undef GLOBAL
X/* my version of BADDR() has no problems with casting */
X#undef  BADDR
X#define BADDR(x)        ((APTR)((long)x << 2))
X#define MKBADDR(x)      ((BPTR)((long)x >> 2))
X
X#define ACTION_HANDLER_DEBUG    2010L
X#define DEBUG_SPECIAL 0x40000000
X#define DEBUG_WAIT    0x40000001
X#define DEBUG_SERVER  0x20000000
X#define DEBUG_SERVWT  0x10000000
X
Xchar windowname[50] = "CON:0/1/640/160/Debug ";
X
XLONG sendpkt(struct MsgPort *, long, long*, long, long*);
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X   struct MsgPort *proc;
X   long myargs[8];
X   long myres[2];
X   char *filename, *cmdname, *devname;
X   int freeflag, server, handler;
X
X   cmdname = argv[0];
X   if(argc != 3 && argc != 4 && argc != 5)
X   {
XUSAGE:
X      fprintf(stderr, 
X         "Usage: %s device <SERVER|BOTH> [OPEN|CLOSE|WAIT] <logfile>\n",
X         cmdname);
X      return;
X   }
X   devname = argv[1];
X
X   if ((proc = (struct MsgPort *)DeviceProc(devname)) == NULL)
X   {
X      fprintf(stderr, "Unable to get a device proc for %s\n", devname);
X      goto USAGE;
X   }
X
X   handler = 0;
X   if((server=(!stricmp(argv[2], "SERVER"))) ||
X      (server=handler=(!stricmp(argv[2], "BOTH"))))
X   {
X      if(argc < 4) goto USAGE;
X      argc--, argv++;
X   }
X   else
X      handler = 1;
X
X   if(!stricmp(argv[2], "WAIT"))
X   {
X      freeflag = 0;
X      myargs[0] = DEBUG_WAIT;
X   }
X   else if(!stricmp(argv[2], "CLOSE"))
X   {
X      freeflag = 1;
X      myargs[0] = 0;
X   }
X   else if(!stricmp(argv[2], "OPEN"))
X   {
X      freeflag = 1;
X      myargs[0] = 1;
X      if(handler)
X      {
X         if(argc == 4) filename = argv[3];
X         else
X         {
X            strcat(windowname, devname);
X            strcat(windowname, "/a");
X            filename = windowname;
X         }
X         if(!(myargs[1] = (long)Open(filename, 1006)))
X         {
X            fprintf(stderr, "Can't open output %s '%s'\n",
X               (argc == 4 ? "file" : "window"), filename);
X            goto USAGE;
X         }
X      }
X   }
X   else
X   {
X      fprintf(stderr, "Unknown debugging command '%s'\n", argv[2]);
X      goto USAGE;
X   }
X
X   if(handler)
X   {
X      sendpkt(proc,ACTION_HANDLER_DEBUG,myargs,2,myres);
X      if(freeflag && myres[0] != 0 && myres[1])
X         Close((BPTR)myres[1]);
X   }
X
X   if(server)
X   {
X      myargs[0] |= (DEBUG_SERVER|DEBUG_SPECIAL);
X      sendpkt(proc,ACTION_HANDLER_DEBUG,myargs,2,myres);
X   }
X
X}
X
XLONG sendpkt(pid,action,args,nargs,res)
Xstruct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
XLONG action,          /* packet type ... (what you want handler to do )   */
X     args[],          /* a pointer to a argument list           */
X     nargs,           /* number of arguments in list            */
X     res[];           /* pointer to 2 longs for result, or NULL */
X   {
X   struct MsgPort        *replyport;
X   struct StandardPacket *packet;
X 
X   LONG  count, lres, *pargs;
X
X   replyport = (struct MsgPort *) CreatePort(NULL,0);
X   if(!replyport) return(0L);
X
X   packet = (struct StandardPacket *) 
X      AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
X   if(!packet) 
X      {
X      DeletePort(replyport);
X      return(0L);
X      }
X
X   packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
X   packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
X   packet->sp_Pkt.dp_Port         = replyport;
X   packet->sp_Pkt.dp_Type         = action;
X
X   /* copy the args into the packet */
X   pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
X   for(count=0;count < nargs;count++) 
X      pargs[count]=args[count];
X 
X   PutMsg(pid,(struct Message *)packet); /* send packet */
X
X   WaitPort(replyport);
X   GetMsg(replyport); 
X
X   if(res)
X   {
X      lres = res[0] = packet->sp_Pkt.dp_Res1;
X      res[1] = packet->sp_Pkt.dp_Res2;
X   }
X
X   FreeMem((char *)packet,(long)sizeof(struct StandardPacket));
X   DeletePort(replyport); 
X
X   return(lres);
X}
SHAR_EOF
echo "extracting util/netmount.c"
sed 's/^X//' << \SHAR_EOF > util/netmount.c
X#include <exec/types.h>
X#include <exec/memory.h>
X#include <exec/nodes.h>
X#include <exec/lists.h>
X#include <exec/ports.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <libraries/filehandler.h>
X#include <string.h>
X#include <stdlib.h>
X#include <proto/exec.h>
X#include <proto/dos.h>
X
X#undef GLOBAL
X/* my version of BADDR() has no problems with casting */
X#undef  BADDR
X#define BADDR(x)        ((APTR)((long)x << 2))
X#define MKBADDR(x)      ((BPTR)((long)x >> 2))
X
X#define ACTION_NETWORK_KLUDGE 4674764L   
X
Xlong sendpkt(struct MsgPort *, long, long*, long);
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
Xstruct MsgPort *proc;
Xlong myargs[8];
Xint len1, len2;
Xunsigned char *nodename;
Xchar *devname;
X
X   if (argc != 4)
X   {
X      printf("Usage: %s <netdevice> <nodename> <rmtdevice>\n", argv[0]);
X      return;
X   }
X
X   if(!(nodename = AllocMem(len1=strlen(argv[2])+2, 0)) ||
X      !(devname  = AllocMem(len2=strlen(argv[3]+1), 0)))
X   {
X      printf("Error: No memory\n");
X      return;
X   }
X
X   nodename[0] = strlen(argv[2]);
X   strcpy(nodename+1, argv[2]);
X
X   strcpy(devname, argv[3]);
X
X   myargs[0]=(long)MKBADDR(nodename);
X   myargs[1]=(long)MKBADDR(devname);
X
X   if ((proc = (struct MsgPort *)DeviceProc(argv[1])) == NULL)
X   {
X      printf("Unable to get a device proc for %s\n", argv[1]);
X      return;
X   }
X
X   sendpkt(proc,ACTION_NETWORK_KLUDGE,myargs,2);
X
X   FreeMem(nodename, len1);
X   FreeMem(devname, len2);
X}
X
XLONG sendpkt(pid,action,args,nargs)
Xstruct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
XLONG action,          /* packet type ... (what you want handler to do )   */
X     args[],          /* a pointer to a argument list */
X     nargs;           /* number of arguments in list  */
X   {
X   struct MsgPort        *replyport;
X   struct StandardPacket *packet;
X 
X   LONG  count, *pargs, res1;
X
X   replyport = (struct MsgPort *) CreatePort(NULL,0);
X   if(!replyport) return(NULL);
X
X   packet = (struct StandardPacket *) 
X      AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
X   if(!packet) 
X      {
X      DeletePort(replyport);
X      return(NULL);
X      }
X
X   packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
X   packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
X   packet->sp_Pkt.dp_Port         = replyport;
X   packet->sp_Pkt.dp_Type         = action;
X
X   /* copy the args into the packet */
X   pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
X   for(count=0;count < nargs;count++) 
X      pargs[count]=args[count];
X 
X   PutMsg(pid,(struct Message *)packet); /* send packet */
X
X   WaitPort(replyport);
X   GetMsg(replyport); 
X
X   res1 = packet->sp_Pkt.dp_Res1;
X
X   FreeMem((char *)packet,(long)sizeof(struct StandardPacket));
X   DeletePort(replyport); 
X
X   return(res1);
X}
SHAR_EOF
echo "extracting util/netstat.c"
sed 's/^X//' << \SHAR_EOF > util/netstat.c
X#include <exec/types.h>
X#include <exec/memory.h>
X#include <intuition/intuition.h>
X#include <graphics/gfxmacros.h>
X#include <graphics/rastport.h>
X#include <libraries/dos.h>
X#include <proto/intuition.h>
X#include <proto/dos.h>
X#include <proto/exec.h>
X#include <proto/graphics.h>
X#include <string.h>
X#include "netstat.h"
X
X#define MAXSTATS 300
X#define XOFF      10
X#define YOFF      40
X#define TIMEINTERVAL 1
X#define YMARGIN   12
X#define MINPEAK  400
X#define TEXT1   (6*8) 
X#define TEXT2   (25*8)
X#define XMARGIN   12
X#define MKBADDR(x)      ((BPTR)((long)x >> 2))
X
Xstruct NewWindow NewWindowStructure1 = {
X   0,0,
X   XOFF+MAXSTATS+XMARGIN, YOFF+YMARGIN+50,
X   0,1,
X   MENUPICK+CLOSEWINDOW+REFRESHWINDOW+NEWSIZE,
X   WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+WINDOWSIZING+SIMPLE_REFRESH,
X   NULL,
X   NULL,
X   "Software Distillery NET: Status",
X   NULL,
X   NULL,
X   XOFF+MAXSTATS+XMARGIN,YOFF+YMARGIN+20,
X   9999,9999,
X   WBENCHSCREEN
X};
X
Xint xsize = 300;
Xint ysize = 100;
Xint yscale = 100;
Xlong peak = 0;
X
Xvoid main(int, char **);
Xvoid MemCleanup(void);
Xvoid refresh(void);
Xvoid QueueTimer(struct timerequest *, ULONG);
Xvoid setscale(void);
Xvoid update(void);
Xint dispvals(void);
Xvoid DeleteIOReq(struct IOStdReq *);
Xlong sendpkt(struct MsgPort *, long, long*, long);
Xstruct IOStdReq *CreateIOReq(struct MsgPort *, int);
X
X/* Global variables */
X
Xstruct Window *Window;
Xstruct TmpRas tmpras;
Xlong wstats[MAXSTATS], rstats[MAXSTATS];
Xint statpos;
X
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X   WORD areabuffer[300];
X   struct IntuiMessage *message;
X   int run;
X   ULONG portmask, waitmask, windmask, timemask;
X/* struct MenuItem *item; */
X   struct MsgPort *port;
X   struct AreaInfo myAreaInfo;
X   struct statmsg *statmsg;
X   struct MsgPort *proc;
X   long args[8];
X   struct timerequest *timerreq;
X   struct MsgPort     *timerport;
X
X   timerreq            = NULL;
X   timerport           = NULL;
X   proc                = NULL;
X   Window              = NULL;
X   port                = NULL;
X   args[0]             = 0;
X   if ((IntuitionBase = (struct IntuitionBase *)
X 		       OpenLibrary("intuition.library", 0)) == NULL) goto done;
X   if ((GfxBase = (struct GfxBase *)
X		 OpenLibrary("graphics.library", 0)) == NULL) goto done;
X   if ((Window = OpenWindow(&NewWindowStructure1)) == NULL) goto done;
X
X   if ((port = CreatePort("netstat_port", 0)) == NULL) goto done;
X   if ((timerport = CreatePort(NULL, 0)) == NULL) goto done;
X   if ((timerreq  = (struct timerequest *)
X           CreateIOReq(timerport, sizeof(struct timerequest))) == NULL)
X 	   goto done;
X   if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)timerreq, 0))
X   	   goto done;
X
X   InitArea(&myAreaInfo, areabuffer, 175);
X   Window->RPort->AreaInfo = &myAreaInfo;
X   Window->RPort->TmpRas = InitTmpRas(&tmpras, AllocRaster(600, 175),
X					       RASSIZE(600, 175));
X   if ((argc > 1) &&
X       ((proc = (struct MsgPort *)DeviceProc(argv[1])) != NULL))
X      {
X      args[0] = 0x40000002;
X      args[1] = MKBADDR(port);
X      sendpkt(proc, 2010, args, 2);
X      }
X
X   memset((char *)wstats, 0, sizeof(wstats));
X   memset((char *)rstats, 0, sizeof(rstats));
X   statpos = 0;
X   peak = 0;
X   ysize = Window->Height-(YOFF+YMARGIN);
X   if (ysize < 20) ysize = 20;
X   setscale();
X   refresh();
X
X   run = 0;
X
X   windmask = 1 << Window->UserPort->mp_SigBit;
X   portmask = 1 << port->mp_SigBit;
X   timemask = (1 << timerport->mp_SigBit);
X   QueueTimer(timerreq, TIMEINTERVAL);
X   while(run == 0)
X      {
X      waitmask = Wait(windmask | portmask | timemask);
X      if (waitmask & timemask)
X         {
X         /* get rid of the message */
X         (void)GetMsg(timerport);
X         QueueTimer(timerreq, TIMEINTERVAL);
X         /* Also, we want to scroll the entire thing left one pixel */
X         update();
X
X         statpos ++;
X         if (statpos >= MAXSTATS)
X            statpos = 0;
X         wstats[statpos] = rstats[statpos] = 0;
X         }
X      if (waitmask & portmask)
X         {
X         statmsg = (struct statmsg *)GetMsg(port);
X         if (statmsg->direction)
X            rstats[statpos] += statmsg->count;
X         else
X            wstats[statpos] += statmsg->count;
X         ReplyMsg((struct Message *)statmsg);
X         }
X      if (waitmask & windmask)
X         {
X         while ((message = (struct IntuiMessage *)
X	                   GetMsg(Window->UserPort)) != NULL)
X            {
X            switch(message->Class)
X               {
X               case CLOSEWINDOW:
X                  run = -1;
X                  break;
X#if 0
X               case MENUPICK:
X	          item = ItemAddress(&MenuList1, message->Code);
X                  switch(item->Command)
X                     {
X                     case 1:
X                         run = 1;
X                     default:
X                         run = 1;
X                         break;
X                     }
X                  break;
X#endif
X
X               case NEWSIZE:
X               case REFRESHWINDOW:
X                  ysize = Window->Height-(YOFF+YMARGIN);
X                  if (ysize < 20) ysize = 20;
X                  setscale();
X                  refresh();
X		  break;
X
X               default:
X                  break;
X               }
X            ReplyMsg((struct Message *)message);
X            }
X         }
X      }
X
X   Wait(timemask);
X
X   Window->RPort->TmpRas = NULL;
X   FreeRaster(tmpras.RasPtr, 600, 175);
X
Xdone:
X   if (args[0] && proc != NULL)
X      {
X      args[1] = 0;
X      sendpkt(proc,2010,args,2);
X      }
X
X   /* Reply to any outstanding messages */
X   while(statmsg = (struct statmsg *)GetMsg(port)) 
X      ReplyMsg((struct Message *)statmsg);
X
X   if (timerreq != NULL)
X      {
X      if (timerreq->tr_node.io_Device != NULL)
X         {
X         AbortIO( (struct IORequest *)timerreq );
X         CloseDevice((struct IORequest *)timerreq);
X         }
X      DeleteIOReq((struct IOStdReq *)timerreq);
X      }
X  if (timerport != NULL)     DeletePort(timerport);
X  if (Window != NULL) CloseWindow(Window);
X  if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase);
X  if (GfxBase != NULL)       CloseLibrary((struct Library *)GfxBase);
X  if (port != NULL)          DeletePort(port);
X  XCEXIT(0L);
X}
X
Xvoid setscale()
X{
X/* Now recalculate the scale */
Xif (peak < MINPEAK)
X   yscale = MINPEAK/ysize;
Xelse
X   yscale = (peak*5)/(ysize*4);
X
X}
Xint dispvals()
X{
Xchar buf[80];
Xlong reads, writes, perf;
Xstruct RastPort *rp = Window->RPort;
Xstatic long lr, lw, lp, lk;
X
Xreads = rstats[statpos];
Xwrites = wstats[statpos];
Xperf = reads+writes;
X
X/* Have we hit a new high? */
Xif (perf > peak)
X   {
X   peak = perf;
X   /* Will this shoot off the end of the graph ? */
X   if ((peak/yscale) > ysize)
X      {
X      setscale();
X      return(1);
X      }
X   }
X
XSetAPen(rp, 0);
Xif (lp != perf || lr != reads)
X   RectFill(rp, XOFF+TEXT1, YOFF-28, XOFF+TEXT1+(7*8), YOFF-1);
Xif (lk != peak || lw != writes)
X   RectFill(rp, XOFF+TEXT2, YOFF-28, XOFF+TEXT2+(7*8), YOFF-1);
X
Xlp = perf;
Xlr = reads;
Xlk = peak;
Xlw = writes;
X
XSetAPen(rp, 3);
Xsprintf(buf, "%7d", perf);
XMove(rp, XOFF+TEXT1, YOFF-20);
XText(rp, buf, 7);
X
Xsprintf(buf, "%7d", peak);
XMove(rp, XOFF+TEXT2, YOFF-20);
XText(rp, buf, 7);
X
Xsprintf(buf, "%7d", reads);
XMove(rp, XOFF+TEXT1, YOFF-10);
XText(rp, buf, 7);
X
Xsprintf(buf, "%7d", writes);
XMove(rp, XOFF+TEXT2, YOFF-10);
XText(rp, buf, 7);
Xreturn(0);
X}
X
Xvoid update()
X{
Xshort rsize, wsize;
Xstruct RastPort *rp = Window->RPort;
X
Xif (dispvals())
X   {
X   refresh();
X   return;
X   }
X
XScrollRaster(rp, 1, 0, XOFF, YOFF, XOFF+xsize, YOFF+ysize);
X/* Now update the data for the one we just finished */
Xrsize = rstats[statpos]/yscale;
Xwsize = wstats[statpos]/yscale;
X/* Now display the line at the right place for the read and then the write */
XMove(rp, XOFF+MAXSTATS, YOFF+ysize);
Xif (rsize)
X   {
X   SetAPen(rp, 2);
X   Draw(rp, XOFF+MAXSTATS, YOFF+ysize-rsize);
X   }
Xif (wsize)
X   {
X   SetAPen(rp, 3);
X   Draw(rp, XOFF+MAXSTATS, YOFF+ysize-rsize-wsize);
X   }
X/* And put a point where the limit is */
XSetAPen(rp, 1);
XWritePixel(rp, XOFF+MAXSTATS, YOFF+ysize-(peak/yscale));
X}
X
Xvoid refresh()
X{
Xint i, j;
Xshort rsize, wsize;
Xstruct RastPort *rp = Window->RPort;
Xchar *p;
X
XSetAPen(rp, 0);
XRectFill(rp, XOFF, YOFF, XOFF+MAXSTATS+1, YOFF+ysize);
X
Xp = "Total:        Bps    Peak:        Bps";
XSetAPen(rp, 1);
XMove(rp, XOFF, YOFF-20);
XText(rp, p, strlen(p));
X
Xp = "Reads:        Bps  Writes:        Bps";
XMove(rp, XOFF, YOFF-10);
XText(rp, p, strlen(p));
X
XSetAPen(rp, 3);
Xp = " ) 1989 The Software Distillery";
XMove(rp, XOFF, YOFF+ysize+9);
XText(rp, p, strlen(p));
Xdispvals();
X
XSetAPen(rp, 1);
XSetDrMd(rp, JAM1);
XMove(rp, XOFF-1, YOFF);
XDraw(rp, XOFF-1, YOFF+1+ysize);
XDraw(rp, XOFF+1+xsize, YOFF+1+ysize);
X
Xi = statpos+1;
Xfor (j = 0; j < MAXSTATS; j++)
X   {
X   if (i >= MAXSTATS) i = 0;
X   rsize = rstats[i]/yscale;
X   wsize = wstats[i]/yscale;
X   /* Now display the line at the right place for the read and then the write */
X   Move(rp, XOFF+j, YOFF+ysize);
X   if (rsize)
X      {
X      SetAPen(rp, 2);
X      Draw(rp, XOFF+j, YOFF+ysize-rsize);
X      }
X   if (wsize)
X      {
X      SetAPen(rp, 3);
X      Draw(rp, XOFF+j, YOFF+ysize-rsize-wsize);
X      }
X   i++;
X   }
XSetAPen(rp, 1);
XMove(rp, XOFF, YOFF+ysize-(peak/yscale));
XDraw(rp, XOFF+MAXSTATS, YOFF+ysize-(peak/yscale));
X}
X
X/************************************************************************/
X/* Queue a timer to go off in a given number of seconds                 */
X/************************************************************************/
Xvoid QueueTimer(tr, seconds)
Xstruct timerequest *tr;
XULONG seconds;
X{
X   tr->tr_node.io_Command = TR_ADDREQUEST;   /* add a new timer request */
X   tr->tr_time.tv_secs =  seconds;        	/* seconds */
X   tr->tr_time.tv_micro = 0;
X   SendIO( (struct IORequest *)tr );
X}
X
X
Xstruct IOStdReq *CreateIOReq(port, size)
Xstruct MsgPort *port;
Xint size;
X{
X   register struct IOStdReq *ioReq;
X
X   if ((ioReq = (struct IOStdReq *)
X                AllocMem(size, MEMF_CLEAR | MEMF_PUBLIC)) != NULL)
X      {
X      ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
X      ioReq->io_Message.mn_Node.ln_Pri  = 0;
X      ioReq->io_Message.mn_Length       = size;
X      ioReq->io_Message.mn_ReplyPort    = port;
X      }
X   return(ioReq);
X}
X
Xvoid DeleteIOReq(ioReq)
Xregister struct IOStdReq *ioReq;
X{
X   ioReq->io_Message.mn_Node.ln_Type = 0xff;
X   ioReq->io_Device = (struct Device *) -1;
X   ioReq->io_Unit = (struct Unit *) -1;
X
X   FreeMem( (char *)ioReq, ioReq->io_Message.mn_Length);
X}
X
XLONG sendpkt(pid,action,args,nargs)
Xstruct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
XLONG action,          /* packet type ... (what you want handler to do )   */
X     args[],          /* a pointer to a argument list */
X     nargs;           /* number of arguments in list  */
X   {
X   struct MsgPort        *replyport;
X   struct StandardPacket *packet;
X 
X   LONG  count, *pargs, res1;
X
X   replyport = (struct MsgPort *) CreatePort(NULL,0);
X   if(!replyport) return(NULL);
X
X   packet = (struct StandardPacket *) 
X      AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
X   if(!packet) 
X      {
X      DeletePort(replyport);
X      return(NULL);
X      }
X
X   packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
X   packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
X   packet->sp_Pkt.dp_Port         = replyport;
X   packet->sp_Pkt.dp_Type         = action;
X
X   /* copy the args into the packet */
X   pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
X   for(count=0;count < nargs;count++) 
X      pargs[count]=args[count];
X 
X   PutMsg(pid,(struct Message *)packet); /* send packet */
X
X   WaitPort(replyport);
X   GetMsg(replyport); 
X
X   res1 = packet->sp_Pkt.dp_Res1;
X
X   FreeMem((char *)packet,(long)sizeof(struct StandardPacket));
X   DeletePort(replyport); 
X
X   return(res1);
X}
X
Xvoid MemCleanup(){}
SHAR_EOF
echo "extracting util/netstat.h"
sed 's/^X//' << \SHAR_EOF > util/netstat.h
Xstruct statmsg
X   {
X   struct Message msg;
X   long   count;
X   int    direction;
X   };SHAR_EOF
echo "extracting util/shutdown.c"
sed 's/^X//' << \SHAR_EOF > util/shutdown.c
X#include <exec/types.h>
X#include <exec/memory.h>
X#include <exec/nodes.h>
X#include <exec/lists.h>
X#include <exec/ports.h>
X#include <libraries/dos.h>
X#include <libraries/dosextens.h>
X#include <libraries/filehandler.h>
X#include <string.h>
X#include <stdlib.h>
X#include <proto/exec.h>
X#include <proto/dos.h>
X
X#undef GLOBAL
X/* my version of BADDR() has no problems with casting */
X#undef  BADDR
X#define BADDR(x)        ((APTR)((long)x << 2))
X#define MKBADDR(x)      ((BPTR)((long)x >> 2))
X
Xlong sendpkt(struct MsgPort *, long, long*, long);
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
Xstruct MsgPort *proc;
Xlong myargs[8];
X
Xif (argc != 2)
X   {
X   printf("Usage: %s <device>\n", argv[0]);
X   return;
X   }
X
Xmyargs[0]=1;
X
Xif ((proc = (struct MsgPort *)DeviceProc(argv[1])) == NULL)
X   {
X   printf("Unable to get a device proc for %s\n", argv[1]);
X   return;
X   }
X
Xsendpkt(proc,ACTION_DIE,myargs,1);
X}
X
XLONG sendpkt(pid,action,args,nargs)
Xstruct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
XLONG action,          /* packet type ... (what you want handler to do )   */
X     args[],          /* a pointer to a argument list */
X     nargs;           /* number of arguments in list  */
X   {
X   struct MsgPort        *replyport;
X   struct StandardPacket *packet;
X 
X   LONG  count, *pargs, res1;
X
X   replyport = (struct MsgPort *) CreatePort(NULL,0);
X   if(!replyport) return(NULL);
X
X   packet = (struct StandardPacket *) 
X      AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
X   if(!packet) 
X      {
X      DeletePort(replyport);
X      return(NULL);
X      }
X
X   packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
X   packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
X   packet->sp_Pkt.dp_Port         = replyport;
X   packet->sp_Pkt.dp_Type         = action;
X
X   /* copy the args into the packet */
X   pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
X   for(count=0;count < nargs;count++) 
X      pargs[count]=args[count];
X 
X   PutMsg(pid,(struct Message *)packet); /* send packet */
X
X   WaitPort(replyport);
X   GetMsg(replyport); 
X
X   res1 = packet->sp_Pkt.dp_Res1;
X
X   FreeMem((char *)packet,(long)sizeof(struct StandardPacket));
X   DeletePort(replyport); 
X
X   return(res1);
X}
SHAR_EOF
echo "End of archive 4 (of 4)"
# if you want to concatenate archives, remove anything after this line
exit