1 #ifndef lint 2 static char sccsid[] = "@(#)unixtraps.c 4.3 84/05/05"; 3 #endif 4 5 /* From Lou Salkind: compat/RCS/unixtraps.c,v 1.2 84/01/31 13:34:34 */ 6 7 /* 8 * Function to execute version 6 and version 7 UNIX system calls from 9 * compatability mode on UNIX-32V. 10 * Art Wetzel August 1979 11 */ 12 13 #include <stdio.h> 14 #include <signal.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <sys/ioctl.h> 18 #include <sys/time.h> 19 #include <sys/dir.h> 20 #ifdef V6UNIX 21 #ifdef TRACE 22 #define RTSNAME "/../../../../usr/local/v6trc" 23 #else 24 #define RTSNAME "/../../../../usr/local/v6run" 25 #endif 26 #include "unix6sys.h" 27 #ifdef TRACE 28 #include "unix6sysn.h" 29 #endif 30 #endif 31 #ifdef V7UNIX 32 #ifdef TRACE 33 #define RTSNAME "/../../../../usr/local/v7trc" 34 #else 35 #define RTSNAME "/../../../../usr/local/v7run" 36 #endif 37 #include "unix7sys.h" 38 #ifdef TRACE 39 #include "unix7sysn.h" 40 #endif 41 #endif 42 #include "defs.h" 43 #define CARRY 1 44 #define MAXSARGS 100 45 #ifdef V6UNIX 46 #define ARGVLEN 512 47 #define ENVLEN 0 48 #endif 49 #ifdef V7UNIX 50 #define ARGVLEN 5120 51 #define ENVLEN 1000 52 #endif 53 char argvs[ARGVLEN+ENVLEN]; 54 int args[MAXSARGS]; 55 56 /* 32v type stat structure */ 57 extern struct stat stat32v; 58 59 /* place for times data so we can reverse the longs */ 60 struct timebuf { 61 long t1; 62 long t2; 63 long t3; 64 long t4; 65 } timebuf; 66 67 /* place for pipe file descriptors */ 68 int pipes[2]; 69 70 /* wait status */ 71 int wstatus; 72 73 #ifdef V6UNIX 74 /* version 6 style stat structure */ 75 struct v6nod { 76 dev_t majmin; 77 ino_t inumber; 78 unsigned short flags; 79 unsigned char nlinks; 80 unsigned char uid; 81 unsigned char gid; 82 unsigned char size0; 83 unsigned short size1; 84 unsigned short addr[8]; 85 long actime; 86 long modtime; 87 } *v6stat; 88 #endif 89 90 #ifdef V7UNIX 91 /* version 7 style stat structure */ 92 struct v7stat { 93 dev_t v7st_dev; 94 u_short v7st_ino; 95 u_short v7st_mode; 96 short v7st_nlink; 97 short v7st_uid; 98 short v7st_gid; 99 dev_t v7st_rdev; 100 int v7st_size; 101 int v7st_atime; 102 int v7st_mtime; 103 int v7st_ctime; 104 } statv7; 105 106 struct timeb { 107 time_t time; 108 u_short millitm; 109 short timezone; 110 short dstflag; 111 } timeb; 112 #endif 113 114 #define NFILES 20 115 #define ODSIZE 16 116 117 off_t olseek(); 118 119 struct odirect { 120 u_short od_ino; 121 char od_name[14]; 122 }; 123 124 struct fdflags { 125 DIR *fd_dirp; 126 struct odirect fd_od; 127 off_t fd_offset; 128 } fdflags[NFILES]; 129 130 /* do the trap stuff for the trap with code */ 131 dotrap(code) 132 int code; 133 { 134 register unsigned short *argp, *savp, *savep; 135 register int i, j, indirflg; 136 register char *avp, *oavp; 137 extern sigcatch(); 138 extern errno; 139 extern int sigtrapped; 140 DIR *dp; 141 142 sigtrapped = 0; 143 /* clear out condition codes of psl */ 144 psl &= ~017; 145 /* special case of indirect sys call */ 146 if (code == 0) { 147 /* remember this was indirect */ 148 indirflg = 1; 149 /* point to args */ 150 argp = (unsigned short *)*(pc++); 151 /* code for indirect sys call */ 152 code = *argp++; 153 /* is it legit */ 154 if (code>>8 != TRAPS) { 155 fprintf(stderr,"Bad indirect sys call at 0x%x\n",pc-2); 156 pc++; 157 /* set carry flag */ 158 psl |= CARRY; 159 regs[0] = -1; 160 return(-1); 161 } 162 code &= 0377; 163 } else { 164 /* remember this was not indirect */ 165 indirflg = 0; 166 /* point to args */ 167 argp = pc; 168 } 169 /* check if code too high or bad sys code */ 170 if (code >= NSYSTRAPS || sysargs[code][0] == ILLSYS) { 171 fprintf(stderr,"Unimplimented trap %d at 0x%x\n",code,argp); 172 /* set carry bit */ 173 psl |= CARRY; 174 regs[0] = -1; 175 return(-1); 176 } 177 /* copy args to known locations */ 178 i=0; 179 for (j=0; j<sysargs[code][0]; j++) 180 args[i++] = regs[j]; 181 for (j=0; j<(sysargs[code][1]); j++) 182 args[i++] = *argp++; 183 #ifdef TRACE 184 fprintf(stderr,"pid %d ",getpid()); 185 if (indirflg) 186 fprintf(stderr,"indirect "); 187 fprintf(stderr, "%s (%d) from 0%o with %d args", 188 sysnames[code], code, pc-1, i); 189 for (j=0; j<i; j++) 190 fprintf(stderr," 0%o",args[j]); 191 if (code==OPEN || code==STAT || code==CREAT || code==EXEC || 192 code==UNLNK || code==LINK || code==CHDIR || code==MKNOD) 193 fprintf(stderr," (%s)",args[0]); 194 #ifdef V7UNIX 195 if (code==EXECE) 196 fprintf(stderr," (%s)",args[0]); 197 #endif 198 if (code==LINK) 199 fprintf(stderr," (%s)",args[1]); 200 #endif 201 /* go do whatever sys call it is */ 202 switch (code) { 203 case FORK: 204 /* indirect forks return pids on both sides - must do here */ 205 /* this is possibly a bug in 32V */ 206 i = fork(); 207 break; 208 209 case WAIT: 210 i = wait(&wstatus); 211 args[0] = i; 212 args[1] = wstatus; 213 break; 214 215 case EXEC: 216 #ifdef V7UNIX 217 case EXECE: 218 #endif 219 /* 220 * have to do a lot of junk here to fix up an argv 221 * for execute since (1) the pdp-11 argv consists of 16 222 * bit pointers and (2) the argv itself is in the 223 * pdp-11 program space where it would get clobbered 224 * when a new program is read in and before its 225 * argv is set up. 226 */ 227 avp = &argvs[0]; 228 savp = (unsigned short *)args[1]; 229 #ifdef V6UNIX 230 for (i=1; args[i] = *savp++; i++) 231 if (args[i] == 0177777) 232 break; 233 #ifdef TRACE 234 else 235 fprintf(stderr,"argv[%d]%s ",i-1,args[i]); 236 #endif 237 #endif 238 #ifdef V7UNIX 239 savep = (unsigned short *)args[2]; 240 for (i=1; args[i] = *savp++; i++) 241 #ifdef TRACE 242 fprintf(stderr,"argv[%d]%s ",i-1,args[i]); 243 #else 244 ; 245 #endif 246 #endif 247 if (stat(args[0], &stat32v)) { 248 /* return error here if file does not exist */ 249 #ifdef TRACE 250 fprintf(stderr," does not exist\n"); 251 #endif 252 i = -1; 253 break; 254 } 255 /* must have execute permission */ 256 if (stat32v.st_mode & (S_IEXEC>>6)) 257 goto experm; 258 if (stat32v.st_mode & (S_IEXEC>>3)) { 259 if (stat32v.st_gid == getegid()) 260 goto experm; 261 if (geteuid() == 0) 262 goto experm; 263 } 264 if (stat32v.st_mode & S_IEXEC) { 265 if (stat32v.st_uid == geteuid()) 266 goto experm; 267 if (geteuid() == 0) 268 goto experm; 269 } 270 /* return failure if no exec permision allowed */ 271 i = -1; 272 experm: 273 /* can't exec a directory */ 274 if ((stat32v.st_mode&S_IFMT) == S_IFDIR) 275 i = -1; 276 if (i == -1) 277 break; 278 args[i] = 0; 279 for (j=1; j<i; j++) { 280 oavp = (char *)args[j]; 281 args[j] = (int)avp; 282 while (*avp++ = *oavp++) 283 ; 284 } 285 #ifdef V7UNIX 286 if (code == EXECE) { 287 for (j = ++i; args[j] = *savep++; j++) 288 ; 289 for (j = i; oavp = (char *)args[j]; j++) { 290 args[j] = (int)avp; 291 while (*avp++ = *oavp++) 292 ; 293 } 294 } 295 #endif 296 /* SETUID and SETGID files must be started with a fresh RTS */ 297 if (stat32v.st_mode & S_ISGID || stat32v.st_mode & S_ISUID) { 298 /* should add a check here for good magic # in header */ 299 args[1] = args[0]; 300 args[0] = (int)RTSNAME; 301 #ifdef TRACE 302 fprintf(stderr," SETUID-GID"); 303 #endif 304 if (args[i]) 305 i = execve(args[0], &args[0], &args[i]); 306 else 307 i = execv(args[0], &args[0]); 308 fprintf(stderr,"can't exec %s\n",RTSNAME); 309 break; 310 } 311 i = execute(args[0], &args[1], &args[i]); 312 /* shouldn't get here if exec works */ 313 break; 314 315 case SEEK: 316 #ifdef V6UNIX 317 /* fix up negative offsets */ 318 if (args[2] != 0 && args[2] != 3) 319 if (args[1] >= 32768) 320 args[1] -= 65536; 321 if (args[2] <= 2) 322 i = olseek(args[0], args[1], args[2]); 323 else 324 i = olseek(args[0], args[1]*512, args[2]-3); 325 if (i != -1) 326 i = 0; 327 #endif 328 #ifdef V7UNIX 329 i = olseek(args[0], (args[1]<<16)|(args[2]&0177777), args[3]); 330 #endif 331 break; 332 333 case MKNOD: 334 if ((args[1] & S_IFMT) == S_IFDIR) 335 i = mkdir(args[0], args[1] & 0777); 336 else { 337 #ifdef V6UNIX 338 /* 339 * version 6 uses allocated bit which 340 * means regular file here 341 */ 342 if (args[1] & S_IFBLK) 343 args[1] &= ~S_IFREG; 344 #endif 345 i = mknod(args[0], args[1], args[2]); 346 } 347 break; 348 349 case PIPE: 350 i = pipe(pipes); 351 args[0] = pipes[0]; 352 args[1] = pipes[1]; 353 break; 354 355 #ifdef V6UNIX 356 case TELL: 357 i = lseek(args[0], 0L, 1); 358 break; 359 360 case STTY: 361 i = stty(args[0], args[1]); 362 break; 363 364 case GTTY: 365 i = gtty(args[0], args[1]); 366 break; 367 #endif 368 369 /* HAVE TO FAKE THE SIZE OF DIRECTORIES */ 370 371 case STAT: 372 i = stat(args[0], &stat32v); 373 goto allstat; 374 375 case FSTAT: 376 /* do the syscall to a local stat buffer */ 377 i = fstat(args[0], &stat32v); 378 379 allstat: 380 /* reverse the longs */ 381 stat32v.st_size = longrev(stat32v.st_size); 382 stat32v.st_atime = longrev(stat32v.st_atime); 383 stat32v.st_mtime = longrev(stat32v.st_mtime); 384 stat32v.st_ctime = longrev(stat32v.st_ctime); 385 #ifdef V7UNIX 386 statv7.v7st_dev = stat32v.st_dev; 387 statv7.v7st_ino = stat32v.st_ino; 388 statv7.v7st_mode = stat32v.st_mode; 389 statv7.v7st_nlink = stat32v.st_nlink; 390 statv7.v7st_uid = stat32v.st_uid; 391 statv7.v7st_gid = stat32v.st_gid; 392 statv7.v7st_rdev = stat32v.st_rdev; 393 statv7.v7st_size = stat32v.st_size; 394 statv7.v7st_atime = stat32v.st_atime; 395 statv7.v7st_mtime = stat32v.st_mtime; 396 statv7.v7st_ctime = stat32v.st_ctime; 397 /* copy out otherwise unchanged stat buffer */ 398 /* in two pieces with st_size as the breaking point */ 399 /* note that st_rdev is a short but due to alingnmemt */ 400 /* problems the rest of the structure is out of sync */ 401 j = (int)((char *)(&statv7.v7st_size) - 402 (char *)(&statv7.v7st_dev)); 403 bcopy(&statv7, args[1], j); 404 bcopy(&statv7.v7st_size, args[1]+j-2, sizeof(struct v7stat)-j); 405 #endif 406 #ifdef V6UNIX 407 /* point to user area as v6stat structure */ 408 v6stat = (struct v6nod *)args[1]; 409 /* copy out piece by piece */ 410 v6stat->majmin = stat32v.st_dev; 411 v6stat->inumber = stat32v.st_ino; 412 v6stat->flags = stat32v.st_mode; 413 v6stat->nlinks = (unsigned char)stat32v.st_nlink; 414 v6stat->uid = (unsigned char)stat32v.st_uid; 415 v6stat->gid = (unsigned char)stat32v.st_gid; 416 /* note size already reversed */ 417 v6stat->size0 = (unsigned char)(stat32v.st_size & 0377); 418 v6stat->size1 = (unsigned short)(stat32v.st_size>>16); 419 v6stat->actime = stat32v.st_atime; 420 v6stat->modtime = stat32v.st_mtime; 421 /* patch up flags */ 422 /* for now just set 100000 bit if not a plain file */ 423 if (v6stat->flags & 060000) 424 v6stat->flags |= 0100000; 425 #endif 426 break; 427 428 case TIMES: 429 i = times(&timebuf); 430 timebuf.t2 = longrev(timebuf.t2) + timebuf.t1; 431 timebuf.t3 = longrev(timebuf.t3); 432 timebuf.t4 = longrev(timebuf.t4); 433 bcopy(&timebuf.t2,args[0],sizeof(struct timebuf)-sizeof(long)); 434 break; 435 436 #ifdef V6UNIX 437 case SLEEP: 438 /* do a sleep function - what about pwb which has alarm? */ 439 sleep(args[0]); 440 break; 441 #endif 442 443 case GETUID: 444 args[0] = getuid(); 445 args[1] = geteuid(); 446 #ifdef V6UNIX 447 i = args[1]<<8 | (args[0] & 0377); 448 #endif 449 break; 450 451 case GETGID: 452 args[0] = getgid(); 453 args[1] = getegid(); 454 #ifdef V6UNIX 455 i = args[1]<<8 | (args[0] & 0377); 456 #endif 457 break; 458 459 /* uids and gids are 8 bits in version 6 */ 460 case SETUID: 461 case SETGID: 462 #ifdef V6UNIX 463 args[0] &= 0377; 464 #endif 465 if (code == SETUID) 466 i = setuid(args[0]); 467 else 468 i = setgid(args[0]); 469 break; 470 471 case SIG: 472 /* if it is a good signal code */ 473 if (args[0] <= NSIG) { 474 /* get the current signal value */ 475 i = sigvals[args[0]]; 476 /* reset the signal to the new value */ 477 sigvals[args[0]] = args[1]; 478 /* actually do signal except don't reset SIGILL */ 479 if (args[0] != SIGILL) { 480 if (args[1] == (int)SIG_DFL || 481 args[1] & (int)SIG_IGN) { 482 if ((int)signal(args[0],args[1]) == -1) 483 i = -1; 484 } else { 485 if ((int)signal(args[0],sigcatch) == -1) 486 i = -1; 487 } 488 } 489 } else 490 i = -1; 491 break; 492 493 case BRK: 494 /* brk is successful unless we run over the stack */ 495 /* NB: this assumes register usage which need not be used */ 496 i = 0; 497 if (args[0] >= regs[6]) 498 i = -1; 499 break; 500 501 /* 502 * the next bunch are to cope with sys calls removed from 4.2 503 */ 504 case TIME: 505 i = time(0); 506 break; 507 508 case STIME: { 509 struct timeval tv; 510 511 tv.tv_usec = 0; 512 tv.tv_sec = (args[0] & 0xffff) | ((args[1] & 0xffff) << 16); 513 i = settimeofday(&tv); 514 break; 515 } 516 517 case NICE: 518 i = nice(args[0]); 519 break; 520 521 #ifdef V7UNIX 522 case ALARM: 523 i = alarm(args[0]); 524 break; 525 526 case PAUSE: 527 i = pause(); 528 break; 529 530 case UTIME: 531 i = utime(args[0], args[1]); 532 break; 533 534 case FTIME: 535 i = ftime(&timeb); 536 timeb.time = longrev(timeb.time); 537 bcopy(&timeb, args[0], sizeof timeb - 2); 538 break; 539 540 case IOCTL: 541 args[1] = mapioctl(args[1]); 542 if (args[1] == 0) 543 i = -1; 544 else 545 i = ioctl(args[0], args[1], args[2]); 546 break; 547 #endif 548 549 #ifdef V6UNIX 550 case PWBSYS: 551 /* ignore pwbsys for now */ 552 switch (args[2]) { 553 case UNAME: 554 #ifdef TRACE 555 fprintf(stderr,"UNAME with %d %d\n",args[0],args[1]); 556 #endif 557 strcpy(args[0],"pwbname"); 558 i = 0; 559 break; 560 561 case UDATA: 562 #ifdef TRACE 563 fprintf(stderr,"UDATA with %d %d\n",args[0],args[1]); 564 #endif 565 i = 0; 566 break; 567 568 case USTAT: 569 fprintf(stderr,"USTAT with %d %d\n",args[0],args[1]); 570 i = 0; 571 break; 572 573 case UTIME: 574 fprintf(stderr,"UTIME with %d %d\n",args[0],args[1]); 575 i = 0; 576 break; 577 default: 578 fprintf(stderr,"bad PWBSYS %d\n",args[3]); 579 i = -1; 580 break; 581 } 582 break; 583 #endif 584 585 default: 586 /* 587 * Many sys calls are easily done here since most 588 * system call codes are the same on version 6 and 7 UNIX 589 * as they are here. 590 */ 591 i = syscall(code,args[0],args[1],args[2],args[3],args[4]); 592 #ifdef V6UNIX 593 /* allow read write access to created files for (IDIS v6 mod) */ 594 if (code==CREAT) { 595 /* get actual file mode after create */ 596 fstat(i, &stat32v); 597 close(i); 598 /* ensure read/write access to owner */ 599 chmod(args[0], 0644); 600 i = open(args[0], 2); 601 /* change mode back the way it was */ 602 chmod(args[0], stat32v.st_mode); 603 } 604 #endif 605 break; 606 case OPEN: 607 /* 608 * check if we are opening a directory 609 */ 610 if (stat(args[0], &stat32v) >= 0 && 611 ((stat32v.st_mode & S_IFMT) == S_IFDIR) && 612 ((dp = opendir(args[0])) != NULL)) { 613 #ifdef DTRACE 614 fprintf(stderr,"open directory fd %d\n", i); 615 #endif 616 i = dp->dd_fd; 617 fdflags[i].fd_dirp = dp; 618 fdflags[i].fd_offset = 0; 619 } else 620 i = open(args[0], args[1]); 621 break; 622 case CLOSE: 623 i = close(args[0]); 624 if (i >= 0 && fdflags[args[0]].fd_dirp) { 625 closedir(fdflags[args[0]].fd_dirp); 626 fdflags[args[0]].fd_dirp = 0; 627 } 628 break; 629 case READ: 630 if ((unsigned)args[0] < NFILES && fdflags[args[0]].fd_dirp) 631 i = oread(args[0], args[1], args[2]); 632 else 633 i = read(args[0], args[1], args[2]); 634 break; 635 } 636 #ifdef TRACE 637 fprintf(stderr," sys val -> 0%o\n",i); 638 #endif 639 /* set carry bit if sys error */ 640 if (i == -1) 641 psl |= CARRY; 642 /* if not an indirect sys call, adjust the pc */ 643 if (!indirflg && !sigtrapped) 644 pc = argp; 645 /* do alternate return on one side of fork */ 646 if (code == FORK && i != 0) 647 pc++; 648 /* do the various return value formats */ 649 switch (sysargs[code][2]) { 650 case NORMRET: 651 /* normal case only one return value in r0 */ 652 regs[0] = i; 653 break; 654 case LONGRET: 655 /* return a long in r0 - r1 as in time */ 656 regs[1] = i; 657 regs[0] = i >> 16; 658 break; 659 case TWORET: 660 /* return two ints in r0 - r1 as in pipe */ 661 if (i == -1) 662 regs[0] = i; 663 else { 664 regs[1] = args[1]; 665 regs[0] = args[0]; 666 } 667 break; 668 } 669 if (i== -1) 670 regs[0] = errno; 671 } 672 673 long 674 longrev(l) 675 long l; 676 { 677 /* function to reverse the halves of a long */ 678 union { 679 long lng; 680 short s[2]; 681 } u; 682 register short t; 683 u.lng = l; 684 t = u.s[0]; 685 u.s[0] = u.s[1]; 686 u.s[1] = t; 687 return(u.lng); 688 } 689 690 /* 691 * Note: these tables are sorted by 692 * ioctl "code" (in ascending order). 693 */ 694 int fctls[] = { FIOCLEX, FIONCLEX, FIOASYNC, FIONBIO, FIONREAD, 0 }; 695 int tctls[] = { 696 TIOCGETD, TIOCSETD, TIOCHPCL, TIOCMODG, TIOCMODS, 697 TIOCGETP, TIOCSETP, TIOCSETN, TIOCEXCL, TIOCNXCL, 698 TIOCFLUSH,TIOCSETC, TIOCGETC, TIOCREMOTE,TIOCMGET, 699 TIOCMBIC, TIOCMBIS, TIOCMSET, TIOCSTART,TIOCSTOP, 700 TIOCPKT, TIOCNOTTY,TIOCSTI, TIOCOUTQ, TIOCGLTC, 701 TIOCSLTC, TIOCSPGRP,TIOCGPGRP,TIOCCDTR, TIOCSDTR, 702 TIOCCBRK, TIOCSBRK, TIOCLGET, TIOCLSET, TIOCLBIC, 703 TIOCLBIS, 0 704 }; 705 706 /* 707 * Map an old style ioctl command to new. 708 */ 709 mapioctl(cmd) 710 int cmd; 711 { 712 register int *map, c; 713 714 switch ((cmd >> 8) & 0xff) { 715 716 case 'f': 717 map = fctls; 718 break; 719 720 case 't': 721 map = tctls; 722 break; 723 724 default: 725 return (0); 726 } 727 while ((c = *map) && (c&0xff) < (cmd&0xff)) 728 map++; 729 if (c && (c&0xff) == (cmd&0xff)) 730 return (c); 731 return (0); 732 } 733 734 /* 735 * emulate a read of n bytes on an old style directory 736 */ 737 oread(fd, buf, count) 738 int fd, count; 739 char *buf; 740 { 741 struct fdflags *fp; 742 struct direct *dp; 743 DIR *dirp; 744 struct odirect *odp; 745 register int nleft = count; 746 int dir_off; 747 int i; 748 749 fp = &fdflags[fd]; 750 dirp = fp->fd_dirp; 751 odp = &fp->fd_od; 752 if (dirp == NULL) 753 return(-1); 754 dir_off = fp->fd_offset % ODSIZE; 755 if (dir_off) { 756 i = ODSIZE - dir_off; 757 if (nleft < i) 758 i = nleft; 759 bcopy((caddr_t)odp + dir_off, buf, i); 760 fp->fd_offset += i; 761 if (i == nleft) 762 return(i); 763 buf += i; 764 nleft -= i; 765 } 766 while (nleft >= ODSIZE) { 767 if ((dp = readdir(dirp)) == NULL) 768 return(count - nleft); 769 odp->od_ino = dp->d_ino; 770 strncpy(odp->od_name, dp->d_name, 14); 771 bcopy((caddr_t)odp, buf, ODSIZE); 772 fp->fd_offset += ODSIZE; 773 buf += ODSIZE; 774 nleft -= ODSIZE; 775 } 776 if (nleft > 0) { 777 if ((dp = readdir(dirp)) == NULL) 778 return(count - nleft); 779 odp->od_ino = dp->d_ino; 780 strncpy(odp->od_name, dp->d_name, 14); 781 bcopy((caddr_t)odp, buf, nleft); 782 fp->fd_offset += nleft; 783 /* nleft = 0; */ 784 } 785 return(count); 786 } 787 788 /* 789 * emulate the lseek system call 790 */ 791 off_t 792 olseek(fd, n, whence) 793 int fd, whence; 794 off_t n; 795 { 796 struct fdflags *fp; 797 char buf[512]; 798 off_t newpos; 799 int i, j; 800 801 if ((unsigned)fd >= NFILES) 802 return(-1); 803 fp = &fdflags[fd]; 804 /* 805 * the system can handle everything 806 * except directory files 807 */ 808 if (fp->fd_dirp == NULL) 809 return(lseek(fd, n, whence)); 810 switch (whence) { 811 case 0: 812 newpos = n; 813 break; 814 case 1: 815 newpos = fp->fd_offset + n; 816 break; 817 case 2: /* not yet implemented */ 818 default: 819 return(-1); 820 } 821 if (newpos < 0) 822 return(-1); 823 if (newpos < fp->fd_offset) { 824 rewinddir(fdflags[fd].fd_dirp); 825 fp->fd_offset = 0; 826 } 827 i = newpos - fp->fd_offset; 828 while (i > 0) { 829 j = i < 512 ? i : 512; 830 if (oread(fd, buf, j) != j) 831 break; 832 i -= j; 833 } 834 return(fp->fd_offset); 835 } 836