xref: /csrg-svn/sys/kern/kern_descrip.c (revision 46495)
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.19 (Berkeley) 02/21/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 (error = VOP_ADVLOCK(vp, p, F_GETLK, &fl, F_POSIX))
231 			return (error);
232 		return (copyout((caddr_t)&fl, (caddr_t)uap->arg, sizeof (fl)));
233 
234 	default:
235 		return (EINVAL);
236 	}
237 	/* NOTREACHED */
238 }
239 
240 fset(fp, bit, value)
241 	struct file *fp;
242 	int bit, value;
243 {
244 
245 	if (value)
246 		fp->f_flag |= bit;
247 	else
248 		fp->f_flag &= ~bit;
249 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
250 	    (caddr_t)&value));
251 }
252 
253 fgetown(fp, valuep)
254 	struct file *fp;
255 	int *valuep;
256 {
257 	int error;
258 
259 	switch (fp->f_type) {
260 
261 	case DTYPE_SOCKET:
262 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
263 		return (0);
264 
265 	default:
266 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
267 		*valuep = -*valuep;
268 		return (error);
269 	}
270 }
271 
272 fsetown(fp, value)
273 	struct file *fp;
274 	int value;
275 {
276 
277 	if (fp->f_type == DTYPE_SOCKET) {
278 		((struct socket *)fp->f_data)->so_pgid = value;
279 		return (0);
280 	}
281 	if (value > 0) {
282 		struct proc *p = pfind(value);
283 		if (p == 0)
284 			return (ESRCH);
285 		value = p->p_pgrp->pg_id;
286 	} else
287 		value = -value;
288 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
289 }
290 
291 fioctl(fp, cmd, value)
292 	struct file *fp;
293 	int cmd;
294 	caddr_t value;
295 {
296 
297 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
298 }
299 
300 /*
301  * Close a file descriptor.
302  */
303 /* ARGSUSED */
304 close(p, uap, retval)
305 	struct proc *p;
306 	struct args {
307 		int	fdes;
308 	} *uap;
309 	int *retval;
310 {
311 	register struct filedesc *fdp = p->p_fd;
312 	register struct file *fp;
313 	register u_char *pf;
314 
315 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
316 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
317 		return (EBADF);
318 	pf = (u_char *)&OFILEFLAGS(fdp, uap->fdes);
319 	if (*pf & UF_MAPPED)
320 		(void) munmapfd(p, uap->fdes);
321 	OFILE(fdp, uap->fdes) = NULL;
322 	while (fdp->fd_lastfile >= 0 && OFILE(fdp, fdp->fd_lastfile) == NULL)
323 		fdp->fd_lastfile--;
324 	*pf = 0;
325 	return (closef(fp));
326 }
327 
328 /*
329  * Return status information about a file descriptor.
330  */
331 /* ARGSUSED */
332 fstat(p, uap, retval)
333 	struct proc *p;
334 	register struct args {
335 		int	fdes;
336 		struct	stat *sb;
337 	} *uap;
338 	int *retval;
339 {
340 	register struct filedesc *fdp = p->p_fd;
341 	register struct file *fp;
342 	struct stat ub;
343 	int error;
344 
345 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
346 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
347 		return (EBADF);
348 	switch (fp->f_type) {
349 
350 	case DTYPE_VNODE:
351 		error = vn_stat((struct vnode *)fp->f_data, &ub);
352 		break;
353 
354 	case DTYPE_SOCKET:
355 		error = soo_stat((struct socket *)fp->f_data, &ub);
356 		break;
357 
358 	default:
359 		panic("fstat");
360 		/*NOTREACHED*/
361 	}
362 	if (error == 0)
363 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
364 	return (error);
365 }
366 
367 /*
368  * Allocate a user file descriptor.
369  */
370 int fdexpand, fdreexpand;
371 
372 ufalloc(fdp, want, result)
373 	register struct filedesc *fdp;
374 	register int want;
375 	int *result;
376 {
377 	int last, osize, ofiles, nfiles;
378 	struct file **newofile;
379 	char *newofileflags;
380 
381 	for (;;) {
382 		last = (fdp->fd_maxfiles < nofile) ? fdp->fd_maxfiles : nofile;
383 		for (; want < last; want++) {
384 			if (OFILE(fdp, want) == NULL) {
385 				OFILEFLAGS(fdp, want) = 0;
386 				if (want > fdp->fd_lastfile)
387 					fdp->fd_lastfile = want;
388 				*result = want;
389 				return (0);
390 			}
391 		}
392 		if (fdp->fd_maxfiles >= nofile)
393 			return (EMFILE);
394 		if (fdp->fd_maxfiles == NDFILE) {
395 			fdp->fd_moreofiles = (struct file **)
396 			    malloc(NDEXTENT * OFILESIZE, M_FILE, M_WAITOK);
397 			fdp->fd_moreofileflags =
398 			    (char *)&fdp->fd_moreofiles[NDEXTENT];
399 			bzero((char *)fdp->fd_moreofiles, NDEXTENT * OFILESIZE);
400 			fdp->fd_maxfiles = NDFILE + NDEXTENT;
401 			fdexpand++;
402 			continue;
403 		}
404 		ofiles = fdp->fd_maxfiles - NDFILE;
405 		osize = ofiles * OFILESIZE;
406 		nfiles = (2 * osize) / OFILESIZE;
407 		newofile = (struct file **) malloc(2 * osize, M_FILE, M_WAITOK);
408 		newofileflags = (char *)&newofile[nfiles];
409 		bzero((char *)newofile, 2 * osize);
410 		bcopy((char *)fdp->fd_moreofiles, (char *)newofile,
411 			sizeof(struct file *) * ofiles);
412 		bcopy((char *)fdp->fd_moreofileflags, (char *)newofileflags,
413 			sizeof(char) * ofiles);
414 		free(fdp->fd_moreofiles, M_FILE);
415 		fdp->fd_moreofiles = newofile;
416 		fdp->fd_moreofileflags = newofileflags;
417 		fdp->fd_maxfiles = NDFILE + nfiles;
418 		fdreexpand++;
419 	}
420 }
421 
422 /*
423  * Check to see if any user file descriptors are available.
424  */
425 ufavail(fdp)
426 	register struct filedesc *fdp;
427 {
428 	register int i, avail;
429 
430 	avail = nofile - fdp->fd_maxfiles;
431 	for (i = 0; i < fdp->fd_maxfiles; i++)
432 		if (OFILE(fdp, i) == NULL)
433 			avail++;
434 	return (avail);
435 }
436 
437 struct	file *lastf;
438 /*
439  * Allocate a user file descriptor
440  * and a file structure.
441  * Initialize the descriptor
442  * to point at the file structure.
443  */
444 falloc(p, resultfp, resultfd)
445 	register struct proc *p;
446 	struct file **resultfp;
447 	int *resultfd;
448 {
449 	register struct file *fp;
450 	int error, i;
451 
452 	if (error = ufalloc(p->p_fd, 0, &i))
453 		return (error);
454 	if (lastf == 0)
455 		lastf = file;
456 	for (fp = lastf; fp < fileNFILE; fp++)
457 		if (fp->f_count == 0)
458 			goto slot;
459 	for (fp = file; fp < lastf; fp++)
460 		if (fp->f_count == 0)
461 			goto slot;
462 	tablefull("file");
463 	return (ENFILE);
464 slot:
465 	OFILE(p->p_fd, i) = fp;
466 	fp->f_count = 1;
467 	fp->f_data = 0;
468 	fp->f_offset = 0;
469 	fp->f_cred = u.u_cred;
470 	crhold(fp->f_cred);
471 	lastf = fp + 1;
472 	if (resultfp)
473 		*resultfp = fp;
474 	if (resultfd)
475 		*resultfd = i;
476 	return (0);
477 }
478 
479 /*
480  * Duplicate a filedesc structure.
481  */
482 struct filedesc *
483 fddup(fdp, justref)
484 	register struct filedesc *fdp;
485 	int justref;
486 {
487 	register struct filedesc *newfdp;
488 	register struct file *fp;
489 	register int i;
490 	int j, last;
491 
492 	if (justref) {
493 		fdp->fd_refcnt++;
494 		return (fdp);
495 	}
496 	MALLOC(newfdp, struct filedesc *, sizeof(*fdp), M_FILE, M_WAITOK);
497 	bcopy((char *)fdp, (char *)newfdp, sizeof(*fdp));
498 	VREF(newfdp->fd_cdir);
499 	if (newfdp->fd_rdir)
500 		VREF(newfdp->fd_rdir);
501 	newfdp->fd_refcnt = 1;
502 	newfdp->fd_maxfiles = NDFILE;
503 	if (fdp->fd_lastfile > NDFILE &&
504 	    ufalloc(newfdp, fdp->fd_lastfile, &j)) {
505 		log(LOG_ERR, "fddup: lost file descriptor(s)");
506 		last = newfdp->fd_maxfiles;
507 	} else
508 		last = fdp->fd_lastfile;
509 	for (i = 0; i <= last; i++) {
510 		fp = OFILE(fdp, i);
511 		if (fp == NULL)
512 			continue;
513 		fp->f_count++;
514 		OFILE(newfdp, i) = fp;
515 		OFILEFLAGS(newfdp, i) = OFILEFLAGS(fdp, i);
516 	}
517 	return (newfdp);
518 }
519 
520 /*
521  * Release a filedesc structure.
522  */
523 fdrele(fdp)
524 	register struct filedesc *fdp;
525 {
526 	struct file *f;
527 	register int i;
528 
529 	if (fdp->fd_refcnt > 1) {
530 		fdp->fd_refcnt--;
531 		return;
532 	}
533 	for (i = 0; i <= fdp->fd_lastfile; i++) {
534 		if (f = OFILE(fdp, i)) {
535 			OFILE(fdp, i) = NULL;
536 			OFILEFLAGS(fdp, i) = 0;
537 			(void) closef(f);
538 		}
539 	}
540 	if (fdp->fd_maxfiles > NDFILE)
541 		FREE(fdp->fd_moreofiles, M_FILE);
542 	vrele(fdp->fd_cdir);
543 	if (fdp->fd_rdir)
544 		vrele(fdp->fd_rdir);
545 	FREE(fdp, M_FILE);
546 }
547 
548 /*
549  * Internal form of close.
550  * Decrement reference count on file structure.
551  */
552 closef(fp)
553 	register struct file *fp;
554 {
555 	struct proc *p = u.u_procp;		/* XXX */
556 	struct vnode *vp;
557 	struct flock lf;
558 	int error;
559 
560 	if (fp == NULL)
561 		return (0);
562 	/*
563 	 * POSIX record locking dictates that any close releases ALL
564 	 * locks owned by this process.  This is handled by setting
565 	 * a flag in the unlock to free ONLY locks obeying POSIX
566 	 * semantics, and not to free BSD-style file locks.
567 	 */
568 	if (fp->f_type == DTYPE_VNODE) {
569 		lf.l_whence = SEEK_SET;
570 		lf.l_start = 0;
571 		lf.l_len = 0;
572 		lf.l_type = F_UNLCK;
573 		vp = (struct vnode *)fp->f_data;
574 		(void) VOP_ADVLOCK(vp, p, F_UNLCK, &lf, F_POSIX);
575 	}
576 	if (fp->f_count > 1) {
577 		fp->f_count--;
578 		return (0);
579 	}
580 	if (fp->f_count < 1)
581 		panic("closef: count < 1");
582 	if (fp->f_type == DTYPE_VNODE)
583 		(void) VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK);
584 	error = (*fp->f_ops->fo_close)(fp);
585 	crfree(fp->f_cred);
586 	fp->f_count = 0;
587 	return (error);
588 }
589 
590 /*
591  * Apply an advisory lock on a file descriptor.
592  *
593  * Just attempt to get a record lock of the requested type on
594  * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
595  */
596 
597 /* ARGSUSED */
598 flock(p, uap, retval)
599 	struct proc *p;
600 	register struct args {
601 		int	fdes;
602 		int	how;
603 	} *uap;
604 	int *retval;
605 {
606 	register struct filedesc *fdp = p->p_fd;
607 	register struct file *fp;
608 	struct vnode *vp;
609 	struct flock lf;
610 	int error;
611 
612 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
613 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
614 		return (EBADF);
615 	if (fp->f_type != DTYPE_VNODE)
616 		return (EOPNOTSUPP);
617 	vp = (struct vnode *)fp->f_data;
618 	lf.l_whence = SEEK_SET;
619 	lf.l_start = 0;
620 	lf.l_len = 0;
621 	if (uap->how & LOCK_UN) {
622 		lf.l_type = F_UNLCK;
623 		return (VOP_ADVLOCK(vp, fp, F_UNLCK, &lf, F_FLOCK));
624 	}
625 	if (uap->how & LOCK_EX)
626 		lf.l_type = F_WRLCK;
627 	else if (uap->how & LOCK_SH)
628 		lf.l_type = F_RDLCK;
629 	else
630 		return (EBADF);
631 	if (uap->how & LOCK_NB)
632 		return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK));
633 	return (VOP_ADVLOCK(vp, fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
634 }
635 
636 /*
637  * File Descriptor pseudo-device driver (/dev/fd/).
638  *
639  * Opening minor device N dup()s the file (if any) connected to file
640  * descriptor N belonging to the calling process.  Note that this driver
641  * consists of only the ``open()'' routine, because all subsequent
642  * references to this file will be direct to the other driver.
643  */
644 /* ARGSUSED */
645 fdopen(dev, mode, type)
646 	dev_t dev;
647 	int mode, type;
648 {
649 	struct proc *p = u.u_procp;		/* XXX */
650 
651 	/*
652 	 * XXX Kludge: set p->p_dupfd to contain the value of the
653 	 * the file descriptor being sought for duplication. The error
654 	 * return ensures that the vnode for this device will be released
655 	 * by vn_open. Open will detect this special error and take the
656 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
657 	 * will simply report the error.
658 	 */
659 	p->p_dupfd = minor(dev);
660 	return (ENODEV);
661 }
662 
663 /*
664  * Duplicate the specified descriptor to a free descriptor.
665  */
666 dupfdopen(fdp, indx, dfd, mode)
667 	register struct filedesc *fdp;
668 	register int indx, dfd;
669 	int mode;
670 {
671 	register struct file *wfp;
672 	struct file *fp;
673 
674 	/*
675 	 * If the to-be-dup'd fd number is greater than the allowed number
676 	 * of file descriptors, or the fd to be dup'd has already been
677 	 * closed, reject.  Note, check for new == old is necessary as
678 	 * falloc could allocate an already closed to-be-dup'd descriptor
679 	 * as the new descriptor.
680 	 */
681 	fp = OFILE(fdp, indx);
682 	if ((u_int)dfd >= fdp->fd_maxfiles || (wfp = OFILE(fdp, dfd)) == NULL ||
683 	    fp == wfp)
684 		return (EBADF);
685 
686 	/*
687 	 * Check that the mode the file is being opened for is a subset
688 	 * of the mode of the existing descriptor.
689 	 */
690 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
691 		return (EACCES);
692 	OFILE(fdp, indx) = wfp;
693 	OFILEFLAGS(fdp, indx) = OFILEFLAGS(fdp, dfd);
694 	wfp->f_count++;
695 	if (indx > fdp->fd_lastfile)
696 		fdp->fd_lastfile = indx;
697 	return (0);
698 }
699 
700 #if defined(vax) || defined(tahoe)
701 /*
702  * Brain dead routines to compensate for limitations in PCC
703  */
704 struct file **
705 ofilefunc(fdp, indx)
706 	struct filedesc *fdp;
707 	int indx;
708 {
709 
710 	if (indx < NDFILE)
711 		return (&fdp->fd_ofile[indx]);
712 	return (&fdp->fd_moreofiles[indx - NDFILE]);
713 }
714 
715 char *
716 ofileflagsfunc(fdp, indx)
717 	struct filedesc *fdp;
718 	int indx;
719 {
720 
721 	if (indx < NDFILE)
722 		return (&fdp->fd_ofileflags[indx]);
723 	return (&fdp->fd_moreofileflags[indx - NDFILE]);
724 }
725 #endif
726