1 # 2 static char sccsid[] = " unixtraps.c 4.1 82/05/12 "; 3 /* Function to execute version 6 and version 7 UNIX system calls from 4 * compatability mode on UNIX-32V. 5 * Art Wetzel August 1979 6 */ 7 #include <stdio.h> 8 #include <signal.h> 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 #ifdef V6UNIX 12 #ifdef TRACE 13 #define RTSNAME "/../../../../usr/local/v6trc" 14 #else 15 #define RTSNAME "/../../../../usr/local/v6run" 16 #endif 17 #include "unix6sys.h" 18 #ifdef TRACE 19 #include "unix6sysn.h" 20 #endif 21 #endif 22 #ifdef V7UNIX 23 #ifdef TRACE 24 #define RTSNAME "/../../../../usr/local/v7trc" 25 #else 26 #define RTSNAME "/../../../../usr/local/v7run" 27 #endif 28 #include "unix7sys.h" 29 #ifdef TRACE 30 #include "unix7sysn.h" 31 #endif 32 #endif 33 #include "defs.h" 34 #define CARRY 1 35 #define MAXSARGS 25 36 #ifdef V6UNIX 37 #define ARGVLEN 512 38 #define ENVLEN 0 39 #endif 40 #ifdef V7UNIX 41 #define ARGVLEN 5120 42 #define ENVLEN 1000 43 #endif 44 char argvs[ARGVLEN+ENVLEN]; 45 int args[MAXSARGS]; 46 /* 32v type stat structure */ 47 extern struct stat stat32v; 48 /* place for times data so we can reverse the longs */ 49 struct timebuf { 50 long t1; 51 long t2; 52 long t3; 53 long t4; 54 } timebuf; 55 /* place for pipe file descriptors */ 56 int pipes[2]; 57 /* wait status */ 58 int wstatus; 59 #ifdef V6UNIX 60 /* version 6 style stat structure */ 61 struct v6nod { 62 dev_t majmin; 63 ino_t inumber; 64 unsigned short flags; 65 unsigned char nlinks; 66 unsigned char uid; 67 unsigned char gid; 68 unsigned char size0; 69 unsigned short size1; 70 unsigned short addr[8]; 71 long actime; 72 long modtime; 73 } *v6stat; 74 #endif 75 /* do the trap stuff for the trap with code */ 76 dotrap(code) int code; { 77 register unsigned short *argp, *savp, *savep; 78 register int i, j, indirflg; 79 register char *avp, *oavp; 80 extern sigcatch(); 81 extern errno; 82 /* clear out condition codes of psl */ 83 psl &= ~017; 84 /* special case of indirect sys call */ 85 if(code == 0) { 86 /* remember this was indirect */ 87 indirflg = 1; 88 /* point to args */ 89 argp = (unsigned short *)*(pc++); 90 /* code for indirect sys call */ 91 code = *argp++; 92 /* is it legit */ 93 if(code>>8 != TRAPS) { 94 fprintf(stderr,"Bad indirect sys call at 0x%x\n",pc-2); 95 pc++; 96 /* set carry flag */ 97 psl |= CARRY; 98 regs[0] = -1; 99 return(-1); 100 } 101 code &= 0377; 102 } 103 else { 104 /* remember this was not indirect */ 105 indirflg = 0; 106 /* point to args */ 107 argp = pc; 108 } 109 /* check if code too high or bad sys code */ 110 if(code >= NSYSTRAPS || sysargs[code][0] == ILLSYS) { 111 fprintf(stderr,"Unimplimented trap %d at 0x%x\n",code,argp); 112 /* set carry bit */ 113 psl |= CARRY; 114 regs[0] = -1; 115 return(-1); 116 } 117 /* copy args to known locations */ 118 i=0; 119 for(j=0; j<sysargs[code][0]; j++) args[i++] = regs[j]; 120 for(j=0; j<(sysargs[code][1]); j++) args[i++] = *argp++; 121 #ifdef TRACE 122 fprintf(stderr,"pid %d ",getpid()); 123 if(indirflg) fprintf(stderr,"indirect "); 124 fprintf(stderr,"%s (%d) from 0%o with %d args",sysnames[code],code,pc-1,i); 125 for(j=0; j<i; j++) 126 fprintf(stderr," 0%o",args[j]); 127 if(code==OPEN||code==STAT||code==CREAT||code==EXEC||code==UNLNK||code==LINK||code==CHDIR||code==MKNOD) 128 fprintf(stderr," (%s)",args[0]); 129 #ifdef V7UNIX 130 if(code==EXECE) 131 fprintf(stderr," (%s)",args[0]); 132 #endif 133 if(code==LINK) 134 fprintf(stderr," (%s)",args[1]); 135 #endif 136 /* go do whatever sys call it is */ 137 switch(code) { 138 case FORK: 139 /* indirect forks return pids on both sides - must do here */ 140 /* this is possibly a bug in 32V */ 141 i = fork(); 142 break; 143 case WAIT: 144 i = wait(&wstatus); 145 args[0] = i; 146 args[1] = wstatus; 147 break; 148 case EXEC: 149 #ifdef V7UNIX 150 case EXECE: 151 #endif 152 /* 153 * have to do a lot of junk here to fix up an argv 154 * for execute since (1) the pdp-11 argv consists of 16 155 * bit pointers and (2) the argv itself is in the 156 * pdp-11 program space where it would get clobbered 157 * when a new program is read in and before its 158 * argv is set up. 159 */ 160 avp = &argvs[0]; 161 savp = (unsigned short *)args[1]; 162 #ifdef V6UNIX 163 for(i=1; args[i] = *savp++; i++) 164 if(args[i] == 0177777) break; 165 #ifdef TRACE 166 else fprintf(stderr,"argv[%d]%s ",i-1,args[i]); 167 #endif 168 #endif 169 #ifdef V7UNIX 170 savep = (unsigned short *)args[2]; 171 for(i=1; args[i] = *savp++; i++) 172 #ifdef TRACE 173 fprintf(stderr,"argv[%d]%s ",i-1,args[i]); 174 #else 175 ; 176 #endif 177 #endif 178 if(stat(args[0], &stat32v)) { 179 /* return error here if file does not exist */ 180 #ifdef TRACE 181 fprintf(stderr," does not exist\n"); 182 #endif 183 i = -1; 184 break; 185 } 186 /* must have execute permission */ 187 if(stat32v.st_mode & (S_IEXEC>>6)) goto experm; 188 if(stat32v.st_mode & (S_IEXEC>>3)) { 189 if(stat32v.st_gid == getegid()) goto experm; 190 if(geteuid() == 0) goto experm; 191 } 192 if(stat32v.st_mode & S_IEXEC) { 193 if(stat32v.st_uid == geteuid()) goto experm; 194 if(geteuid() == 0) goto experm; 195 } 196 /* return failure if no exec permision allowed */ 197 i = -1; 198 experm: 199 /* can't exec a directory */ 200 if(stat32v.st_mode & S_IFDIR) 201 i = -1; 202 if(i == -1) break; 203 args[i] = 0; 204 for(j=0; j<i; j++) { 205 oavp = (char *)args[j]; 206 args[j] = (int)avp; 207 while(*avp++ = *oavp++) ; 208 } 209 #ifdef V7UNIX 210 if(code == EXECE) { 211 for(j = ++i; args[j] = *savep++; j++) ; 212 for( ; j>i; j--) { 213 oavp = (char *)args[j]; 214 args[j] = (int)avp; 215 while(*avp++ = *oavp++) ; 216 } 217 } 218 #endif 219 /* SETUID and SETGID files must be started with a fresh RTS */ 220 if(stat32v.st_mode & S_ISGID || stat32v.st_mode & S_ISUID) { 221 /* should add a check here for good magic # in header */ 222 args[1] = args[0]; 223 args[0] = (int)RTSNAME; 224 #ifdef TRACE 225 fprintf(stderr," SETUID-GID"); 226 #endif 227 if(args[i]) 228 i = execve(args[0], &args[0], &args[i]); 229 else 230 i = execv(args[0], &args[0]); 231 fprintf(stderr,"can't exec %s\n",RTSNAME); 232 break; 233 } 234 i = execute(args[0], &args[1], &args[i]); 235 /* shouldn't get here if exec works */ 236 break; 237 case SEEK: 238 #ifdef V6UNIX 239 /* fix up negative offsets */ 240 if(args[2] != 0 && args[2] != 3) 241 if(args[1] >= 32768) args[1] -= 65536; 242 if(args[2] <= 2) 243 i = lseek(args[0], args[1], args[2]); 244 else 245 i = lseek(args[0], args[1]*512, args[2]-3); 246 if(i != -1) i = 0; 247 #endif 248 #ifdef V7UNIX 249 i = lseek(args[0], (args[1]<<16)|(args[2]&0177777), args[3]); 250 #endif 251 break; 252 #ifdef V6UNIX 253 case MKNOD: 254 /* version 6 uses allocated bit which means regular file here */ 255 if(args[1] & S_IFBLK) 256 args[1] &= ~S_IFREG; 257 i = mknod(args[0], args[1], args[2]); 258 break; 259 #endif 260 case PIPE: 261 i = pipe(pipes); 262 args[0] = pipes[0]; 263 args[1] = pipes[1]; 264 break; 265 #ifdef V6UNIX 266 case TELL: 267 i = lseek(args[0], 0L, 1); 268 break; 269 #endif 270 case STAT: 271 case FSTAT: 272 /* do the syscall to a local stat buffer */ 273 i = syscall(code, args[0], &stat32v); 274 /* reverse the longs */ 275 stat32v.st_size = longrev(stat32v.st_size); 276 stat32v.st_atime = longrev(stat32v.st_atime); 277 stat32v.st_mtime = longrev(stat32v.st_mtime); 278 stat32v.st_ctime = longrev(stat32v.st_ctime); 279 #ifdef V7UNIX 280 /* copy out otherwise unchanged stat buffer */ 281 /* in two pieces with st_size as the breaking point */ 282 /* note that st_rdev is a short but due to alingnmemt */ 283 /* problems the rest of the structure is out of sync */ 284 j = (int)((char *)(&stat32v.st_size)-(char *)(&stat32v.st_dev)); 285 bcopy(&stat32v, args[1], j); 286 bcopy(&stat32v.st_size, args[1]+j-2, sizeof(struct stat)-j); 287 #endif 288 #ifdef V6UNIX 289 /* point to user area as v6stat structure */ 290 v6stat = (struct v6nod *)args[1]; 291 /* copy out piece by piece */ 292 v6stat->majmin = stat32v.st_dev; 293 v6stat->inumber = stat32v.st_ino; 294 v6stat->flags = stat32v.st_mode; 295 v6stat->nlinks = (unsigned char)stat32v.st_nlink; 296 v6stat->uid = (unsigned char)stat32v.st_uid; 297 v6stat->gid = (unsigned char)stat32v.st_gid; 298 /* note size already reversed */ 299 v6stat->size0 = (unsigned char)(stat32v.st_size & 0377); 300 v6stat->size1 = (unsigned short)(stat32v.st_size>>16); 301 v6stat->actime = stat32v.st_atime; 302 v6stat->modtime = stat32v.st_mtime; 303 /* patch up flags */ 304 /* for now just set 100000 bit if not a plain file */ 305 if(v6stat->flags & 060000) 306 v6stat->flags |= 0100000; 307 #endif 308 break; 309 case TIMES: 310 i = times(&timebuf); 311 timebuf.t2 = longrev(timebuf.t2) + timebuf.t1; 312 timebuf.t3 = longrev(timebuf.t3); 313 timebuf.t4 = longrev(timebuf.t4); 314 bcopy(&timebuf.t2,args[0],sizeof(struct timebuf)-sizeof(long)); 315 break; 316 #ifdef V6UNIX 317 case SLEEP: 318 /* do a sleep function - what about pwb which has alarm? */ 319 sleep(args[0]); 320 break; 321 #endif 322 case GETUID: 323 args[0] = getuid(); 324 args[1] = geteuid(); 325 #ifdef V6UNIX 326 i = args[1]<<8 | args[0]; 327 #endif 328 break; 329 case GETGID: 330 args[0] = getgid(); 331 args[1] = getegid(); 332 #ifdef V6UNIX 333 i = args[1]<<8 | args[0]; 334 #endif 335 break; 336 #ifdef V6UNIX 337 case SETUID: 338 case SETGID: 339 /* uids and gids are 8 bits in version 6 */ 340 i = syscall(code,args[0]&0377); 341 break; 342 #endif 343 case SIG: 344 /* if it is a good signal code */ 345 if(args[0] <= NSIG) { 346 /* get the current signal value */ 347 i = sigvals[args[0]]; 348 /* reset the signal to the new value */ 349 sigvals[args[0]] = args[1]; 350 /* actually do signal except don't reset SIGILL */ 351 if(args[0] != SIGILL) { 352 if(args[1] == (int)SIG_DFL || args[1] & (int)SIG_IGN) { 353 if((int)signal(args[0],args[1]) == -1) 354 i = -1; 355 } else { 356 if((int)signal(args[0], sigcatch) == -1) 357 i = -1; 358 } 359 } 360 } 361 else i = -1; 362 break; 363 case BRK: 364 /* brk is successful unless we run over the stack */ 365 i = 0; 366 if(args[0] >= regs[6]) i = -1; 367 break; 368 #ifdef V6UNIX 369 case PWBSYS: 370 /* ignore pwbsys for now */ 371 switch(args[2]) { 372 case UNAME: 373 #ifdef TRACE 374 fprintf(stderr,"UNAME with %d %d\n",args[0],args[1]); 375 #endif 376 strcpy(args[0],"pwbname"); 377 i = 0; 378 break; 379 case UDATA: 380 #ifdef TRACE 381 fprintf(stderr,"UDATA with %d %d\n",args[0],args[1]); 382 #endif 383 i = 0; 384 break; 385 case USTAT: 386 fprintf(stderr,"USTAT with %d %d\n",args[0],args[1]); 387 i = 0; 388 break; 389 case UTIME: 390 fprintf(stderr,"UTIME with %d %d\n",args[0],args[1]); 391 i = 0; 392 break; 393 default: 394 fprintf(stderr,"bad PWBSYS %d\n",args[3]); 395 i = -1; 396 break; 397 } 398 break; 399 #endif 400 default: 401 /* 402 * Many sys calls are easily done here since most 403 * system call codes are the same on version 6 and 7 UNIX 404 * as they are here. 405 */ 406 i = syscall(code,args[0],args[1],args[2],args[3],args[4]); 407 #ifdef V6UNIX 408 /* allow read write access to created files for(IDIS v6 mod) */ 409 if(code==CREAT) { 410 /* get actual file mode after create */ 411 fstat(i, &stat32v); 412 close(i); 413 /* ensure read/write access to owner */ 414 chmod(args[0], 0644); 415 i = open(args[0], 2); 416 /* change mode back the way it was */ 417 chmod(args[0], stat32v.st_mode); 418 } 419 #endif 420 break; 421 } 422 #ifdef TRACE 423 fprintf(stderr," sys val -> 0%o\n",i); 424 #endif 425 /* set carry bit if sys error */ 426 if(i == -1) 427 psl |= CARRY; 428 /* if not an indirect sys call, adjust the pc */ 429 if(indirflg == 0) 430 pc = argp; 431 /* do alternate return on one side of fork */ 432 if(code == FORK && i != 0) 433 pc++; 434 /* do the various return value formats */ 435 switch(sysargs[code][2]) { 436 case NORMRET: 437 /* normal case only one return value in r0 */ 438 regs[0] = i; 439 break; 440 case LONGRET: 441 /* return a long in r0 - r1 as in time */ 442 regs[1] = i; 443 regs[0] = i >> 16; 444 break; 445 case TWORET: 446 /* return two ints in r0 - r1 as in pipe */ 447 if(i == -1) 448 regs[0] = i; 449 else { 450 regs[1] = args[1]; 451 regs[0] = args[0]; 452 } 453 break; 454 } 455 if(i== -1) 456 regs[0] = errno; 457 } 458 long longrev(l) long l; { 459 /* function to reverse the halves of a long */ 460 union { 461 long lng; 462 short s[2]; 463 } u; 464 register short t; 465 u.lng = l; 466 t = u.s[0]; 467 u.s[0] = u.s[1]; 468 u.s[1] = t; 469 return(u.lng); 470 } 471