/* * NFS-HANDLER.C V1.11 27-June-89 * * DNet DOS level NFS handler. * * By Matthew Dillon. * * This handler converts DOS packets into a form suitable for transmission * over a DNet link to a remote server which will execute the operations. */ #include "dos.h" #include /* * Since this code might be called several times in a row without being * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!! This also goes * for any global/static assignments that might be changed by running the * code. */ PROC *DosProc; /* Our Process */ DEVNODE *DosNode; /* Our DOS node.. created by DOS for us */ DEVLIST *DevList; /* Device List structure for our volume node */ void *SysBase; /* EXEC library base */ /* void *DResBase; */ DOSLIB *DOSBase; /* DOS library base for debug process */ MLIST FHBase; /* Open Files */ MLIST LCBase; /* Open Locks */ long TotalBytes; /* total bytes of data in filesystem */ void *CHan; /* DNet channel */ HANDLE RFRoot; char TmpBuf[256]; #ifdef DEBUG short DBDisable = 0; /* Debug code */ #endif HANDLE *AllocHandle(); /* * Don't call the entry point main(). This way, if you make a mistake * with the compile options you'll get a link error. */ void __saveds noname ARGS((void)); void returnpacket ARGS((PACKET *)); int packetsqueued ARGS((void)); HANDLE *GetHandleForLock ARGS((LOCK *)); void *GetLockForHandle ARGS((HANDLE *)); HANDLE *AllocHandle ARGS((char *, RtOpen *)); void FreeHandle ARGS((HANDLE *)); void *dosalloc ARGS((ulong)); void dosfree ARGS((ulong *)); char *bstos ARGS((ubyte *)); char *skipdevice ARGS((char *)); int DoNetworkOp ARGS((char, void *, int, void *, int, void *, int)); void __saveds noname() { reg PACKET *packet; reg short error; MSG *msg; ubyte notdone; void *tmp; #ifndef LATTICE mygeta4(); #endif /* * Initialize all global variables. SysBase MUST be initialized before * we can make Exec calls. */ TotalBytes = 0; SysBase = *(void **)4; DOSBase = (void *)OpenLibrary("dos.library",0); /* DResBase= OpenLibrary("dres.library",0); */ DosProc = (PROC *)FindTask(NULL); CHan = 0; { WaitPort(&DosProc->pr_MsgPort); /* Get Startup Packet */ msg = GetMsg(&DosProc->pr_MsgPort); packet = (PACKET *)msg->mn_Node.ln_Name; /* * Loading DosNode->dn_Task causes DOS *NOT* to startup a new * instance of the device driver for every reference. E.G. if * you were writing a CON device you would want this field to * be NULL. */ if (DOSBase /*&& DResBase*/) { DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info); register DEVLIST *dl = dosalloc(sizeof(DEVLIST)); DosNode = BTOC(packet->dp_Arg3); DosNode->dn_Task = &DosProc->pr_MsgPort; /* * Create Volume node and add to the device list. This will * cause the WORKBENCH to recognize us as a disk. If we don't * create a Volume node, Wb will not recognize us. However, * we are a RAM: disk, Volume node or not. */ DevList = dl; dl->dl_Type = DLT_VOLUME; dl->dl_Task = &DosProc->pr_MsgPort; dl->dl_DiskType = ID_DOS_DISK; dl->dl_Name = (BSTR)DosNode->dn_Name; dl->dl_Next = di->di_DevInfo; di->di_DevInfo = (long)CTOB(dl); packet->dp_Res1 = DOS_TRUE; packet->dp_Res2 = 0; } else { /* couldn't open dos.library */ packet->dp_Res1 = DOS_FALSE; returnpacket(packet); return; /* exit process */ } returnpacket(packet); } /* Initialize RAM disk */ #ifdef DEBUG dbinit(); #endif { NewList((LIST *)&FHBase); /* more globals */ NewList((LIST *)&LCBase); BZero(&RFRoot, sizeof(RFRoot)); DateStamp((long *)&RFRoot.Date); RFRoot.Type = FILE_DIR; RFRoot.Name = "Root"; } /* * Here begins the endless loop, waiting for requests over our * message port and executing them. Since requests are sent over * our message port, this precludes being able to call DOS functions * ourselves (that is why the debugging routines are a separate process) */ top: for (notdone = 1; notdone;) { WaitPort(&DosProc->pr_MsgPort); while (msg = GetMsg(&DosProc->pr_MsgPort)) { packet = (PACKET *)msg->mn_Node.ln_Name; packet->dp_Res1 = DOS_TRUE; packet->dp_Res2 = 0; error = 0; if (!CHan) { /* attempt to open server channel */ CHan = DOpen(NULL, PORT_NFS, -80, -80); if (!CHan) { /* otherwise giveup! */ notdone = 0; goto fail; } } #ifdef DEBUG dbprintf("ACTION %ld\n", packet->dp_Type); #endif switch(packet->dp_Type) { case ACTION_DIE: /* attempt to die? */ notdone = 0; /* try to die */ break; case ACTION_OPENRW: /* FileHandle,Lock,Name Bool */ case ACTION_OPENOLD: /* FileHandle,Lock,Name Bool */ case ACTION_OPENNEW: /* FileHandle,Lock,Name Bool */ { OpOpen opkt; RtOpen rpkt; short r; char *name = skipdevice(bstos((ubyte *)packet->dp_Arg3)); HANDLE *handle; opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg2)->Handle; opkt.Modes = packet->dp_Type; r = DoNetworkOp('O',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt)); if (r) { error = ERROR_OBJECT_IN_USE; } else if (rpkt.Handle == -1) { error = ERROR_OBJECT_NOT_FOUND; } else if (rpkt.Type > 0) { /* can't open dir */ OpClose opkt; opkt.Handle = rpkt.Handle; DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0); error = ERROR_OBJECT_WRONG_TYPE; } else { if (name[0] == 0) name = GetHandleForLock((LOCK *)packet->dp_Arg2)->Name; handle = AllocHandle(name, &rpkt); ((FH *)BTOC(packet->dp_Arg1))->fh_Arg1 = (long)handle; } } break; case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */ { HANDLE *handle = (HANDLE *)packet->dp_Arg1; OpRead opkt; RtRead rpkt; short err; opkt.Handle = handle->Handle; opkt.Bytes = packet->dp_Arg3; err = DoNetworkOp('R',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt)); if (err) rpkt.Bytes = -1; if (rpkt.Bytes > 0 && rpkt.Bytes <= opkt.Bytes) DRead(CHan, (void *)packet->dp_Arg2, rpkt.Bytes); packet->dp_Res1 = rpkt.Bytes; } break; case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */ { HANDLE *handle = (HANDLE *)packet->dp_Arg1; OpWrite opkt; RtWrite rpkt; short err; opkt.Handle = handle->Handle; opkt.Bytes = packet->dp_Arg3; err = DoNetworkOp('W',&opkt,sizeof(opkt),(void *)packet->dp_Arg2,packet->dp_Arg3,&rpkt,sizeof(rpkt)); if (err) rpkt.Bytes = -1; packet->dp_Res1 = rpkt.Bytes; } break; case ACTION_CLOSE: /* FHArg1 Bool:TRUE */ { HANDLE *handle = (HANDLE *)packet->dp_Arg1; OpClose opkt; if (packet->dp_Arg1 == NULL || handle->Magic != MAGIC) { Alert(AT_Recovery|0, (char *)0x12345555); } else { opkt.Handle = handle->Handle; DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0); FreeHandle(handle); } } if (!GetHead(&FHBase)) notdone = 0; break; case ACTION_SEEK: /* FHArg1,Position,Mode OldPosition*/ { HANDLE *handle = (HANDLE *)packet->dp_Arg1; OpSeek opkt; RtSeek rpkt; short err; opkt.Handle = handle->Handle; opkt.Offset = packet->dp_Arg2; opkt.How = packet->dp_Arg3 + 1; err = DoNetworkOp('S',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt)); if (err) rpkt.NewOffset = -1; if (rpkt.NewOffset < 0) error = ERROR_SEEK_ERROR; else packet->dp_Res1 = rpkt.OldOffset; } break; case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */ { HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1); register FIB *fib = BTOC(packet->dp_Arg2); OpNextDir opkt; RtNextDir rpkt; short err; #ifdef DEBUG dbprintf("FIB = %08lx\n", fib); #endif if (handle->Type < 0) { error = ERROR_OBJECT_WRONG_TYPE; break; } opkt.Handle = handle->Handle; opkt.Index = fib->fib_DiskKey; err = DoNetworkOp('N',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt)); if (err || rpkt.Handle == -1) { error = ERROR_NO_MORE_ENTRIES; } else { /* not a real file handle, just info & name */ unsigned char fn; if (DRead(CHan, &fn, 1) != 1) TmpBuf[fn = 0] = 0; if (DRead(CHan, TmpBuf, fn) != fn) TmpBuf[fn = 0] = 0; ++fib->fib_DiskKey; /* next key */ fib->fib_DirEntryType = rpkt.Type; fib->fib_Protection = rpkt.Prot; fib->fib_EntryType = NULL; fib->fib_Size = rpkt.Size; fib->fib_NumBlocks = rpkt.Size >> 9; if (strlen(TmpBuf) >= sizeof(fib->fib_FileName) - 2) { fib->fib_FileName[0] = 1; fib->fib_FileName[1] = '?'; fib->fib_FileName[2] = 0; } else { strcpy(fib->fib_FileName+1, TmpBuf); fib->fib_FileName[0] = strlen(TmpBuf); } fib->fib_Comment[0] = 0; fib->fib_Comment[1] = 0; fib->fib_Date = rpkt.Date; } } break; case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */ { HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1); register FIB *fib = BTOC(packet->dp_Arg2); #ifdef DEBUG dbprintf("FIB = %08lx\n", fib); #endif fib->fib_DiskKey = 0; fib->fib_DirEntryType = handle->Type; /* * fib->fib_FileName bcpl type string */ fib->fib_Protection = handle->Prot; fib->fib_EntryType = NULL; fib->fib_Size = handle->Size; fib->fib_NumBlocks = handle->Size >> 9; if (strlen(handle->Name) >= sizeof(fib->fib_FileName) - 2) { fib->fib_FileName[0] = 1; fib->fib_FileName[1] = '?'; fib->fib_FileName[2] = 0; } else { strcpy(fib->fib_FileName+1, handle->Name); fib->fib_FileName[0] = strlen(handle->Name); } fib->fib_Comment[0] = 0; fib->fib_Comment[1] = 0; fib->fib_Date = handle->Date; } break; case ACTION_INFO: /* Lock, InfoData Bool:TRUE */ tmp = BTOC(packet->dp_Arg2); error = -1; /* fall through */ case ACTION_DISK_INFO: /* InfoData Bool:TRUE */ { register INFODATA *id; /* * Note: id_NumBlocks is never 0, but only to get * around a bug I found in my shell (where I divide * by id_NumBlocks). Other programs probably break * as well. */ (error) ? (id = tmp) : (id = BTOC(packet->dp_Arg1)); error = 0; BZero(id, sizeof(*id)); id->id_DiskState = ID_VALIDATED; id->id_NumBlocks = (TotalBytes >> 9) + 1; id->id_NumBlocksUsed = (TotalBytes >> 9) + 1; id->id_BytesPerBlock = 512; id->id_DiskType = ID_DOS_DISK; id->id_VolumeNode = (long)CTOB(DosNode); id->id_InUse = (long)GetHead(&LCBase); } break; case ACTION_PARENT: /* Lock ParentLock */ { HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1); OpParent opkt; RtParent rpkt; short err; opkt.Handle = handle->Handle; err = DoNetworkOp('P',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt)); if (err) rpkt.Handle = NULL; if (rpkt.Handle == -1) { error = ERROR_OBJECT_NOT_FOUND; } else { /* create a file handle and return a lock */ HANDLE *newhandle; unsigned char fn; if (DRead(CHan, &fn, 1) != 1) TmpBuf[fn = 0] = 0; if (DRead(CHan, TmpBuf, fn) != fn) TmpBuf[fn = 0] = 0; newhandle = AllocHandle(TmpBuf, &rpkt); packet->dp_Res1 = (long)GetLockForHandle(newhandle); } } break; case ACTION_DELETE_OBJECT: /*Lock,Name Bool */ { OpDelete opkt; RtDelete rpkt; short err; char *name = skipdevice(bstos((ubyte *)packet->dp_Arg2)); opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle; err = DoNetworkOp('D',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt)); if (err || rpkt.Error) error = ERROR_OBJECT_NOT_FOUND; } break; case ACTION_CREATE_DIR: /* Lock,Name Lock */ { OpCreateDir opkt; RtCreateDir rpkt; short err; char *name = skipdevice(bstos((ubyte *)packet->dp_Arg2)); opkt.DirHandle = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle; err = DoNetworkOp('M',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt)); if (err) rpkt.Handle = NULL; if (rpkt.Handle == -1) { error = ERROR_OBJECT_EXISTS; } else { /* create a file handle and return a lock */ HANDLE *newhandle = AllocHandle(name, &rpkt); packet->dp_Res1 = (long)GetLockForHandle(newhandle); } } break; case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */ { OpOpen opkt; RtOpen rpkt; short err; char *name = skipdevice(bstos((ubyte *)packet->dp_Arg2)); HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1); opkt.DirHandle = handle->Handle; opkt.Modes = 1005; err = DoNetworkOp('O',&opkt,sizeof(opkt),name,strlen(name)+1,&rpkt,sizeof(rpkt)); if (err) { error = ERROR_OBJECT_IN_USE; } else if (rpkt.Handle == -1) { error = ERROR_OBJECT_NOT_FOUND; } else { HANDLE *newhandle; if (name[0] == 0) name = handle->Name; newhandle = AllocHandle(name, &rpkt); packet->dp_Res1 = (long)GetLockForHandle(newhandle); } } break; case ACTION_COPY_DIR: /* Lock, Lock */ { OpDup opkt; RtDup rpkt; short err; HANDLE *oldhandle = GetHandleForLock((LOCK *)packet->dp_Arg1); opkt.Handle = oldhandle->Handle; err = DoNetworkOp('d',&opkt,sizeof(opkt),NULL,0,&rpkt,sizeof(rpkt)); if (err) { error = ERROR_OBJECT_IN_USE; } else if (rpkt.Handle == -1) { error = ERROR_OBJECT_NOT_FOUND; } else { HANDLE *handle = AllocHandle(oldhandle->Name, &rpkt); packet->dp_Res1 = (long)GetLockForHandle(handle); } } break; case ACTION_FREE_LOCK: /* Lock, Bool */ { HANDLE *handle = GetHandleForLock((LOCK *)packet->dp_Arg1); OpClose opkt; opkt.Handle = handle->Handle; DoNetworkOp('C',&opkt,sizeof(opkt),NULL,0,NULL,0); FreeHandle(handle); } break; case ACTION_SET_PROTECT:/* -,Lock,Name,Mask Bool */ error = ERROR_ACTION_NOT_KNOWN; break; case ACTION_SET_COMMENT:/* -,Lock,Name,Comment Bool */ error = ERROR_ACTION_NOT_KNOWN; break; case ACTION_RENAME_OBJECT:/* SLock,SName,DLock,DName Bool */ { OpRename opkt; RtRename rpkt; short err; char *name1= skipdevice(bstos((ubyte *)packet->dp_Arg2)); char *name2= skipdevice(bstos((ubyte *)packet->dp_Arg4)); short len1 = strlen(name1); short len2 = strlen(name2); char *name = AllocMem(len1+len2+2, MEMF_PUBLIC); opkt.DirHandle1 = GetHandleForLock((LOCK *)packet->dp_Arg1)->Handle; opkt.DirHandle2 = GetHandleForLock((LOCK *)packet->dp_Arg3)->Handle; strcpy(name, name1); strcpy(name+len1+1,name2); err = DoNetworkOp('r',&opkt,sizeof(opkt),name,len1+len2+2,&rpkt,sizeof(rpkt)); FreeMem(name, len1+len2+2); if (err) { error = ERROR_OBJECT_IN_USE; } else if (rpkt.Error) { error = ERROR_OBJECT_NOT_FOUND; } } break; /* * A few other packet types which we do not support */ case ACTION_INHIBIT: /* Bool Bool */ /* Return success for the hell of it */ break; case ACTION_RENAME_DISK:/* BSTR:NewName Bool */ case ACTION_MORECACHE: /* #BufsToAdd Bool */ case ACTION_WAIT_CHAR: /* Timeout, ticks Bool */ case ACTION_FLUSH: /* writeout bufs, disk motor off */ case ACTION_RAWMODE: /* Bool(-1:RAW 0:CON) OldState */ default: fail: error = ERROR_ACTION_NOT_KNOWN; break; } if (packet) { if (error) { packet->dp_Res1 = DOS_FALSE; packet->dp_Res2 = error; } returnpacket(packet); } } } Delay(50); /* I wanna even see the debug message! */ Forbid(); if (packetsqueued() || GetHead(&FHBase)) { Permit(); goto top; /* sorry... can't exit */ } /* * Causes a new process to be created on next reference */ DosNode->dn_Task = FALSE; /* * Remove Volume entry. Since DOS uses singly linked lists, we * must (ugg) search it manually to find the link before our * Volume entry. */ { DOSINFO *di = BTOC(((ROOTNODE *)DOSBase->dl_Root)->rn_Info); register DEVLIST *dl; register void *dlp; dlp = &di->di_DevInfo; for (dl = BTOC(di->di_DevInfo); dl && dl != DevList; dl = BTOC(dl->dl_Next)) dlp = &dl->dl_Next; if (dl == DevList) { *(BPTR *)dlp = dl->dl_Next; dosfree((ulong *)dl); } else { ; } } /* * closedown, fall of the end of the world * * (which is how you kill yourself if a PROCESS. A TASK would have * had to RemTask(NULL) itself). */ if (CHan) DClose(CHan); CHan = 0; #ifdef DEBUG dbuninit(); #endif CloseLibrary((LIB *)DOSBase); /* CloseLibrary(DResBase); */ } /* * PACKET ROUTINES. Dos Packets are in a rather strange format as you * can see by this and how the PACKET structure is extracted in the * GetMsg() of the main routine. */ void returnpacket(packet) PACKET *packet; { register struct Message *mess; register struct MsgPort *replyport; replyport = packet->dp_Port; mess = packet->dp_Link; packet->dp_Port = &DosProc->pr_MsgPort; mess->mn_Node.ln_Name = (char *)packet; mess->mn_Node.ln_Succ = NULL; mess->mn_Node.ln_Pred = NULL; PutMsg(replyport, mess); } /* * Are there any packets queued to our device? */ int packetsqueued() { return ((void *)DosProc->pr_MsgPort.mp_MsgList.lh_Head != (void *)&DosProc->pr_MsgPort.mp_MsgList.lh_Tail); } /* * Handle structure, locks, and manipulation. */ HANDLE * GetHandleForLock(block) LOCK *block; { register LOCK *lock = BTOC(block); register HANDLE *handle; #ifdef DEBUG dbprintf("GetHandleForLock: %08lx ", lock); #endif if (lock) { handle = (HANDLE *)lock->fl_Key; #ifdef DEBUG dbprintf("Handle=%08lx (h=$%08lx)\n", handle, handle->Handle); #endif if (handle->Magic == MAGIC) return(handle); Alert(AT_Recovery|1, (char *)handle); } #ifdef DEBUG dbprintf("\n"); #endif /*Alert(AT_Recovery|2, (char *)-2);*/ return(&RFRoot); } void * GetLockForHandle(handle) HANDLE *handle; { register LOCK *lock = handle->Lock; register LOCKLINK *ln; #ifdef DEBUG dbprintf("GetLockForHandle: %08lx ", handle); #endif if (!lock) { lock = dosalloc(sizeof(LOCK)); #ifdef DEBUG dbprintf("(allocate) %08lx\n", lock); #endif ln = AllocMem(sizeof(LOCKLINK), MEMF_PUBLIC|MEMF_CLEAR); AddHead((LIST *)&LCBase,(NODE *)ln); ln->Lock = lock; lock->fl_Link = (long)ln; lock->fl_Key = (long)handle; lock->fl_Access = ACCESS_READ; lock->fl_Task= &DosProc->pr_MsgPort; lock->fl_Volume = (BPTR)CTOB(DosNode); handle->Lock = lock; } #ifdef DEBUG dbprintf("Lock=%08lx\n", lock); #endif return((void *)CTOB(lock)); } HANDLE * AllocHandle(name, rpkt) char *name; RtOpen *rpkt; { HANDLE *handle; register char *ptr; for (ptr = name + strlen(name) - 1; ptr >= name && *ptr != '/'; --ptr); ++ptr; handle = AllocMem(sizeof(HANDLE), MEMF_PUBLIC|MEMF_CLEAR); handle->Magic = MAGIC; handle->Handle= rpkt->Handle; handle->Type = rpkt->Type; handle->Prot = rpkt->Prot; handle->Size = rpkt->Size; handle->Name = AllocMem(strlen(ptr)+1, MEMF_PUBLIC); handle->Date = rpkt->Date; strcpy(handle->Name, ptr); AddHead((LIST *)&FHBase, (NODE *)handle); #ifdef DEBUG dbprintf("AllocHandle: %08lx '%s' h=$%08lx\n", handle, ptr, handle->Handle); #endif return(handle); } void FreeHandle(handle) HANDLE *handle; { #ifdef DEBUG dbprintf("FreeHandle: %08lx %08lx\n", handle, handle->Lock); #endif if (handle->Lock) { register LOCK *lock = handle->Lock; Remove((NODE *)lock->fl_Link); FreeMem((void *)lock->fl_Link, sizeof(LOCKLINK)); dosfree((ulong *)lock); } Remove((NODE *)handle); handle->Magic = 0; FreeMem(handle->Name, strlen(handle->Name)+1); FreeMem(handle, sizeof(HANDLE)); } /* * DOS MEMORY ROUTINES * * DOS makes certain assumptions about LOCKS. A lock must minimally be * a FileLock structure, with additional private information after the * FileLock structure. The longword before the beginning of the structure * must contain the length of structure + 4. * * NOTE!!!!! The workbench does not follow the rules and assumes it can * copy lock structures. This means that if you want to be workbench * compatible, your lock structures must be EXACTLY sizeof(struct FileLock). */ void * dosalloc(bytes) reg ulong bytes; { reg ulong *ptr; bytes += 4; ptr = AllocMem(bytes, MEMF_PUBLIC|MEMF_CLEAR); *ptr = bytes; return(ptr+1); } void dosfree(ptr) register ulong *ptr; { --ptr; FreeMem(ptr, *ptr); } /* * Convert a BSTR into a normal string.. copying the string into buf. * I use normal strings for internal storage, and convert back and forth * when required. */ char * bstos(bstr) ubyte *bstr; { static char buf[512]; static char *ptr = buf; if (ptr == buf) /* switch which buffer to use */ ptr = buf + 256; else ptr = buf; bstr = BTOC(bstr); BMov(bstr+1,ptr,*bstr); ptr[*bstr] = 0; return(ptr); } char * skipdevice(str) register char *str; { char *base = str; while (*str && *str != ':') ++str; if (*str == 0) str = base; else ++str; return(str); } /* * data = DoNetworkOp(&cmd, &len, data) */ int DoNetworkOp(cmd, s, _slen, d, dlen, r, rlen) char cmd; int _slen; void *s; void *d; void *r; { ubyte slen = _slen; if (CHan) { if (DWrite(CHan, &cmd, 1) < 0) goto fail; if (DWrite(CHan, &slen, 1) < 0) goto fail; if (DWrite(CHan, &dlen, 4) < 0) goto fail; if (DWrite(CHan, s, slen) < 0) goto fail; if (dlen) { if (DWrite(CHan, d, dlen) < 0) goto fail; } if (r) { if (DRead(CHan, r, rlen) != rlen) goto fail; } return(0); } fail: if (CHan) { DClose(CHan); CHan = 0; } return(1); } #ifndef LATTICE #asm _mygeta4: far data lea __H1_org+32766,a4 rts public __H0_org dseg public __H1_org cseg #endasm #endif #ifdef DEBUG /* note, doesn't work w/ Lattice */ /* * DEBUG CODE */ /* DEBUGGING */ PORT *Dbport; /* owned by the debug process */ PORT *Dback; /* owned by the DOS device driver */ MSG DummyMsg; /* Dummy message that debug proc can use */ /* * DEBUGGING CODE. You cannot make DOS library calls that access other * devices from within a DOS device driver because they use the same * message port as the driver. If you need to make such calls you must * create a port and construct the DOS messages yourself. I do not * do this. To get debugging info out another PROCESS is created to which * debugging messages can be sent. * * You want the priority of the debug process to be larger than the * priority of your DOS handler. This is so if your DOS handler crashes * you have a better idea of where it died from the debugging messages * (remember that the two processes are asyncronous from each other). */ extern void debugproc(); dbinit() { TASK *task = FindTask(NULL); Dback = CreatePort(NULL,NULL); CreateProc("DEV_DB", task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096); WaitPort(Dback); /* handshake startup */ GetMsg(Dback); /* remove dummy msg */ dbprintf("Debugger running V1.10, 2 November 1987\n"); dbprintf("Works with WORKBENCH!\n"); } dbuninit() { MSG killmsg; if (Dbport) { killmsg.mn_Length = 0; /* 0 means die */ PutMsg(Dbport,&killmsg); WaitPort(Dback); /* He's dead jim! */ GetMsg(Dback); DeletePort(Dback); /* * Since the debug process is running at a greater priority, I * am pretty sure that it is guarenteed to be completely removed * before this task gets control again. Still, it doesn't hurt... */ Delay(50); /* ensure he's dead */ } } dbprintf(a,b,c,d,e,f,g,h,i,j) { char buf[256]; MSG *msg; if (Dbport && !DBDisable) { sprintf(buf,a,b,c,d,e,f,g,h,i,j); msg = AllocMem(sizeof(MSG)+strlen(buf)+1, MEMF_PUBLIC|MEMF_CLEAR); msg->mn_Length = strlen(buf)+1; /* Length NEVER 0 */ strcpy(msg+1,buf); PutMsg(Dbport,msg); } } /* * BTW, the DOS library used by debugmain() was actually openned by * the device driver. Note: DummyMsg cannot be on debugmain()'s stack * since debugmain() goes away on the final handshake. */ void debugmain() { MSG *msg; short len; void *fh; mygeta4(); Dbport = CreatePort(NULL,NULL); fh = Open("con:0/0/640/100/debugwindow", 1006); PutMsg(Dback, &DummyMsg); for (;;) { WaitPort(Dbport); msg = GetMsg(Dbport); len = msg->mn_Length; if (len == 0) break; --len; /* Fix length up */ Write(fh, msg+1, len); FreeMem(msg,sizeof(MSG)+len+1); } Close(fh); DeletePort(Dbport); PutMsg(Dback,&DummyMsg); /* Kill handshake */ } /* * The assembly tag for the DOS process: CNOP causes alignment problems * with the Aztec assembler for some reason. I assume then, that the * alignment is unknown. Since the BCPL conversion basically zero's the * lower two bits of the address the actual code may start anywhere around * the label.... Sigh.... (see CreatProc() above). */ #asm public _debugproc public _debugmain cseg nop nop nop _debugproc: nop nop movem.l D2-D7/A2-A6,-(sp) jsr _debugmain movem.l (sp)+,D2-D7/A2-A6 rts #endasm #endif