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