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