xref: /csrg-svn/sys/kern/kern_descrip.c (revision 46765)
1 /*
2  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_descrip.c	7.20 (Berkeley) 02/28/91
8  */
9 
10 #include "param.h"
11 #include "systm.h"
12 #include "user.h"
13 #include "filedesc.h"
14 #include "kernel.h"
15 #include "vnode.h"
16 #include "proc.h"
17 #include "file.h"
18 #include "socket.h"
19 #include "socketvar.h"
20 #include "stat.h"
21 #include "ioctl.h"
22 #include "fcntl.h"
23 #include "malloc.h"
24 #include "syslog.h"
25 
26 /*
27  * Descriptor management.
28  */
29 int nofile = NOFILE;		/* per-process maximum open files */
30 
31 /*
32  * System calls on descriptors.
33  */
34 /* ARGSUSED */
35 getdtablesize(p, uap, retval)
36 	struct proc *p;
37 	struct args *uap;
38 	int *retval;
39 {
40 
41 	*retval = nofile;
42 	return (0);
43 }
44 
45 /*
46  * Duplicate a file descriptor.
47  */
48 /* ARGSUSED */
49 dup(p, uap, retval)
50 	struct proc *p;
51 	struct args {
52 		int	i;
53 	} *uap;
54 	int *retval;
55 {
56 	register struct filedesc *fdp = p->p_fd;
57 	struct file *fp;
58 	int fd, error;
59 
60 	/*
61 	 * XXX Compatibility
62 	 */
63 	if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
64 
65 	if ((unsigned)uap->i >= fdp->fd_maxfiles ||
66 	    (fp = OFILE(fdp, uap->i)) == NULL)
67 		return (EBADF);
68 	if (error = ufalloc(fdp, 0, &fd))
69 		return (error);
70 	OFILE(fdp, fd) = fp;
71 	OFILEFLAGS(fdp, fd) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE;
72 	fp->f_count++;
73 	if (fd > fdp->fd_lastfile)
74 		fdp->fd_lastfile = fd;
75 	*retval = fd;
76 	return (0);
77 }
78 
79 /*
80  * Duplicate a file descriptor to a particular value.
81  */
82 /* ARGSUSED */
83 dup2(p, uap, retval)
84 	struct proc *p;
85 	register struct args {
86 		int	i;
87 		int	j;
88 	} *uap;
89 	int *retval;
90 {
91 	register struct filedesc *fdp = p->p_fd;
92 	register struct file *fp;
93 	int i, error;
94 
95 	if ((unsigned)uap->i >= fdp->fd_maxfiles ||
96 	    (fp = OFILE(fdp, uap->i)) == NULL ||
97 	    (unsigned)uap->j >= nofile)
98 		return (EBADF);
99 	*retval = uap->j;
100 	if (uap->i == uap->j)
101 		return (0);
102 	if ((unsigned)uap->j >= fdp->fd_maxfiles) {
103 		if (error = ufalloc(fdp, uap->j, &i))
104 			return (error);
105 		if (uap->j != i)
106 			panic("dup2: ufalloc");
107 	} else if (OFILE(fdp, uap->j)) {
108 		if (OFILEFLAGS(fdp, uap->j) & UF_MAPPED)
109 			(void) munmapfd(p, uap->j);
110 		error = closef(OFILE(fdp, uap->j));
111 	}
112 	OFILE(fdp, uap->j) = fp;
113 	OFILEFLAGS(fdp, uap->j) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE;
114 	fp->f_count++;
115 	if (uap->j > fdp->fd_lastfile)
116 		fdp->fd_lastfile = uap->j;
117 	/*
118 	 * dup2() must succeed even though the close had an error.
119 	 */
120 	error = 0;		/* XXX */
121 	return (error);
122 }
123 
124 /*
125  * The file control system call.
126  */
127 /* ARGSUSED */
128 fcntl(p, uap, retval)
129 	struct proc *p;
130 	register struct args {
131 		int	fdes;
132 		int	cmd;
133 		int	arg;
134 	} *uap;
135 	int *retval;
136 {
137 	register struct filedesc *fdp = p->p_fd;
138 	register struct file *fp;
139 	register char *pop;
140 	struct vnode *vp;
141 	int i, error, flags = F_POSIX;
142 	struct flock fl;
143 
144 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
145 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
146 		return (EBADF);
147 	pop = &OFILEFLAGS(fdp, uap->fdes);
148 	switch(uap->cmd) {
149 	case F_DUPFD:
150 		if ((unsigned)uap->arg >= nofile)
151 			return (EINVAL);
152 		if (error = ufalloc(fdp, uap->arg, &i))
153 			return (error);
154 		OFILE(fdp, i) = fp;
155 		OFILEFLAGS(fdp, i) = *pop &~ UF_EXCLOSE;
156 		fp->f_count++;
157 		if (i > fdp->fd_lastfile)
158 			fdp->fd_lastfile = i;
159 		*retval = i;
160 		return (0);
161 
162 	case F_GETFD:
163 		*retval = *pop & 1;
164 		return (0);
165 
166 	case F_SETFD:
167 		*pop = (*pop &~ 1) | (uap->arg & 1);
168 		return (0);
169 
170 	case F_GETFL:
171 		*retval = OFLAGS(fp->f_flag);
172 		return (0);
173 
174 	case F_SETFL:
175 		fp->f_flag &= ~FCNTLFLAGS;
176 		fp->f_flag |= FFLAGS(uap->arg) & FCNTLFLAGS;
177 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
178 			return (error);
179 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
180 			(void) fset(fp, FNDELAY, 0);
181 		return (error);
182 
183 	case F_GETOWN:
184 		return (fgetown(fp, retval));
185 
186 	case F_SETOWN:
187 		return (fsetown(fp, uap->arg));
188 
189 	case F_SETLKW:
190 		flags |= F_WAIT;
191 		/* Fall into F_SETLK */
192 
193 	case F_SETLK:
194 		if (fp->f_type != DTYPE_VNODE)
195 			return (EBADF);
196 		vp = (struct vnode *)fp->f_data;
197 		/* Copy in the lock structure */
198 		error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
199 		if (error)
200 			return (error);
201 		if (fl.l_whence == SEEK_CUR)
202 			fl.l_start += fp->f_offset;
203 		switch (fl.l_type) {
204 
205 		case F_RDLCK:
206 			if ((fp->f_flag & FREAD) == 0)
207 				return (EBADF);
208 			return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags));
209 
210 		case F_WRLCK:
211 			if ((fp->f_flag & FWRITE) == 0)
212 				return (EBADF);
213 			return (VOP_ADVLOCK(vp, p, F_SETLK, &fl, flags));
214 
215 		case F_UNLCK:
216 			return (VOP_ADVLOCK(vp, p, F_UNLCK, &fl, F_POSIX));
217 
218 		default:
219 			return (EINVAL);
220 		}
221 
222 	case F_GETLK:
223 		if (fp->f_type != DTYPE_VNODE)
224 			return (EBADF);
225 		vp = (struct vnode *)fp->f_data;
226 		/* Copy in the lock structure */
227 		error = copyin((caddr_t)uap->arg, (caddr_t)&fl, sizeof (fl));
228 		if (error)
229 			return (error);
230 		if (fl.l_whence == SEEK_CUR)
231 			fl.l_start += fp->f_offset;
232 		if (error = VOP_ADVLOCK(vp, p, F_GETLK, &fl, F_POSIX))
233 			return (error);
234 		return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
235 
236 	default:
237 		return (EINVAL);
238 	}
239 	/* NOTREACHED */
240 }
241 
242 fset(fp, bit, value)
243 	struct file *fp;
244 	int bit, value;
245 {
246 
247 	if (value)
248 		fp->f_flag |= bit;
249 	else
250 		fp->f_flag &= ~bit;
251 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
252 	    (caddr_t)&value));
253 }
254 
255 fgetown(fp, valuep)
256 	struct file *fp;
257 	int *valuep;
258 {
259 	int error;
260 
261 	switch (fp->f_type) {
262 
263 	case DTYPE_SOCKET:
264 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
265 		return (0);
266 
267 	default:
268 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
269 		*valuep = -*valuep;
270 		return (error);
271 	}
272 }
273 
274 fsetown(fp, value)
275 	struct file *fp;
276 	int value;
277 {
278 
279 	if (fp->f_type == DTYPE_SOCKET) {
280 		((struct socket *)fp->f_data)->so_pgid = value;
281 		return (0);
282 	}
283 	if (value > 0) {
284 		struct proc *p = pfind(value);
285 		if (p == 0)
286 			return (ESRCH);
287 		value = p->p_pgrp->pg_id;
288 	} else
289 		value = -value;
290 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
291 }
292 
293 fioctl(fp, cmd, value)
294 	struct file *fp;
295 	int cmd;
296 	caddr_t value;
297 {
298 
299 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
300 }
301 
302 /*
303  * Close a file descriptor.
304  */
305 /* ARGSUSED */
306 close(p, uap, retval)
307 	struct proc *p;
308 	struct args {
309 		int	fdes;
310 	} *uap;
311 	int *retval;
312 {
313 	register struct filedesc *fdp = p->p_fd;
314 	register struct file *fp;
315 	register u_char *pf;
316 
317 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
318 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
319 		return (EBADF);
320 	pf = (u_char *)&OFILEFLAGS(fdp, uap->fdes);
321 	if (*pf & UF_MAPPED)
322 		(void) munmapfd(p, uap->fdes);
323 	OFILE(fdp, uap->fdes) = NULL;
324 	while (fdp->fd_lastfile >= 0 && OFILE(fdp, fdp->fd_lastfile) == NULL)
325 		fdp->fd_lastfile--;
326 	*pf = 0;
327 	return (closef(fp));
328 }
329 
330 /*
331  * Return status information about a file descriptor.
332  */
333 /* ARGSUSED */
334 fstat(p, uap, retval)
335 	struct proc *p;
336 	register struct args {
337 		int	fdes;
338 		struct	stat *sb;
339 	} *uap;
340 	int *retval;
341 {
342 	register struct filedesc *fdp = p->p_fd;
343 	register struct file *fp;
344 	struct stat ub;
345 	int error;
346 
347 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
348 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
349 		return (EBADF);
350 	switch (fp->f_type) {
351 
352 	case DTYPE_VNODE:
353 		error = vn_stat((struct vnode *)fp->f_data, &ub);
354 		break;
355 
356 	case DTYPE_SOCKET:
357 		error = soo_stat((struct socket *)fp->f_data, &ub);
358 		break;
359 
360 	default:
361 		panic("fstat");
362 		/*NOTREACHED*/
363 	}
364 	if (error == 0)
365 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
366 	return (error);
367 }
368 
369 /*
370  * Allocate a user file descriptor.
371  */
372 int fdexpand, fdreexpand;
373 
374 ufalloc(fdp, want, result)
375 	register struct filedesc *fdp;
376 	register int want;
377 	int *result;
378 {
379 	int last, osize, ofiles, nfiles;
380 	struct file **newofile;
381 	char *newofileflags;
382 
383 	for (;;) {
384 		last = (fdp->fd_maxfiles < nofile) ? fdp->fd_maxfiles : nofile;
385 		for (; want < last; want++) {
386 			if (OFILE(fdp, want) == NULL) {
387 				OFILEFLAGS(fdp, want) = 0;
388 				if (want > fdp->fd_lastfile)
389 					fdp->fd_lastfile = want;
390 				*result = want;
391 				return (0);
392 			}
393 		}
394 		if (fdp->fd_maxfiles >= nofile)
395 			return (EMFILE);
396 		if (fdp->fd_maxfiles == NDFILE) {
397 			fdp->fd_moreofiles = (struct file **)
398 			    malloc(NDEXTENT * OFILESIZE, M_FILE, M_WAITOK);
399 			fdp->fd_moreofileflags =
400 			    (char *)&fdp->fd_moreofiles[NDEXTENT];
401 			bzero((char *)fdp->fd_moreofiles, NDEXTENT * OFILESIZE);
402 			fdp->fd_maxfiles = NDFILE + NDEXTENT;
403 			fdexpand++;
404 			continue;
405 		}
406 		ofiles = fdp->fd_maxfiles - NDFILE;
407 		osize = ofiles * OFILESIZE;
408 		nfiles = (2 * osize) / OFILESIZE;
409 		newofile = (struct file **) malloc(2 * osize, M_FILE, M_WAITOK);
410 		newofileflags = (char *)&newofile[nfiles];
411 		bzero((char *)newofile, 2 * osize);
412 		bcopy((char *)fdp->fd_moreofiles, (char *)newofile,
413 			sizeof(struct file *) * ofiles);
414 		bcopy((char *)fdp->fd_moreofileflags, (char *)newofileflags,
415 			sizeof(char) * ofiles);
416 		free(fdp->fd_moreofiles, M_FILE);
417 		fdp->fd_moreofiles = newofile;
418 		fdp->fd_moreofileflags = newofileflags;
419 		fdp->fd_maxfiles = NDFILE + nfiles;
420 		fdreexpand++;
421 	}
422 }
423 
424 /*
425  * Check to see if any user file descriptors are available.
426  */
427 ufavail(fdp)
428 	register struct filedesc *fdp;
429 {
430 	register int i, avail;
431 
432 	avail = nofile - fdp->fd_maxfiles;
433 	for (i = 0; i < fdp->fd_maxfiles; i++)
434 		if (OFILE(fdp, i) == NULL)
435 			avail++;
436 	return (avail);
437 }
438 
439 struct	file *lastf;
440 /*
441  * Allocate a user file descriptor
442  * and a file structure.
443  * Initialize the descriptor
444  * to point at the file structure.
445  */
446 falloc(p, resultfp, resultfd)
447 	register struct proc *p;
448 	struct file **resultfp;
449 	int *resultfd;
450 {
451 	register struct file *fp;
452 	int error, i;
453 
454 	if (error = ufalloc(p->p_fd, 0, &i))
455 		return (error);
456 	if (lastf == 0)
457 		lastf = file;
458 	for (fp = lastf; fp < fileNFILE; fp++)
459 		if (fp->f_count == 0)
460 			goto slot;
461 	for (fp = file; fp < lastf; fp++)
462 		if (fp->f_count == 0)
463 			goto slot;
464 	tablefull("file");
465 	return (ENFILE);
466 slot:
467 	OFILE(p->p_fd, i) = fp;
468 	fp->f_count = 1;
469 	fp->f_data = 0;
470 	fp->f_offset = 0;
471 	fp->f_cred = u.u_cred;
472 	crhold(fp->f_cred);
473 	lastf = fp + 1;
474 	if (resultfp)
475 		*resultfp = fp;
476 	if (resultfd)
477 		*resultfd = i;
478 	return (0);
479 }
480 
481 /*
482  * Duplicate a filedesc structure.
483  */
484 struct filedesc *
485 fddup(fdp, justref)
486 	register struct filedesc *fdp;
487 	int justref;
488 {
489 	register struct filedesc *newfdp;
490 	register struct file *fp;
491 	register int i;
492 	int j, last;
493 
494 	if (justref) {
495 		fdp->fd_refcnt++;
496 		return (fdp);
497 	}
498 	MALLOC(newfdp, struct filedesc *, sizeof(*fdp), M_FILE, M_WAITOK);
499 	bcopy((char *)fdp, (char *)newfdp, sizeof(*fdp));
500 	VREF(newfdp->fd_cdir);
501 	if (newfdp->fd_rdir)
502 		VREF(newfdp->fd_rdir);
503 	newfdp->fd_refcnt = 1;
504 	newfdp->fd_maxfiles = NDFILE;
505 	if (fdp->fd_lastfile > NDFILE &&
506 	    ufalloc(newfdp, fdp->fd_lastfile, &j)) {
507 		log(LOG_ERR, "fddup: lost file descriptor(s)");
508 		last = newfdp->fd_maxfiles;
509 	} else
510 		last = fdp->fd_lastfile;
511 	for (i = 0; i <= last; i++) {
512 		fp = OFILE(fdp, i);
513 		if (fp == NULL)
514 			continue;
515 		fp->f_count++;
516 		OFILE(newfdp, i) = fp;
517 		OFILEFLAGS(newfdp, i) = OFILEFLAGS(fdp, i);
518 	}
519 	return (newfdp);
520 }
521 
522 /*
523  * Release a filedesc structure.
524  */
525 fdrele(fdp)
526 	register struct filedesc *fdp;
527 {
528 	struct file *f;
529 	register int i;
530 
531 	if (fdp->fd_refcnt > 1) {
532 		fdp->fd_refcnt--;
533 		return;
534 	}
535 	for (i = 0; i <= fdp->fd_lastfile; i++) {
536 		if (f = OFILE(fdp, i)) {
537 			OFILE(fdp, i) = NULL;
538 			OFILEFLAGS(fdp, i) = 0;
539 			(void) closef(f);
540 		}
541 	}
542 	if (fdp->fd_maxfiles > NDFILE)
543 		FREE(fdp->fd_moreofiles, M_FILE);
544 	vrele(fdp->fd_cdir);
545 	if (fdp->fd_rdir)
546 		vrele(fdp->fd_rdir);
547 	FREE(fdp, M_FILE);
548 }
549 
550 /*
551  * Internal form of close.
552  * Decrement reference count on file structure.
553  */
554 closef(fp)
555 	register struct file *fp;
556 {
557 	struct proc *p = u.u_procp;		/* XXX */
558 	struct vnode *vp;
559 	struct flock lf;
560 	int error;
561 
562 	if (fp == NULL)
563 		return (0);
564 	/*
565 	 * POSIX record locking dictates that any close releases ALL
566 	 * locks owned by this process.  This is handled by setting
567 	 * a flag in the unlock to free ONLY locks obeying POSIX
568 	 * semantics, and not to free BSD-style file locks.
569 	 */
570 	if (fp->f_type == DTYPE_VNODE) {
571 		lf.l_whence = SEEK_SET;
572 		lf.l_start = 0;
573 		lf.l_len = 0;
574 		lf.l_type = F_UNLCK;
575 		vp = (struct vnode *)fp->f_data;
576 		(void) VOP_ADVLOCK(vp, p, F_UNLCK, &lf, F_POSIX);
577 	}
578 	if (fp->f_count > 1) {
579 		fp->f_count--;
580 		return (0);
581 	}
582 	if (fp->f_count < 1)
583 		panic("closef: count < 1");
584 	if (fp->f_type == DTYPE_VNODE)
585 		(void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK);
586 	error = (*fp->f_ops->fo_close)(fp);
587 	crfree(fp->f_cred);
588 	fp->f_count = 0;
589 	return (error);
590 }
591 
592 /*
593  * Apply an advisory lock on a file descriptor.
594  *
595  * Just attempt to get a record lock of the requested type on
596  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
597  */
598 
599 /* ARGSUSED */
600 flock(p, uap, retval)
601 	struct proc *p;
602 	register struct args {
603 		int	fdes;
604 		int	how;
605 	} *uap;
606 	int *retval;
607 {
608 	register struct filedesc *fdp = p->p_fd;
609 	register struct file *fp;
610 	struct vnode *vp;
611 	struct flock lf;
612 	int error;
613 
614 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
615 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
616 		return (EBADF);
617 	if (fp->f_type != DTYPE_VNODE)
618 		return (EOPNOTSUPP);
619 	vp = (struct vnode *)fp->f_data;
620 	lf.l_whence = SEEK_SET;
621 	lf.l_start = 0;
622 	lf.l_len = 0;
623 	if (uap->how & LOCK_UN) {
624 		lf.l_type = F_UNLCK;
625 		return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK));
626 	}
627 	if (uap->how & LOCK_EX)
628 		lf.l_type = F_WRLCK;
629 	else if (uap->how & LOCK_SH)
630 		lf.l_type = F_RDLCK;
631 	else
632 		return (EBADF);
633 	if (uap->how & LOCK_NB)
634 		return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK));
635 	return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
636 }
637 
638 /*
639  * File Descriptor pseudo-device driver (/dev/fd/).
640  *
641  * Opening minor device N dup()s the file (if any) connected to file
642  * descriptor N belonging to the calling process.  Note that this driver
643  * consists of only the ``open()'' routine, because all subsequent
644  * references to this file will be direct to the other driver.
645  */
646 /* ARGSUSED */
647 fdopen(dev, mode, type)
648 	dev_t dev;
649 	int mode, type;
650 {
651 	struct proc *p = u.u_procp;		/* XXX */
652 
653 	/*
654 	 * XXX Kludge: set p->p_dupfd to contain the value of the
655 	 * the file descriptor being sought for duplication. The error
656 	 * return ensures that the vnode for this device will be released
657 	 * by vn_open. Open will detect this special error and take the
658 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
659 	 * will simply report the error.
660 	 */
661 	p->p_dupfd = minor(dev);
662 	return (ENODEV);
663 }
664 
665 /*
666  * Duplicate the specified descriptor to a free descriptor.
667  */
668 dupfdopen(fdp, indx, dfd, mode)
669 	register struct filedesc *fdp;
670 	register int indx, dfd;
671 	int mode;
672 {
673 	register struct file *wfp;
674 	struct file *fp;
675 
676 	/*
677 	 * If the to-be-dup'd fd number is greater than the allowed number
678 	 * of file descriptors, or the fd to be dup'd has already been
679 	 * closed, reject.  Note, check for new == old is necessary as
680 	 * falloc could allocate an already closed to-be-dup'd descriptor
681 	 * as the new descriptor.
682 	 */
683 	fp = OFILE(fdp, indx);
684 	if ((u_int)dfd >= fdp->fd_maxfiles || (wfp = OFILE(fdp, dfd)) == NULL ||
685 	    fp == wfp)
686 		return (EBADF);
687 
688 	/*
689 	 * Check that the mode the file is being opened for is a subset
690 	 * of the mode of the existing descriptor.
691 	 */
692 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
693 		return (EACCES);
694 	OFILE(fdp, indx) = wfp;
695 	OFILEFLAGS(fdp, indx) = OFILEFLAGS(fdp, dfd);
696 	wfp->f_count++;
697 	if (indx > fdp->fd_lastfile)
698 		fdp->fd_lastfile = indx;
699 	return (0);
700 }
701 
702 #if defined(vax) || defined(tahoe)
703 /*
704  * Brain dead routines to compensate for limitations in PCC
705  */
706 struct file **
707 ofilefunc(fdp, indx)
708 	struct filedesc *fdp;
709 	int indx;
710 {
711 
712 	if (indx < NDFILE)
713 		return (&fdp->fd_ofile[indx]);
714 	return (&fdp->fd_moreofiles[indx - NDFILE]);
715 }
716 
717 char *
718 ofileflagsfunc(fdp, indx)
719 	struct filedesc *fdp;
720 	int indx;
721 {
722 
723 	if (indx < NDFILE)
724 		return (&fdp->fd_ofileflags[indx]);
725 	return (&fdp->fd_moreofileflags[indx - NDFILE]);
726 }
727 #endif
728