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