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