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