+#
+/* Function to execute version 6 and version 7 UNIX system calls from
+ * compatability mode on UNIX-32V.
+ * Art Wetzel August 1979
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef V6UNIX
+#ifdef TRACE
+#define RTSNAME "/../../../../usr/local/v6trc"
+#else
+#define RTSNAME "/../../../../usr/local/v6run"
+#endif
+#include "unix6sys.h"
+#ifdef TRACE
+#include "unix6sysn.h"
+#endif
+#endif
+#ifdef V7UNIX
+#ifdef TRACE
+#define RTSNAME "/../../../../usr/local/v7trc"
+#else
+#define RTSNAME "/../../../../usr/local/v7run"
+#endif
+#include "unix7sys.h"
+#ifdef TRACE
+#include "unix7sysn.h"
+#endif
+#endif
+#include "defs.h"
+#define CARRY 1
+#define MAXSARGS 25
+#ifdef V6UNIX
+#define ARGVLEN 512
+#define ENVLEN 0
+#endif
+#ifdef V7UNIX
+#define ARGVLEN 5120
+#define ENVLEN 1000
+#endif
+char argvs[ARGVLEN+ENVLEN];
+int args[MAXSARGS];
+/* 32v type stat structure */
+extern struct stat stat32v;
+/* place for times data so we can reverse the longs */
+struct timebuf {
+ long t1;
+ long t2;
+ long t3;
+ long t4;
+} timebuf;
+/* place for pipe file descriptors */
+int pipes[2];
+/* wait status */
+int wstatus;
+#ifdef V6UNIX
+/* version 6 style stat structure */
+struct v6nod {
+ dev_t majmin;
+ ino_t inumber;
+ unsigned short flags;
+ unsigned char nlinks;
+ unsigned char uid;
+ unsigned char gid;
+ unsigned char size0;
+ unsigned short size1;
+ unsigned short addr[8];
+ long actime;
+ long modtime;
+} *v6stat;
+#endif
+/* do the trap stuff for the trap with code */
+dotrap(code) int code; {
+ register unsigned short *argp, *savp, *savep;
+ register int i, j, indirflg;
+ register char *avp, *oavp;
+ extern sigcatch();
+ extern errno;
+ /* clear out condition codes of psl */
+ psl &= ~017;
+ /* special case of indirect sys call */
+ if(code == 0) {
+ /* remember this was indirect */
+ indirflg = 1;
+ /* point to args */
+ argp = (unsigned short *)*(pc++);
+ /* code for indirect sys call */
+ code = *argp++;
+ /* is it legit */
+ if(code>>8 != TRAPS) {
+ fprintf(stderr,"Bad indirect sys call at 0x%x\n",pc-2);
+ pc++;
+ /* set carry flag */
+ psl |= CARRY;
+ regs[0] = -1;
+ return(-1);
+ }
+ code &= 0377;
+ }
+ else {
+ /* remember this was not indirect */
+ indirflg = 0;
+ /* point to args */
+ argp = pc;
+ }
+ /* check if code too high or bad sys code */
+ if(code >= NSYSTRAPS || sysargs[code][0] == ILLSYS) {
+ fprintf(stderr,"Unimplimented trap %d at 0x%x\n",code,argp);
+ /* set carry bit */
+ psl |= CARRY;
+ regs[0] = -1;
+ return(-1);
+ }
+ /* copy args to known locations */
+ i=0;
+ for(j=0; j<sysargs[code][0]; j++) args[i++] = regs[j];
+ for(j=0; j<(sysargs[code][1]); j++) args[i++] = *argp++;
+#ifdef TRACE
+ fprintf(stderr,"pid %d ",getpid());
+ if(indirflg) fprintf(stderr,"indirect ");
+ fprintf(stderr,"%s (%d) from 0%o with %d args",sysnames[code],code,pc-1,i);
+ for(j=0; j<i; j++)
+ fprintf(stderr," 0%o",args[j]);
+ if(code==OPEN||code==STAT||code==CREAT||code==EXEC||code==UNLNK||code==LINK||code==CHDIR||code==MKNOD)
+ fprintf(stderr," (%s)",args[0]);
+#ifdef V7UNIX
+ if(code==EXECE)
+ fprintf(stderr," (%s)",args[0]);
+#endif
+ if(code==LINK)
+ fprintf(stderr," (%s)",args[1]);
+#endif
+ /* go do whatever sys call it is */
+ switch(code) {
+ case FORK:
+ /* indirect forks return pids on both sides - must do here */
+ /* this is possibly a bug in 32V */
+ i = fork();
+ break;
+ case WAIT:
+ i = wait(&wstatus);
+ args[0] = i;
+ args[1] = wstatus;
+ break;
+ case EXEC:
+#ifdef V7UNIX
+ case EXECE:
+#endif
+ /*
+ * have to do a lot of junk here to fix up an argv
+ * for execute since (1) the pdp-11 argv consists of 16
+ * bit pointers and (2) the argv itself is in the
+ * pdp-11 program space where it would get clobbered
+ * when a new program is read in and before its
+ * argv is set up.
+ */
+ avp = &argvs[0];
+ savp = (unsigned short *)args[1];
+#ifdef V6UNIX
+ for(i=1; args[i] = *savp++; i++)
+ if(args[i] == 0177777) break;
+#ifdef TRACE
+ else fprintf(stderr,"argv[%d]%s ",i-1,args[i]);
+#endif
+#endif
+#ifdef V7UNIX
+ savep = (unsigned short *)args[2];
+ for(i=1; args[i] = *savp++; i++)
+#ifdef TRACE
+ fprintf(stderr,"argv[%d]%s ",i-1,args[i]);
+#else
+ ;
+#endif
+#endif
+ if(stat(args[0], &stat32v)) {
+ /* return error here if file does not exist */
+#ifdef TRACE
+ fprintf(stderr," does not exist\n");
+#endif
+ i = -1;
+ break;
+ }
+ /* must have execute permission */
+ if(stat32v.st_mode & (S_IEXEC>>6)) goto experm;
+ if(stat32v.st_mode & (S_IEXEC>>3)) {
+ if(stat32v.st_gid == getegid()) goto experm;
+ if(geteuid() == 0) goto experm;
+ }
+ if(stat32v.st_mode & S_IEXEC) {
+ if(stat32v.st_uid == geteuid()) goto experm;
+ if(geteuid() == 0) goto experm;
+ }
+ /* return failure if no exec permision allowed */
+ i = -1;
+experm:
+ /* can't exec a directory */
+ if(stat32v.st_mode & S_IFDIR)
+ i = -1;
+ if(i == -1) break;
+ args[i] = 0;
+ for(j=0; j<i; j++) {
+ oavp = (char *)args[j];
+ args[j] = (int)avp;
+ while(*avp++ = *oavp++) ;
+ }
+#ifdef V7UNIX
+ if(code == EXECE) {
+ for(j = ++i; args[j] = *savep++; j++) ;
+ for( ; j>i; j--) {
+ oavp = (char *)args[j];
+ args[j] = (int)avp;
+ while(*avp++ = *oavp++) ;
+ }
+ }
+#endif
+ /* SETUID and SETGID files must be started with a fresh RTS */
+ if(stat32v.st_mode & S_ISGID || stat32v.st_mode & S_ISUID) {
+ /* should add a check here for good magic # in header */
+ args[1] = args[0];
+ args[0] = (int)RTSNAME;
+#ifdef TRACE
+ fprintf(stderr," SETUID-GID");
+#endif
+ if(args[i])
+ i = execve(args[0], &args[0], &args[i]);
+ else
+ i = execv(args[0], &args[0]);
+ fprintf(stderr,"can't exec %s\n",RTSNAME);
+ break;
+ }
+ i = execute(args[0], &args[1], &args[i]);
+ /* shouldn't get here if exec works */
+ break;
+ case SEEK:
+#ifdef V6UNIX
+ /* fix up negative offsets */
+ if(args[2] != 0 && args[2] != 3)
+ if(args[1] >= 32768) args[1] -= 65536;
+ if(args[2] <= 2)
+ i = lseek(args[0], args[1], args[2]);
+ else
+ i = lseek(args[0], args[1]*512, args[2]-3);
+ if(i != -1) i = 0;
+#endif
+#ifdef V7UNIX
+ i = lseek(args[0], (args[1]<<16)|(args[2]&0177777), args[3]);
+#endif
+ break;
+#ifdef V6UNIX
+ case MKNOD:
+ /* version 6 uses allocated bit which means regular file here */
+ if(args[1] & S_IFBLK)
+ args[1] &= ~S_IFREG;
+ i = mknod(args[0], args[1], args[2]);
+ break;
+#endif
+ case PIPE:
+ i = pipe(pipes);
+ args[0] = pipes[0];
+ args[1] = pipes[1];
+ break;
+#ifdef V6UNIX
+ case TELL:
+ i = lseek(args[0], 0L, 1);
+ break;
+#endif
+ case STAT:
+ case FSTAT:
+ /* do the syscall to a local stat buffer */
+ i = syscall(code, args[0], &stat32v);
+ /* reverse the longs */
+ stat32v.st_size = longrev(stat32v.st_size);
+ stat32v.st_atime = longrev(stat32v.st_atime);
+ stat32v.st_mtime = longrev(stat32v.st_mtime);
+ stat32v.st_ctime = longrev(stat32v.st_ctime);
+#ifdef V7UNIX
+ /* copy out otherwise unchanged stat buffer */
+ /* in two pieces with st_size as the breaking point */
+ /* note that st_rdev is a short but due to alingnmemt */
+ /* problems the rest of the structure is out of sync */
+ j = (int)((char *)(&stat32v.st_size)-(char *)(&stat32v.st_dev));
+ bcopy(&stat32v, args[1], j);
+ bcopy(&stat32v.st_size, args[1]+j-2, sizeof(struct stat)-j);
+#endif
+#ifdef V6UNIX
+ /* point to user area as v6stat structure */
+ v6stat = (struct v6nod *)args[1];
+ /* copy out piece by piece */
+ v6stat->majmin = stat32v.st_dev;
+ v6stat->inumber = stat32v.st_ino;
+ v6stat->flags = stat32v.st_mode;
+ v6stat->nlinks = (unsigned char)stat32v.st_nlink;
+ v6stat->uid = (unsigned char)stat32v.st_uid;
+ v6stat->gid = (unsigned char)stat32v.st_gid;
+ /* note size already reversed */
+ v6stat->size0 = (unsigned char)(stat32v.st_size & 0377);
+ v6stat->size1 = (unsigned short)(stat32v.st_size>>16);
+ v6stat->actime = stat32v.st_atime;
+ v6stat->modtime = stat32v.st_mtime;
+ /* patch up flags */
+ /* for now just set 100000 bit if not a plain file */
+ if(v6stat->flags & 060000)
+ v6stat->flags |= 0100000;
+#endif
+ break;
+ case TIMES:
+ i = times(&timebuf);
+ timebuf.t2 = longrev(timebuf.t2) + timebuf.t1;
+ timebuf.t3 = longrev(timebuf.t3);
+ timebuf.t4 = longrev(timebuf.t4);
+ bcopy(&timebuf.t2,args[0],sizeof(struct timebuf)-sizeof(long));
+ break;
+#ifdef V6UNIX
+ case SLEEP:
+ /* do a sleep function - what about pwb which has alarm? */
+ sleep(args[0]);
+ break;
+#endif
+ case GETUID:
+ args[0] = getuid();
+ args[1] = geteuid();
+#ifdef V6UNIX
+ i = args[1]<<8 | args[0];
+#endif
+ break;
+ case GETGID:
+ args[0] = getgid();
+ args[1] = getegid();
+#ifdef V6UNIX
+ i = args[1]<<8 | args[0];
+#endif
+ break;
+#ifdef V6UNIX
+ case SETUID:
+ case SETGID:
+ /* uids and gids are 8 bits in version 6 */
+ i = syscall(code,args[0]&0377);
+ break;
+#endif
+ case SIG:
+ /* if it is a good signal code */
+ if(args[0] <= NSIG) {
+ /* get the current signal value */
+ i = sigvals[args[0]];
+ /* reset the signal to the new value */
+ sigvals[args[0]] = args[1];
+ /* actually do signal except don't reset SIGILL */
+ if(args[0] != SIGILL) {
+ if(args[1] == (int)SIG_DFL || args[1] & (int)SIG_IGN) {
+ if((int)signal(args[0],args[1]) == -1)
+ i = -1;
+ } else {
+ if((int)signal(args[0], sigcatch) == -1)
+ i = -1;
+ }
+ }
+ }
+ else i = -1;
+ break;
+ case BRK:
+ /* brk is successful unless we run over the stack */
+ i = 0;
+ if(args[0] >= regs[6]) i = -1;
+ break;
+#ifdef V6UNIX
+ case PWBSYS:
+ /* ignore pwbsys for now */
+ switch(args[2]) {
+ case UNAME:
+#ifdef TRACE
+ fprintf(stderr,"UNAME with %d %d\n",args[0],args[1]);
+#endif
+ strcpy(args[0],"pwbname");
+ i = 0;
+ break;
+ case UDATA:
+#ifdef TRACE
+ fprintf(stderr,"UDATA with %d %d\n",args[0],args[1]);
+#endif
+ i = 0;
+ break;
+ case USTAT:
+fprintf(stderr,"USTAT with %d %d\n",args[0],args[1]);
+ i = 0;
+ break;
+ case UTIME:
+fprintf(stderr,"UTIME with %d %d\n",args[0],args[1]);
+ i = 0;
+ break;
+ default:
+fprintf(stderr,"bad PWBSYS %d\n",args[3]);
+ i = -1;
+ break;
+ }
+ break;
+#endif
+ default:
+ /*
+ * Many sys calls are easily done here since most
+ * system call codes are the same on version 6 and 7 UNIX
+ * as they are here.
+ */
+ i = syscall(code,args[0],args[1],args[2],args[3],args[4]);
+#ifdef V6UNIX
+ /* allow read write access to created files for(IDIS v6 mod) */
+ if(code==CREAT) {
+ /* get actual file mode after create */
+ fstat(i, &stat32v);
+ close(i);
+ /* ensure read/write access to owner */
+ chmod(args[0], 0644);
+ i = open(args[0], 2);
+ /* change mode back the way it was */
+ chmod(args[0], stat32v.st_mode);
+ }
+#endif
+ break;
+ }
+#ifdef TRACE
+ fprintf(stderr," sys val -> 0%o\n",i);
+#endif
+ /* set carry bit if sys error */
+ if(i == -1)
+ psl |= CARRY;
+ /* if not an indirect sys call, adjust the pc */
+ if(indirflg == 0)
+ pc = argp;
+ /* do alternate return on one side of fork */
+ if(code == FORK && i != 0)
+ pc++;
+ /* do the various return value formats */
+ switch(sysargs[code][2]) {
+ case NORMRET:
+ /* normal case only one return value in r0 */
+ regs[0] = i;
+ break;
+ case LONGRET:
+ /* return a long in r0 - r1 as in time */
+ regs[1] = i;
+ regs[0] = i >> 16;
+ break;
+ case TWORET:
+ /* return two ints in r0 - r1 as in pipe */
+ if(i == -1)
+ regs[0] = i;
+ else {
+ regs[1] = args[1];
+ regs[0] = args[0];
+ }
+ break;
+ }
+ if(i== -1)
+ regs[0] = errno;
+}
+long longrev(l) long l; {
+ /* function to reverse the halves of a long */
+ union {
+ long lng;
+ short s[2];
+ } u;
+ register short t;
+ u.lng = l;
+ t = u.s[0];
+ u.s[0] = u.s[1];
+ u.s[1] = t;
+ return(u.lng);
+}