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