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