paul@lfcs.ed.ac.uk (Paul Anderson) (03/22/89)
Quite a lot of people seem to be interested in my patches to AUFS, so I have decided to post them. Here they are - this is a single patch file which patches some of the source files for AUFS and adds a couple of new ones ... ---------------------------------------------------------------------------- *** README.PROCESSES Tue Mar 21 18:58:38 1989 --- ../aufsp/README.PROCESSES Tue Mar 21 20:42:05 1989 *************** *** 0 **** --- 1,52 ---- + + AUFS and running UNIX processes from the Mac + ============================================ + + This file contains a set of patches for the AUFS distributed with CAP 5.0. + These patches allow a Macintosh application to fork one or more Unix processes + on the AUFS server and comminicate with the running processes via a pipe. + To start a process, the Macintosh simply opens a file whose name + starts with a "!". Instead of opening the file, the server attempts to run + the named file as a process. The Macintosh can communicate with the process + simply by reading and writing to the file handle returned by the open command. + Closing the file kills the process. Opening commands with different names + allows more than one process to be active simultaneously. This arrangement + requires no extra software on the Macintosh and is very easy to use from + programs like Hypercard. + + The program has been tested on Sun 3s and 4s, running under SunOS 3.2 and 4.0. + Some changes may be needed for other UNIX versions. It was written as an + experiment rather than a serious tool and it probably has lots of other + problems as well as those listed below - I am not likely to be doing any more + work on it myself, but I would be glad to hear of any improvements and + suggestions. + + Some random thoughts ..... + + The filename has to be supplied as a full Mac volume pathname, including a + full unix pathname :- Eg: sun:!/bin/ls + Where sun is the AUFS volume name. + + The processes run with the same uid as the server. This is an obvious security + problem! Even if the server does not run as root, anybody can log onto it + and run a process with the uid of the server owner. I guess this could be + fixed quite easily. + + It is quite easy to get the server into a deadlocked state - this happens eg. + if the UNIX process and the Mac program both issue reads on the pipe at the + same time. In our Hypercard applications, we isolated the communication with + the UNIX processes into a synchronous routine in Hypertalk - I think it would + be quite hard to prevent this problem in the server itself. Deadlocks like this + can be broken by issuing a ^C to the server. + + Because of this, we don't run the processes in our main AUFS server, but + start a separate server specially for the application. This is why the + supplied version has Process debugging turned on by default and invents itself + a new name based on the user (See aufs.c if you want to change this). + I would be interested in any better solutions to the problem. + + + Paul Anderson JANET: paul@uk.ac.ed.lfcs + LFCS, Dept. of Computer Science UUCP: ..!mcvax!ukc!lfcs!paul + University of Edinburgh ARPA: paul%lfcs.ed.ac.uk@nss.cs.ucl.ac.uk + Edinburgh EH9 3JZ, UK. Tel: 031-667-1081 Ext 2788 *** Makefile Tue Mar 21 17:48:11 1989 --- ../aufsp/Makefile Thu Mar 16 10:57:42 1989 *************** *** 49,60 **** # # End of configurable options # ! SRCS=afpos.c afpvols.c afpfile.c afpdir.c afpfork.c \ afpmisc.c afpserver.c aufsicon.c abmisc2.c \ afpdt.c afpdid.c afposenum.c afpavl.c \ afposfi.c afpgc.c afppasswd.c afposlock.c aufsv.c \ afpudb.c afposncs.c ! OBJS=afpos.o afpvols.o afpfile.o \ afpmisc.o afpserver.o aufsicon.o abmisc2.o \ afpdt.o afpdir.o afpfork.o afpdid.o afposenum.o afpavl.o \ afposfi.o afpgc.o afppasswd.o aufsv.o \ --- 49,60 ---- # # End of configurable options # ! SRCS=afpos.c afproc.c afpvols.c afpfile.c afpdir.c afpfork.c \ afpmisc.c afpserver.c aufsicon.c abmisc2.c \ afpdt.c afpdid.c afposenum.c afpavl.c \ afposfi.c afpgc.c afppasswd.c afposlock.c aufsv.c \ afpudb.c afposncs.c ! OBJS=afpos.o afproc.o afpvols.o afpfile.o \ afpmisc.o afpserver.o aufsicon.o abmisc2.o \ afpdt.o afpdir.o afpfork.o afpdid.o afposenum.o afpavl.o \ afposfi.o afpgc.o afppasswd.o aufsv.o \ *************** *** 94,99 **** --- 94,102 ---- afpos.o: afpos.c ${CC} ${OSDEFS} ${CFLAGS} -c afpos.c + afproc.o: afproc.c + ${CC} ${OSDEFS} ${CFLAGS} -c afproc.c + afposncs.o: afposncs.c ${CC} ${OSDEFS} ${CFLAGS} -c afposncs.c *************** *** 105,110 **** --- 108,117 ---- # Dependencies afpos.o: afpos.c $I/netat/appletalk.h \ + $I/netat/aberrors.h $I/netat/abqueue.h \ + $I/netat/afp.h \ + afpvols.h $I/netat/afpcmd.h + afproc.o: afproc.c $I/netat/appletalk.h \ $I/netat/aberrors.h $I/netat/abqueue.h \ $I/netat/afp.h \ afpvols.h $I/netat/afpcmd.h *** afpmisc.c Tue Mar 21 17:03:25 1989 --- ../aufsp/afpmisc.c Thu Mar 16 10:57:36 1989 *************** *** 49,58 **** {DBG_DEBG|DBG_SRVR,"Server"}, {DBG_DEBG|DBG_UNIX,"Unix"}, {DBG_DEBG|DBG_VOLS,"Volume"}, {DBG_DEBG,"debug"} }; ! #define DBTABN 11 /* size of debug table */ char *DBLevelOpts() { --- 49,59 ---- {DBG_DEBG|DBG_SRVR,"Server"}, {DBG_DEBG|DBG_UNIX,"Unix"}, {DBG_DEBG|DBG_VOLS,"Volume"}, + {DBG_DEBG|DBG_PROC,"Process"}, {DBG_DEBG,"debug"} }; ! #define DBTABN 12 /* size of debug table */ char *DBLevelOpts() { *** afps.h Tue Mar 21 17:48:25 1989 --- ../aufsp/afps.h Thu Mar 16 10:57:38 1989 *************** *** 62,67 **** --- 62,68 ---- #define DBG_DEBG 00200 /* in debug */ #define DBG_UNIX 00400 /* debug unix routines */ #define DBG_ENUM 01000 /* debug directory enumerations */ + #define DBG_PROC 02000 /* debug processes */ #define DBG_ALL (DBG_FILE|DBG_FORK|DBG_SRVR|DBG_VOLS| \ DBG_OSIN|DBG_DIRS|DBG_DESK|DBG_DEBG| \ *************** *** 78,83 **** --- 79,85 ---- #define DBDEB (afp_dbug & DBG_DEBG) #define DBUNX (afp_dbug & DBG_UNIX) #define DBENU (afp_dbug & DBG_ENUM) + #define DBPRO (afp_dbug & DBG_PROC) /* afpdid.c */ *** afpserver.c Tue Mar 21 17:03:29 1989 --- ../aufsp/afpserver.c Thu Mar 16 10:57:39 1989 *************** *** 221,227 **** printf("SrvrDispatch cmd=%s (%d 0x%x), len=%d\n", d->dsp_name,cmd,cmd,len); - d->dsp_cnt++; /* increment counter */ if (d->dsp_flg & DSPF_DMPIN) --- 221,226 ---- *** aufs.c Tue Mar 21 17:48:26 1989 --- ../aufsp/aufs.c Tue Mar 21 20:42:11 1989 *************** *** 178,200 **** exit(1); } /* ! * generate default name from host name * */ char * afs_default_name() { ! char hostname[255]; static char afsname[255]; char *ap; ! gethostname(hostname,(int) sizeof(hostname)); ! if ((ap = index(hostname,'.')) != NULL) ! *ap = '\0'; /* remove trailing domain name */ ! sprintf(afsname,"%s Aufs",hostname); return(afsname); } doargs(argc,argv) int argc; --- 178,202 ---- exit(1); } + /*PAUL*/ + /* Test server is run as user process, so there may be several on the same + host - invent a default name from the user id */ /* ! * generate default name from user name * */ char * afs_default_name() { ! char username[255]; static char afsname[255]; char *ap; ! cuserid(username); ! sprintf(afsname,"AUFSP (%s)",username); return(afsname); } + /*END*/ doargs(argc,argv) int argc; *************** *** 203,208 **** --- 205,215 ---- int c; extern char *optarg; extern int optind; + + /*PAUL*/ + /* Debug processes by default */ + (void)SetDBLevel("Process"); + /*END*/ while ((c = getopt(argc,argv,"a:d:D:n:N:t:sV:U:G:P:c:l:z:S:R:X:")) != EOF) { switch (c) { *************** *** 301,306 **** --- 308,314 ---- int srvinfolen; import word this_net; import byte this_node; + import void Breakin(); char *getenv(),*env; int pid; int mask; *************** *** 479,484 **** --- 487,493 ---- if (!DBDEB) #endif signal(SIGCHLD, inferiordone); + signal(SIGINT, Breakin); /* PAUL - ctrl/C shuts down gracefully ! */ #ifndef NOSHUTDOWNCODE signal(SIGHUP, killnow); /* kill -HUP -- Immediate shutdown */ signal(SIGTERM, killin5); /* kill -TERM -- Timed (5 min) shutdown */ *** afpos.c Tue Mar 21 17:48:24 1989 --- ../aufsp/afpos.c Thu Mar 16 10:57:36 1989 *************** *** 135,140 **** --- 135,141 ---- #include "afppasswd.h" /* in case we are using privates */ #include "afposncs.h" #include "afpgc.h" + #include "afproc.h" #ifdef MAXBSIZE # define IOBSIZE MAXBSIZE /* set to max buf entry size by if there */ *************** *** 205,210 **** --- 206,213 ---- #endif import int errno; + import PROCESS *FindFd(); + import PROCESS *FindProcess(); /* * AFPOS functions *************** *** 879,884 **** --- 882,891 ---- OSClose(fd) int fd; { + + /*PAUL*/ + if (FindFd(fd)!=NOPROC) return ProcClose(fd); + /*END*/ return(unix_close(fd)); /* return OSErr */ } *************** *** 914,919 **** --- 921,933 ---- } #endif + /*PAUL*/ + { + PROCESS *p; + if ((p=FindFd(fd))!=NOPROC) return( ProcRead( p, r, reqcnt, rl ) ); + } + /*END*/ + if (offs != *fpos) lseek(fd,(off_t)offs,L_SET); *************** *** 991,996 **** --- 1005,1017 ---- if (wlen == 0) /* zero byte request? */ return(noErr); /* yes... no work */ + /*PAUL*/ + { + PROCESS *p; + if ((p=FindFd(fd))!=NOPROC) return( ProcWrite( p, wbuf, wlen ) ); + } + /*END*/ + if (flg == 0) { if (offs != *fpos) *fpos = lseek(fd,(off_t)offs,L_SET); *************** *** 1125,1131 **** if (DBOSI) printf("OSFileDirInfo on %s\n",path); ! if (stat(path,&buf) != 0) { /* file exists? */ if (idir) /* was in directory tree? */ Idrdirid(ipdir, idir); /* invalidate the entry then */ return(aeObjectNotFound); /* no... */ --- 1146,1165 ---- if (DBOSI) printf("OSFileDirInfo on %s\n",path); ! /*PAUL*/ ! if (*fn=='!') { ! PROCESS *p; ! if ( ((p=FindProcess(fn))==NOPROC) || (stat(p->cmnd,&buf)!=0) ){ ! if (idir) /* was in directory tree? */ ! Idrdirid(ipdir, idir); /* invalidate the entry then */ ! return(aeObjectNotFound); /* no... */ ! } ! buf.st_mode |= 0777; ! } ! else ! /*END*/ ! ! if (stat(path,&buf) != 0) { /* file exists? */ if (idir) /* was in directory tree? */ Idrdirid(ipdir, idir); /* invalidate the entry then */ return(aeObjectNotFound); /* no... */ *************** *** 1285,1300 **** if (DBDIR) printf("OSFileInfo on %s bm=%x\n",fn,bm); ! if (bm & FP_ATTR) /* skip attr if not requested */ ! OSGetAttr(ipdir,fn,&fdp->fdp_attr); ! if (bm & FP_FINFO) /* skip finfo if not requested */ ! OSGetFNDR(ipdir,fn,fdp->fdp_finfo); fdp->fdp_parms.fp_parms.fp_fileno = buf->st_ino; fdp->fdp_parms.fp_parms.fp_dflen = buf->st_size; fdp->fdp_parms.fp_parms.fp_rflen = 0; if (bm & FP_RFLEN) { OSfname(rpath,ipdir,fn,F_RSRC); /* convert to rsrc name */ if (stat(rpath,&stb) != 0) /* to figure size of resource fork */ --- 1319,1344 ---- if (DBDIR) printf("OSFileInfo on %s bm=%x\n",fn,bm); ! /*PAUL*/ ! if (*fn!='!') { ! /*END*/ ! if (bm & FP_ATTR) /* skip attr if not requested */ ! OSGetAttr(ipdir,fn,&fdp->fdp_attr); ! if (bm & FP_FINFO) /* skip finfo if not requested */ ! OSGetFNDR(ipdir,fn,fdp->fdp_finfo); ! /*PAUL*/ ! } ! /*END/ fdp->fdp_parms.fp_parms.fp_fileno = buf->st_ino; fdp->fdp_parms.fp_parms.fp_dflen = buf->st_size; fdp->fdp_parms.fp_parms.fp_rflen = 0; + /*PAUL*/ + if (*fn=='!') fdp->fdp_parms.fp_parms.fp_rflen = 0; + else + /*END*/ if (bm & FP_RFLEN) { OSfname(rpath,ipdir,fn,F_RSRC); /* convert to rsrc name */ if (stat(rpath,&stb) != 0) /* to figure size of resource fork */ *************** *** 2209,2215 **** if (DBOSI) printf("OSCreateFile: creating %s with %s\n",path, (delf) ? "OverWrite" : "No OverWrite"); ! err = unix_stat(pathstr(pdir),&stb); if (err != noErr) return(err); --- 2253,2263 ---- if (DBOSI) printf("OSCreateFile: creating %s with %s\n",path, (delf) ? "OverWrite" : "No OverWrite"); ! ! /*PAUL*/ ! if (*file=='!') return ProcCreateFile( file, delf ); ! /*END*/ ! err = unix_stat(pathstr(pdir),&stb); if (err != noErr) return(err); *************** *** 2287,2292 **** --- 2335,2344 ---- if (DBOSI) printf("OSOpenFork: Opening %s for %s\n",path,ms); + + /*PAUL*/ + if (*file=='!') return( ProcOpen( file, mo, fhdl ) ); + /*END*/ return(unix_open(path,mo,fhdl)); } *** afproc.c Tue Mar 21 19:06:30 1989 --- ../aufsp/afproc.c Thu Mar 16 10:57:46 1989 *************** *** 0 **** --- 1,453 ---- + /* Extended routines for AUFS to allow communication with UNIX processes. + Paul Anderson 21/9/88 + */ + + #include <stdio.h> + #include <sys/filio.h> + #include <sys/file.h> + #include <sys/signal.h> + #include <netat/appletalk.h> + #include <netat/afp.h> + #include <errno.h> + #include <netat/afpcmd.h> + #include <signal.h> + #include "afps.h" + #include "afpvols.h" + #include "afppasswd.h" + #include "afposncs.h" + #include "afpgc.h" + #include "afproc.h" + + export void Breakin(); + export PROCESS *FindFd(); + export PROCESS *FindProcess(); + export PROCESS *FindPid(); + export OSErr ProcOpen(); + export OSErr ProcClose(); + export OSErr ProcRead(); + export OSErr ProcWrite(); + export OSErr ProcCreateFile(); + export OSErr ProcDelete(); + + extern int errno; + extern void killnow(); /* Terminate server */ + + PROCESS *procList = NOPROC; /* Linked list of process records */ + private int interrupt = 0; /* CTRL/C pressed flag */ + private int status = WAITING; /* Current server status */ + + + export void Breakin() + { + /* If we have an IO deadlock, break it */ + if (status!=WAITING) { interrupt = 1; return; } + + /* Otherwise, kill all the subprocesses & exit */ + if (DBPRO) + printf( "PROCESS: Interrupt - Terminating all processes\n" ); + while (procList != NOPROC) ProcDelete( procList->cmnd ); + if (DBPRO) + printf( "PROCESS: Exiting server\n" ); + killnow(); + } + + + private char *ConvertPath( path ) + char *path; + { + char *buf = malloc( 1+strlen(path) ), *p=buf; + + while (*path) { + if (*path=='!') { ++path; continue; } + if (!strncmp( path, ":2f", 3 )) { path+=3; *p++='/'; continue; } + *p++ = *path++; + } + *p='\0'; + + return buf; + } + + + export PROCESS + *FindProcess( path ) + char *path; + { + PROCESS *p = procList; + + path = ConvertPath( path ); + + while (p!=NOPROC) + if (!strcmp( path, p->cmnd )) { free(path); return p; } + else p=p->nextProc; + + free(path); + return (NOPROC); + } + + + export PROCESS + *FindFd( fd ) + int fd; + { + PROCESS *p = procList; + + while (p!=NOPROC) + if ((p->status!=PROC_CLOSED) && (fd==p->fdi[1])) return p; + else p=p->nextProc; + + return NOPROC; + } + + + export OSErr ProcDelete( path ) + char *path; + { + PROCESS *s, *p = FindProcess( path ); + + if (DBPRO) + printf( "PROCESS: Deleting path: %s\n", path ); + + if (p==NOPROC) return (aeObjectNotFound); + + if (p->status!=PROC_CLOSED) ProcShut(p->fdi[1]); + + if (p==procList) procList=p->nextProc; + else { + for ( s=procList; s->nextProc!=p; s=s->nextProc ) ; + s->nextProc = p->nextProc; + } + + if (DBPRO) + printf( "PROCESS: Deleted: [%08x] %s\n", (unsigned)p, p->cmnd ); + + free(p->cmnd); free(p); + + return (noErr); + } + + + export OSErr + ProcCreateFile( path, delf ) + char *path; + int delf; + { + PROCESS *p; + + if (DBPRO) + printf( "PROCESS: Creating path: %s\n", path ); + + if ( FindProcess( path ) != NOPROC ) { + if (delf) (void)ProcDelete( path ); + else return (aeObjectExists); + } + + if ( ( (p=(PROCESS*)malloc( sizeof(*p) )) == NOPROC ) ) return (aeMiscErr); + + if ( ( p->cmnd = ConvertPath(path) ) == (char*)0 ) { + free(p); return(aeMiscErr); + } + + if ( access( p->cmnd, X_OK ) == -1 ) { + free(p); return(aeObjectNotFound); + } + + if (DBPRO) + printf( "PROCESS: Created: [%08x] %s\n", (unsigned)p, p->cmnd ); + + p->status = PROC_CLOSED; + + p->nextProc = procList; + procList = p; + + return (noErr); + } + + + export OSErr + ProcOpen( path, mo, fhdl ) + char *path; + int mo; + int *fhdl; + { + int block = 1; + PROCESS *p = FindProcess( path ); + + if (DBPRO) + printf( "PROCESS: Opening path: %s\n", path ); + + if (p==NOPROC) return(aeObjectNotFound); + + if (p->status==PROC_CLOSED) { + + if ( pipe(&(p->fdi[0])) == -1 ) { + return (aeMiscErr); + } + + ioctl( p->fdi[1], FIONBIO, &block ); + + if ( pipe(&(p->fdo[0])) == -1 ) { + close(p->fdi[0]); close(p->fdo[1]); + return (aeMiscErr); + } + + p->status = PROC_OPEN; + } + + *fhdl = p->fdi[1]; + + if (DBPRO) + printf( "PROCESS: Opened: [%08x] %s in=(%d,%d) out=(%d,%d)\n", + (unsigned)p, p->cmnd, p->fdi[0], p->fdi[1], p->fdo[0], p->fdo[1] ); + + return (noErr); + } + + + export PROCESS + *FindPid( pid ) + int pid; + { + PROCESS *p = procList; + + while (p!=NOPROC) + if ((p->status==PROC_RUNNING) && (pid==p->pid)) return p; + else p=p->nextProc; + + return NOPROC; + } + + + private void KillProcess(p) + PROCESS *p; + { + union wait status; + int timer; + + if (DBPRO) + printf( "PROCESS: Terminating: [%08x] %s\n", (unsigned)p, p->cmnd ); + + /* Give it two seconds to terminate by itself */ + for (timer=0; timer<4; ++timer) { + if ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) > 0 ) break; + abSleep( 2, TRUE ); + } + + /* Give it a hangup, then another two seconds to clean up */ + if ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) == 0 ) { + if (DBPRO) + printf( "PROCESS: Hanging Up: [%08x] %s\n", (unsigned)p, p->cmnd ); + kill( p->pid, SIGHUP ); + for (timer=0; timer<4; ++timer) { + if ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) > 0 ) break; + abSleep( 2, TRUE ); + } + } + + /* If it still hasnt gone, kill it */ + if ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) == 0 ) { + if (DBPRO) + printf( "PROCESS: Killing: [%08x] %s\n", (unsigned)p, p->cmnd ); + kill( p->pid, SIGKILL ); + } + + /* Now wait for it */ + while ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) == 0 ) + abSleep( 2, TRUE );; + if (DBPRO) + printf( "PROCESS: Died: [%08x] %s status=%04x\n", + (unsigned)p, p->cmnd, status ); + + p->status=PROC_OPEN; + p->termStat = status; + } + + + export OSErr + ProcClose(fd) + int fd; + { + #ifdef NOCLOSE + return(noErr); + #else + return ProcShut(fd); + #endif + } + + + private OSErr + ProcShut(fd) + int fd; + { + PROCESS *p = FindFd(fd); + + if (DBPRO) + printf( "PROCESS: Closing fd: %d\n", fd ); + + if ( (p==NOPROC) || (p->status==PROC_CLOSED) ) return (noErr); + + close( p->fdi[1] ); close( p->fdo[0] ); + + if (p->status==PROC_RUNNING) KillProcess(p); + else { close(p->fdi[0]); close(p->fdo[1]); } + + if (DBPRO) + printf( "PROCESS: Closed: [%08x] %s\n", (unsigned)p, p->cmnd ); + + p->status = PROC_CLOSED; + + return (noErr); + } + + + private void StartProcess(p) + PROCESS *p; + { + if (DBPRO) + printf( "PROCESS: Starting: [%08x] %s\n", (unsigned)p, p->cmnd ); + + if (p->pid=fork()) { + + close(p->fdi[0]); + close(p->fdo[1]); + p->status=PROC_RUNNING; + if (DBPRO) + printf( "PROCESS: Started: [%08x] %s pid=%d\n", + (unsigned)p, p->cmnd, p->pid ); + return; + + } else { + + dup2(p->fdi[0],0); + dup2(p->fdo[1],1); + close(p->fdi[0]); + close(p->fdo[0]); + close(p->fdi[1]); + close(p->fdo[1]); + signal( SIGINT, SIG_IGN ); + execlp( p->cmnd, p->cmnd, (char*)0 ); + exit(0x99); + } + } + + + export OSErr + ProcWrite( p, buf, len ) + PROCESS *p; + char *buf; + int len; + { + int count; + char *s; + + if (DBPRO) + printf( "PROCESS: Writing: [%08x] %s bytes=%d\n", + (unsigned)p, p->cmnd, len ); + + if (p->status==PROC_CLOSED) return(aeEOFErr); + if (p->status==PROC_OPEN) StartProcess(p); + + for ( count=len, s=buf; count>0; --count, ++s ) if (*s=='\r') *s='\n'; + + status = WRITING; interrupt = 0; + + for (;;) { + + count = write( p->fdi[1], buf, len ); + + if (DBPRO && (count>0)) + printf( "PROCESS: Wrote: [%08x] %s bytes=%d\n", + (unsigned)p, p->cmnd, count ); + + if (count==len) { status = WAITING; return (noErr); } + else if (count>=0) { len-=count; buf=&buf[count]; } + else if (errno!=EWOULDBLOCK) { status = WAITING; return (aeMiscErr); }; + + if ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) != 0 ) { + close( p->fdi[1] ); close( p->fdo[0] ); + p->status=PROC_CLOSED; + status = WAITING; + return (aeMiscErr); + } + + if (interrupt) { + interrupt=0; + status = WAITING; + if (DBPRO) + printf( "PROCESS: Write interrupted: [%08x] %s\n", + (unsigned)p, p->cmnd ); + return (aeMiscErr); + } + + abSleep( 2, TRUE ); + } + } + + + export OSErr + ProcRead( p, buf, len, rl ) + PROCESS *p; + char *buf; + int len; + int *rl; + { + long count; + + if (DBPRO) + printf( "PROCESS: Reading: [%08x] %s maxbytes=%d\n", + (unsigned)p, p->cmnd, len ); + + if (p->status==PROC_CLOSED) return(aeEOFErr); + if (p->status==PROC_OPEN) StartProcess(p); + + status = READING; + interrupt = 0; + + for (;;) { + + if ( ioctl( p->fdo[0], FIONREAD, &count ) == -1 ) { + ProcShut(p->fdi[1]); + status = WAITING; + return(aeEOFErr); + } + + if (count>0) { + + if (count>len) count=len; + count = read( p->fdo[0], buf, (int)count ); + *rl = count; + + while (count) { if (*buf=='\n') *buf='\r'; ++buf; --count; } + + if (DBPRO) + printf( "PROCESS: Read: [%08x] %s bytes=%d\n", + (unsigned)p, p->cmnd, *rl ); + + status = WAITING; + + return (noErr); + } + + if ( wait4( p->pid, &(p->termStat), WNOHANG, NULL ) != 0 ) { + close( p->fdi[1] ); close( p->fdo[0] ); + p->status=PROC_CLOSED; + status = WAITING; + if (DBPRO) + printf( "PROCESS: Died while reading: [%08x] %s pid=%d\n", + (unsigned)p, p->cmnd, p->pid ); + return (aeEOFErr); + } + + if (interrupt) { + interrupt=0; + *rl=0; + status = WAITING; + if (DBPRO) + printf( "PROCESS: Read interrupted: [%08x] %s\n", + (unsigned)p, p->cmnd ); + return (aeEOFErr); + } + + abSleep( 2, TRUE ); + } + } + *** afproc.h Tue Mar 21 19:06:31 1989 --- ../aufsp/afproc.h Thu Mar 16 10:57:47 1989 *************** *** 0 **** --- 1,28 ---- + #include <sys/wait.h> + + /* Active process record */ + + typedef struct process { + int pid; /* Process ID */ + union wait termStat; /* Termination status */ + int fdi[2]; /* Input pipe to process */ + int fdo[2]; /* Output pipe from process */ + int status; /* Process status */ + char *cmnd; /* Process command line */ + struct process *nextProc; /* Pointer to next process record */ + } PROCESS; + + #define NOPROC (PROCESS*)0 /* Null process pointer */ + + /* States in process record */ + + #define PROC_CLOSED 1 /* Process created */ + #define PROC_OPEN 2 /* Pipes are open */ + #define PROC_RUNNING 3 /* Process is running */ + + /* Server states */ + + #define WAITING 1 /* Server is not blocked */ + #define READING 2 /* Server is blocked in a read */ + #define WRITING 3 /* Server is blocked in a write */ + ------------------------------------------------- END Paul Anderson JANET: paul@uk.ac.ed.lfcs LFCS, Dept. of Computer Science UUCP: ..!mcvax!ukc!lfcs!paul University of Edinburgh ARPA: paul%lfcs.ed.ac.uk@nss.cs.ucl.ac.uk Edinburgh EH9 3JZ, UK. Tel: 031-667-1081 Ext 2788