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 */
dotrap(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
longrev(l)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 */
mapioctl(cmd)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 */
oread(fd,buf,count)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
olseek(fd,n,whence)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