# static char sccsid[] = " unixtraps.c 4.1 82/05/12 "; /* 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); }