Line data Source code
1 : /* $OpenBSD: kern_descrip.c,v 1.182 2018/08/24 12:45:27 visa Exp $ */
2 : /* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1982, 1986, 1989, 1991, 1993
6 : * The Regents of the University of California. All rights reserved.
7 : * (c) UNIX System Laboratories, Inc.
8 : * All or some portions of this file are derived from material licensed
9 : * to the University of California by American Telephone and Telegraph
10 : * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11 : * the permission of UNIX System Laboratories, Inc.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : *
37 : * @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94
38 : */
39 :
40 : #include <sys/param.h>
41 : #include <sys/systm.h>
42 : #include <sys/filedesc.h>
43 : #include <sys/kernel.h>
44 : #include <sys/vnode.h>
45 : #include <sys/proc.h>
46 : #include <sys/file.h>
47 : #include <sys/socket.h>
48 : #include <sys/socketvar.h>
49 : #include <sys/stat.h>
50 : #include <sys/ioctl.h>
51 : #include <sys/fcntl.h>
52 : #include <sys/lock.h>
53 : #include <sys/malloc.h>
54 : #include <sys/syslog.h>
55 : #include <sys/ucred.h>
56 : #include <sys/unistd.h>
57 : #include <sys/resourcevar.h>
58 : #include <sys/mount.h>
59 : #include <sys/syscallargs.h>
60 : #include <sys/event.h>
61 : #include <sys/pool.h>
62 : #include <sys/ktrace.h>
63 : #include <sys/pledge.h>
64 :
65 : #include <sys/pipe.h>
66 :
67 : /*
68 : * Descriptor management.
69 : *
70 : * We need to block interrupts as long as `fhdlk' is being taken
71 : * with and without the KERNEL_LOCK().
72 : */
73 : struct mutex fhdlk = MUTEX_INITIALIZER(IPL_MPFLOOR);
74 : struct filelist filehead; /* head of list of open files */
75 : int numfiles; /* actual number of open files */
76 :
77 : static __inline void fd_used(struct filedesc *, int);
78 : static __inline void fd_unused(struct filedesc *, int);
79 : static __inline int find_next_zero(u_int *, int, u_int);
80 : static __inline int fd_inuse(struct filedesc *, int);
81 : int finishdup(struct proc *, struct file *, int, int, register_t *, int);
82 : int find_last_set(struct filedesc *, int);
83 : int dodup3(struct proc *, int, int, int, register_t *);
84 :
85 : struct pool file_pool;
86 : struct pool fdesc_pool;
87 :
88 : void
89 0 : filedesc_init(void)
90 : {
91 0 : pool_init(&file_pool, sizeof(struct file), 0, IPL_MPFLOOR,
92 : PR_WAITOK, "filepl", NULL);
93 0 : pool_init(&fdesc_pool, sizeof(struct filedesc0), 0, IPL_NONE,
94 : PR_WAITOK, "fdescpl", NULL);
95 0 : LIST_INIT(&filehead);
96 0 : }
97 :
98 : static __inline int
99 0 : find_next_zero (u_int *bitmap, int want, u_int bits)
100 : {
101 : int i, off, maxoff;
102 : u_int sub;
103 :
104 0 : if (want > bits)
105 0 : return -1;
106 :
107 0 : off = want >> NDENTRYSHIFT;
108 0 : i = want & NDENTRYMASK;
109 0 : if (i) {
110 0 : sub = bitmap[off] | ((u_int)~0 >> (NDENTRIES - i));
111 0 : if (sub != ~0)
112 : goto found;
113 0 : off++;
114 0 : }
115 :
116 0 : maxoff = NDLOSLOTS(bits);
117 0 : while (off < maxoff) {
118 0 : if ((sub = bitmap[off]) != ~0)
119 : goto found;
120 0 : off++;
121 : }
122 :
123 0 : return -1;
124 :
125 : found:
126 0 : return (off << NDENTRYSHIFT) + ffs(~sub) - 1;
127 0 : }
128 :
129 : int
130 0 : find_last_set(struct filedesc *fd, int last)
131 : {
132 : int off, i;
133 0 : u_int *bitmap = fd->fd_lomap;
134 :
135 0 : off = (last - 1) >> NDENTRYSHIFT;
136 :
137 0 : while (off >= 0 && !bitmap[off])
138 0 : off--;
139 0 : if (off < 0)
140 0 : return 0;
141 :
142 0 : i = ((off + 1) << NDENTRYSHIFT) - 1;
143 0 : if (i >= last)
144 0 : i = last - 1;
145 :
146 0 : while (i > 0 && !fd_inuse(fd, i))
147 0 : i--;
148 0 : return i;
149 0 : }
150 :
151 : static __inline int
152 0 : fd_inuse(struct filedesc *fdp, int fd)
153 : {
154 0 : u_int off = fd >> NDENTRYSHIFT;
155 :
156 0 : if (fdp->fd_lomap[off] & (1 << (fd & NDENTRYMASK)))
157 0 : return 1;
158 :
159 0 : return 0;
160 0 : }
161 :
162 : static __inline void
163 0 : fd_used(struct filedesc *fdp, int fd)
164 : {
165 0 : u_int off = fd >> NDENTRYSHIFT;
166 :
167 0 : fdp->fd_lomap[off] |= 1 << (fd & NDENTRYMASK);
168 0 : if (fdp->fd_lomap[off] == ~0)
169 0 : fdp->fd_himap[off >> NDENTRYSHIFT] |= 1 << (off & NDENTRYMASK);
170 :
171 0 : if (fd > fdp->fd_lastfile)
172 0 : fdp->fd_lastfile = fd;
173 0 : fdp->fd_openfd++;
174 0 : }
175 :
176 : static __inline void
177 0 : fd_unused(struct filedesc *fdp, int fd)
178 : {
179 0 : u_int off = fd >> NDENTRYSHIFT;
180 :
181 0 : if (fd < fdp->fd_freefile)
182 0 : fdp->fd_freefile = fd;
183 :
184 0 : if (fdp->fd_lomap[off] == ~0)
185 0 : fdp->fd_himap[off >> NDENTRYSHIFT] &= ~(1 << (off & NDENTRYMASK));
186 0 : fdp->fd_lomap[off] &= ~(1 << (fd & NDENTRYMASK));
187 :
188 : #ifdef DIAGNOSTIC
189 0 : if (fd > fdp->fd_lastfile)
190 0 : panic("fd_unused: fd_lastfile inconsistent");
191 : #endif
192 0 : if (fd == fdp->fd_lastfile)
193 0 : fdp->fd_lastfile = find_last_set(fdp, fd);
194 0 : fdp->fd_openfd--;
195 0 : }
196 :
197 : struct file *
198 0 : fd_iterfile(struct file *fp, struct proc *p)
199 : {
200 : struct file *nfp;
201 : unsigned int count;
202 :
203 0 : mtx_enter(&fhdlk);
204 0 : if (fp == NULL)
205 0 : nfp = LIST_FIRST(&filehead);
206 : else
207 0 : nfp = LIST_NEXT(fp, f_list);
208 :
209 : /* don't refcount when f_count == 0 to avoid race in fdrop() */
210 0 : while (nfp != NULL) {
211 0 : count = nfp->f_count;
212 0 : if (count == 0) {
213 0 : nfp = LIST_NEXT(nfp, f_list);
214 0 : continue;
215 : }
216 0 : if (atomic_cas_uint(&nfp->f_count, count, count + 1) == count)
217 : break;
218 : }
219 0 : mtx_leave(&fhdlk);
220 :
221 0 : if (fp != NULL)
222 0 : FRELE(fp, p);
223 :
224 0 : return nfp;
225 : }
226 :
227 : struct file *
228 0 : fd_getfile(struct filedesc *fdp, int fd)
229 : {
230 : struct file *fp;
231 :
232 0 : vfs_stall_barrier();
233 :
234 0 : if ((u_int)fd >= fdp->fd_nfiles)
235 0 : return (NULL);
236 :
237 0 : mtx_enter(&fdp->fd_fplock);
238 0 : fp = fdp->fd_ofiles[fd];
239 0 : if (fp != NULL)
240 0 : atomic_inc_int(&fp->f_count);
241 0 : mtx_leave(&fdp->fd_fplock);
242 :
243 0 : return (fp);
244 0 : }
245 :
246 : struct file *
247 0 : fd_getfile_mode(struct filedesc *fdp, int fd, int mode)
248 : {
249 : struct file *fp;
250 :
251 0 : KASSERT(mode != 0);
252 :
253 0 : fp = fd_getfile(fdp, fd);
254 0 : if (fp == NULL)
255 0 : return (NULL);
256 :
257 0 : if ((fp->f_flag & mode) == 0) {
258 0 : FRELE(fp, curproc);
259 0 : return (NULL);
260 : }
261 :
262 0 : return (fp);
263 0 : }
264 :
265 : /*
266 : * System calls on descriptors.
267 : */
268 :
269 : /*
270 : * Duplicate a file descriptor.
271 : */
272 : int
273 0 : sys_dup(struct proc *p, void *v, register_t *retval)
274 : {
275 : struct sys_dup_args /* {
276 : syscallarg(int) fd;
277 0 : } */ *uap = v;
278 0 : struct filedesc *fdp = p->p_fd;
279 0 : int old = SCARG(uap, fd);
280 : struct file *fp;
281 0 : int new;
282 0 : int error;
283 :
284 : restart:
285 0 : if ((fp = fd_getfile(fdp, old)) == NULL)
286 0 : return (EBADF);
287 0 : fdplock(fdp);
288 0 : if ((error = fdalloc(p, 0, &new)) != 0) {
289 0 : FRELE(fp, p);
290 0 : if (error == ENOSPC) {
291 0 : fdexpand(p);
292 0 : fdpunlock(fdp);
293 0 : goto restart;
294 : }
295 : goto out;
296 : }
297 : /* No need for FRELE(), finishdup() uses current ref. */
298 0 : error = finishdup(p, fp, old, new, retval, 0);
299 :
300 : out:
301 0 : fdpunlock(fdp);
302 0 : return (error);
303 0 : }
304 :
305 : /*
306 : * Duplicate a file descriptor to a particular value.
307 : */
308 : int
309 0 : sys_dup2(struct proc *p, void *v, register_t *retval)
310 : {
311 : struct sys_dup2_args /* {
312 : syscallarg(int) from;
313 : syscallarg(int) to;
314 0 : } */ *uap = v;
315 :
316 0 : return (dodup3(p, SCARG(uap, from), SCARG(uap, to), 0, retval));
317 : }
318 :
319 : int
320 0 : sys_dup3(struct proc *p, void *v, register_t *retval)
321 : {
322 : struct sys_dup3_args /* {
323 : syscallarg(int) from;
324 : syscallarg(int) to;
325 : syscallarg(int) flags;
326 0 : } */ *uap = v;
327 :
328 0 : if (SCARG(uap, from) == SCARG(uap, to))
329 0 : return (EINVAL);
330 0 : if (SCARG(uap, flags) & ~O_CLOEXEC)
331 0 : return (EINVAL);
332 0 : return (dodup3(p, SCARG(uap, from), SCARG(uap, to),
333 : SCARG(uap, flags), retval));
334 0 : }
335 :
336 : int
337 0 : dodup3(struct proc *p, int old, int new, int flags, register_t *retval)
338 : {
339 0 : struct filedesc *fdp = p->p_fd;
340 : struct file *fp;
341 0 : int i, error;
342 :
343 : restart:
344 0 : if ((fp = fd_getfile(fdp, old)) == NULL)
345 0 : return (EBADF);
346 0 : if ((u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
347 0 : (u_int)new >= maxfiles) {
348 0 : FRELE(fp, p);
349 0 : return (EBADF);
350 : }
351 0 : if (old == new) {
352 : /*
353 : * NOTE! This doesn't clear the close-on-exec flag. This might
354 : * or might not be the intended behavior from the start, but
355 : * this is what everyone else does.
356 : */
357 0 : *retval = new;
358 0 : FRELE(fp, p);
359 0 : return (0);
360 : }
361 0 : fdplock(fdp);
362 0 : if (new >= fdp->fd_nfiles) {
363 0 : if ((error = fdalloc(p, new, &i)) != 0) {
364 0 : FRELE(fp, p);
365 0 : if (error == ENOSPC) {
366 0 : fdexpand(p);
367 0 : fdpunlock(fdp);
368 0 : goto restart;
369 : }
370 : goto out;
371 : }
372 0 : if (new != i)
373 0 : panic("dup2: fdalloc");
374 0 : fd_unused(fdp, new);
375 0 : }
376 : /* No need for FRELE(), finishdup() uses current ref. */
377 0 : error = finishdup(p, fp, old, new, retval, 1);
378 0 : if (!error && flags & O_CLOEXEC)
379 0 : fdp->fd_ofileflags[new] |= UF_EXCLOSE;
380 :
381 : out:
382 0 : fdpunlock(fdp);
383 0 : return (error);
384 0 : }
385 :
386 : /*
387 : * The file control system call.
388 : */
389 : int
390 0 : sys_fcntl(struct proc *p, void *v, register_t *retval)
391 : {
392 : struct sys_fcntl_args /* {
393 : syscallarg(int) fd;
394 : syscallarg(int) cmd;
395 : syscallarg(void *) arg;
396 0 : } */ *uap = v;
397 0 : int fd = SCARG(uap, fd);
398 0 : struct filedesc *fdp = p->p_fd;
399 : struct file *fp, *fp2;
400 : struct vnode *vp;
401 0 : int i, tmp, newmin, flg = F_POSIX;
402 0 : struct flock fl;
403 : int error = 0;
404 :
405 0 : error = pledge_fcntl(p, SCARG(uap, cmd));
406 0 : if (error)
407 0 : return (error);
408 :
409 : restart:
410 0 : if ((fp = fd_getfile(fdp, fd)) == NULL)
411 0 : return (EBADF);
412 0 : switch (SCARG(uap, cmd)) {
413 :
414 : case F_DUPFD:
415 : case F_DUPFD_CLOEXEC:
416 0 : newmin = (long)SCARG(uap, arg);
417 0 : if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
418 0 : (u_int)newmin >= maxfiles) {
419 : error = EINVAL;
420 0 : break;
421 : }
422 0 : fdplock(fdp);
423 0 : if ((error = fdalloc(p, newmin, &i)) != 0) {
424 0 : FRELE(fp, p);
425 0 : if (error == ENOSPC) {
426 0 : fdexpand(p);
427 0 : fdpunlock(fdp);
428 0 : goto restart;
429 : }
430 : } else {
431 : /* No need for FRELE(), finishdup() uses current ref. */
432 0 : error = finishdup(p, fp, fd, i, retval, 0);
433 :
434 0 : if (!error && SCARG(uap, cmd) == F_DUPFD_CLOEXEC)
435 0 : fdp->fd_ofileflags[i] |= UF_EXCLOSE;
436 : }
437 :
438 0 : fdpunlock(fdp);
439 0 : return (error);
440 :
441 : case F_GETFD:
442 0 : fdplock(fdp);
443 0 : *retval = fdp->fd_ofileflags[fd] & UF_EXCLOSE ? 1 : 0;
444 0 : fdpunlock(fdp);
445 0 : break;
446 :
447 : case F_SETFD:
448 0 : fdplock(fdp);
449 0 : if ((long)SCARG(uap, arg) & 1)
450 0 : fdp->fd_ofileflags[fd] |= UF_EXCLOSE;
451 : else
452 0 : fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE;
453 0 : fdpunlock(fdp);
454 0 : break;
455 :
456 : case F_GETFL:
457 0 : *retval = OFLAGS(fp->f_flag);
458 0 : break;
459 :
460 : case F_ISATTY:
461 0 : vp = fp->f_data;
462 0 : if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
463 0 : *retval = 1;
464 : else {
465 0 : *retval = 0;
466 : error = ENOTTY;
467 : }
468 : break;
469 :
470 : case F_SETFL:
471 0 : fp->f_flag &= ~FCNTLFLAGS;
472 0 : fp->f_flag |= FFLAGS((long)SCARG(uap, arg)) & FCNTLFLAGS;
473 0 : tmp = fp->f_flag & FNONBLOCK;
474 0 : error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
475 0 : if (error)
476 : break;
477 0 : tmp = fp->f_flag & FASYNC;
478 0 : error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p);
479 0 : if (!error)
480 : break;
481 0 : fp->f_flag &= ~FNONBLOCK;
482 0 : tmp = 0;
483 0 : (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p);
484 0 : break;
485 :
486 : case F_GETOWN:
487 0 : tmp = 0;
488 0 : error = (*fp->f_ops->fo_ioctl)
489 : (fp, TIOCGPGRP, (caddr_t)&tmp, p);
490 0 : *retval = -tmp;
491 0 : break;
492 :
493 : case F_SETOWN:
494 0 : tmp = (long)SCARG(uap, arg);
495 0 : if (fp->f_type == DTYPE_SOCKET || fp->f_type == DTYPE_PIPE) {
496 : /* nothing */
497 0 : } else if (tmp <= 0) {
498 0 : tmp = -tmp;
499 0 : } else {
500 0 : struct process *pr1 = prfind(tmp);
501 0 : if (pr1 == 0) {
502 : error = ESRCH;
503 0 : break;
504 : }
505 0 : tmp = pr1->ps_pgrp->pg_id;
506 0 : }
507 0 : error = ((*fp->f_ops->fo_ioctl)
508 : (fp, TIOCSPGRP, (caddr_t)&tmp, p));
509 0 : break;
510 :
511 : case F_SETLKW:
512 0 : flg |= F_WAIT;
513 : /* FALLTHROUGH */
514 :
515 : case F_SETLK:
516 0 : error = pledge_flock(p);
517 0 : if (error != 0)
518 : break;
519 :
520 0 : if (fp->f_type != DTYPE_VNODE) {
521 : error = EBADF;
522 0 : break;
523 : }
524 0 : vp = fp->f_data;
525 : /* Copy in the lock structure */
526 0 : error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
527 : sizeof (fl));
528 0 : if (error)
529 : break;
530 0 : if (fl.l_whence == SEEK_CUR) {
531 0 : if (fl.l_start == 0 && fl.l_len < 0) {
532 : /* lockf(3) compliance hack */
533 0 : fl.l_len = -fl.l_len;
534 0 : fl.l_start = fp->f_offset - fl.l_len;
535 0 : } else
536 0 : fl.l_start += fp->f_offset;
537 : }
538 0 : switch (fl.l_type) {
539 :
540 : case F_RDLCK:
541 0 : if ((fp->f_flag & FREAD) == 0) {
542 : error = EBADF;
543 0 : goto out;
544 : }
545 0 : atomic_setbits_int(&fdp->fd_flags, FD_ADVLOCK);
546 0 : error = VOP_ADVLOCK(vp, fdp, F_SETLK, &fl, flg);
547 0 : break;
548 :
549 : case F_WRLCK:
550 0 : if ((fp->f_flag & FWRITE) == 0) {
551 : error = EBADF;
552 0 : goto out;
553 : }
554 0 : atomic_setbits_int(&fdp->fd_flags, FD_ADVLOCK);
555 0 : error = VOP_ADVLOCK(vp, fdp, F_SETLK, &fl, flg);
556 0 : break;
557 :
558 : case F_UNLCK:
559 0 : error = VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
560 0 : goto out;
561 :
562 : default:
563 : error = EINVAL;
564 0 : goto out;
565 : }
566 :
567 0 : fp2 = fd_getfile(fdp, fd);
568 0 : if (fp != fp2) {
569 : /*
570 : * We have lost the race with close() or dup2();
571 : * unlock, pretend that we've won the race and that
572 : * lock had been removed by close()
573 : */
574 0 : fl.l_whence = SEEK_SET;
575 0 : fl.l_start = 0;
576 0 : fl.l_len = 0;
577 0 : VOP_ADVLOCK(vp, fdp, F_UNLCK, &fl, F_POSIX);
578 0 : fl.l_type = F_UNLCK;
579 0 : }
580 0 : if (fp2 != NULL)
581 0 : FRELE(fp2, p);
582 : goto out;
583 :
584 :
585 : case F_GETLK:
586 0 : error = pledge_flock(p);
587 0 : if (error != 0)
588 : break;
589 :
590 0 : if (fp->f_type != DTYPE_VNODE) {
591 : error = EBADF;
592 0 : break;
593 : }
594 0 : vp = fp->f_data;
595 : /* Copy in the lock structure */
596 0 : error = copyin((caddr_t)SCARG(uap, arg), (caddr_t)&fl,
597 : sizeof (fl));
598 0 : if (error)
599 : break;
600 0 : if (fl.l_whence == SEEK_CUR) {
601 0 : if (fl.l_start == 0 && fl.l_len < 0) {
602 : /* lockf(3) compliance hack */
603 0 : fl.l_len = -fl.l_len;
604 0 : fl.l_start = fp->f_offset - fl.l_len;
605 0 : } else
606 0 : fl.l_start += fp->f_offset;
607 : }
608 0 : if (fl.l_type != F_RDLCK &&
609 0 : fl.l_type != F_WRLCK &&
610 0 : fl.l_type != F_UNLCK &&
611 0 : fl.l_type != 0) {
612 : error = EINVAL;
613 0 : break;
614 : }
615 0 : error = VOP_ADVLOCK(vp, fdp, F_GETLK, &fl, F_POSIX);
616 0 : if (error)
617 : break;
618 0 : error = (copyout((caddr_t)&fl, (caddr_t)SCARG(uap, arg),
619 : sizeof (fl)));
620 0 : break;
621 :
622 : default:
623 : error = EINVAL;
624 0 : break;
625 : }
626 : out:
627 0 : FRELE(fp, p);
628 0 : return (error);
629 0 : }
630 :
631 : /*
632 : * Common code for dup, dup2, and fcntl(F_DUPFD).
633 : */
634 : int
635 0 : finishdup(struct proc *p, struct file *fp, int old, int new,
636 : register_t *retval, int dup2)
637 : {
638 : struct file *oldfp;
639 0 : struct filedesc *fdp = p->p_fd;
640 :
641 0 : fdpassertlocked(fdp);
642 0 : KASSERT(fp->f_iflags & FIF_INSERTED);
643 :
644 0 : if (fp->f_count >= FDUP_MAX_COUNT) {
645 0 : FRELE(fp, p);
646 0 : return (EDEADLK);
647 : }
648 :
649 0 : oldfp = fd_getfile(fdp, new);
650 0 : if (dup2 && oldfp == NULL) {
651 0 : if (fd_inuse(fdp, new)) {
652 0 : FRELE(fp, p);
653 0 : return (EBUSY);
654 : }
655 0 : fd_used(fdp, new);
656 0 : }
657 :
658 : /*
659 : * Use `fd_fplock' to synchronize with fd_getfile() so that
660 : * the function no longer creates a new reference to the old file.
661 : */
662 0 : mtx_enter(&fdp->fd_fplock);
663 0 : fdp->fd_ofiles[new] = fp;
664 0 : mtx_leave(&fdp->fd_fplock);
665 :
666 0 : fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] & ~UF_EXCLOSE;
667 0 : *retval = new;
668 :
669 0 : if (oldfp != NULL) {
670 0 : knote_fdclose(p, new);
671 0 : closef(oldfp, p);
672 0 : }
673 :
674 0 : return (0);
675 0 : }
676 :
677 : void
678 0 : fdinsert(struct filedesc *fdp, int fd, int flags, struct file *fp)
679 : {
680 : struct file *fq;
681 :
682 0 : fdpassertlocked(fdp);
683 :
684 0 : mtx_enter(&fhdlk);
685 0 : if ((fp->f_iflags & FIF_INSERTED) == 0) {
686 0 : fp->f_iflags |= FIF_INSERTED;
687 0 : if ((fq = fdp->fd_ofiles[0]) != NULL) {
688 0 : LIST_INSERT_AFTER(fq, fp, f_list);
689 0 : } else {
690 0 : LIST_INSERT_HEAD(&filehead, fp, f_list);
691 : }
692 : }
693 0 : mtx_leave(&fhdlk);
694 :
695 0 : mtx_enter(&fdp->fd_fplock);
696 0 : KASSERT(fdp->fd_ofiles[fd] == NULL);
697 0 : fdp->fd_ofiles[fd] = fp;
698 0 : mtx_leave(&fdp->fd_fplock);
699 :
700 0 : fdp->fd_ofileflags[fd] |= (flags & UF_EXCLOSE);
701 0 : }
702 :
703 : void
704 0 : fdremove(struct filedesc *fdp, int fd)
705 : {
706 0 : fdpassertlocked(fdp);
707 :
708 : /*
709 : * Use `fd_fplock' to synchronize with fd_getfile() so that
710 : * the function no longer creates a new reference to the file.
711 : */
712 0 : mtx_enter(&fdp->fd_fplock);
713 0 : fdp->fd_ofiles[fd] = NULL;
714 0 : mtx_leave(&fdp->fd_fplock);
715 :
716 0 : fdp->fd_ofileflags[fd] = 0;
717 :
718 0 : fd_unused(fdp, fd);
719 0 : }
720 :
721 : int
722 0 : fdrelease(struct proc *p, int fd)
723 : {
724 0 : struct filedesc *fdp = p->p_fd;
725 : struct file *fp;
726 : int error;
727 :
728 0 : fdpassertlocked(fdp);
729 :
730 0 : fp = fd_getfile(fdp, fd);
731 0 : if (fp == NULL)
732 0 : return (EBADF);
733 0 : fdremove(fdp, fd);
734 0 : knote_fdclose(p, fd);
735 0 : fdpunlock(fdp);
736 0 : error = closef(fp, p);
737 0 : fdplock(fdp);
738 0 : return error;
739 0 : }
740 :
741 : /*
742 : * Close a file descriptor.
743 : */
744 : int
745 0 : sys_close(struct proc *p, void *v, register_t *retval)
746 : {
747 : struct sys_close_args /* {
748 : syscallarg(int) fd;
749 0 : } */ *uap = v;
750 0 : int fd = SCARG(uap, fd), error;
751 0 : struct filedesc *fdp = p->p_fd;
752 :
753 0 : fdplock(fdp);
754 0 : error = fdrelease(p, fd);
755 0 : fdpunlock(fdp);
756 :
757 0 : return (error);
758 : }
759 :
760 : /*
761 : * Return status information about a file descriptor.
762 : */
763 : int
764 0 : sys_fstat(struct proc *p, void *v, register_t *retval)
765 : {
766 : struct sys_fstat_args /* {
767 : syscallarg(int) fd;
768 : syscallarg(struct stat *) sb;
769 0 : } */ *uap = v;
770 0 : int fd = SCARG(uap, fd);
771 0 : struct filedesc *fdp = p->p_fd;
772 : struct file *fp;
773 0 : struct stat ub;
774 : int error;
775 :
776 0 : if ((fp = fd_getfile(fdp, fd)) == NULL)
777 0 : return (EBADF);
778 0 : error = (*fp->f_ops->fo_stat)(fp, &ub, p);
779 0 : FRELE(fp, p);
780 0 : if (error == 0) {
781 : /*
782 : * Don't let non-root see generation numbers
783 : * (for NFS security)
784 : */
785 0 : if (suser(p))
786 0 : ub.st_gen = 0;
787 0 : error = copyout((caddr_t)&ub, (caddr_t)SCARG(uap, sb),
788 : sizeof (ub));
789 0 : }
790 : #ifdef KTRACE
791 0 : if (error == 0 && KTRPOINT(p, KTR_STRUCT))
792 0 : ktrstat(p, &ub);
793 : #endif
794 0 : return (error);
795 0 : }
796 :
797 : /*
798 : * Return pathconf information about a file descriptor.
799 : */
800 : int
801 0 : sys_fpathconf(struct proc *p, void *v, register_t *retval)
802 : {
803 : struct sys_fpathconf_args /* {
804 : syscallarg(int) fd;
805 : syscallarg(int) name;
806 0 : } */ *uap = v;
807 0 : int fd = SCARG(uap, fd);
808 0 : struct filedesc *fdp = p->p_fd;
809 : struct file *fp;
810 : struct vnode *vp;
811 : int error;
812 :
813 0 : if ((fp = fd_getfile(fdp, fd)) == NULL)
814 0 : return (EBADF);
815 0 : switch (fp->f_type) {
816 : case DTYPE_PIPE:
817 : case DTYPE_SOCKET:
818 0 : if (SCARG(uap, name) != _PC_PIPE_BUF) {
819 : error = EINVAL;
820 0 : break;
821 : }
822 0 : *retval = PIPE_BUF;
823 : error = 0;
824 0 : break;
825 :
826 : case DTYPE_VNODE:
827 0 : vp = fp->f_data;
828 0 : vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
829 0 : error = VOP_PATHCONF(vp, SCARG(uap, name), retval);
830 0 : VOP_UNLOCK(vp);
831 0 : break;
832 :
833 : default:
834 : error = EOPNOTSUPP;
835 0 : break;
836 : }
837 0 : FRELE(fp, p);
838 0 : return (error);
839 0 : }
840 :
841 : /*
842 : * Allocate a file descriptor for the process.
843 : */
844 : int
845 0 : fdalloc(struct proc *p, int want, int *result)
846 : {
847 0 : struct filedesc *fdp = p->p_fd;
848 : int lim, last, i;
849 : u_int new, off;
850 :
851 0 : fdpassertlocked(fdp);
852 :
853 : /*
854 : * Search for a free descriptor starting at the higher
855 : * of want or fd_freefile. If that fails, consider
856 : * expanding the ofile array.
857 : */
858 : restart:
859 0 : lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
860 0 : last = min(fdp->fd_nfiles, lim);
861 0 : if ((i = want) < fdp->fd_freefile)
862 0 : i = fdp->fd_freefile;
863 0 : off = i >> NDENTRYSHIFT;
864 0 : new = find_next_zero(fdp->fd_himap, off,
865 0 : (last + NDENTRIES - 1) >> NDENTRYSHIFT);
866 0 : if (new != -1) {
867 0 : i = find_next_zero(&fdp->fd_lomap[new],
868 0 : new > off ? 0 : i & NDENTRYMASK,
869 : NDENTRIES);
870 0 : if (i == -1) {
871 : /*
872 : * Free file descriptor in this block was
873 : * below want, try again with higher want.
874 : */
875 0 : want = (new + 1) << NDENTRYSHIFT;
876 0 : goto restart;
877 : }
878 0 : i += (new << NDENTRYSHIFT);
879 0 : if (i < last) {
880 0 : fd_used(fdp, i);
881 0 : if (want <= fdp->fd_freefile)
882 0 : fdp->fd_freefile = i;
883 0 : *result = i;
884 0 : fdp->fd_ofileflags[i] = 0;
885 0 : if (ISSET(p->p_p->ps_flags, PS_PLEDGE))
886 0 : fdp->fd_ofileflags[i] |= UF_PLEDGED;
887 0 : return (0);
888 : }
889 : }
890 0 : if (fdp->fd_nfiles >= lim)
891 0 : return (EMFILE);
892 :
893 0 : return (ENOSPC);
894 0 : }
895 :
896 : void
897 0 : fdexpand(struct proc *p)
898 : {
899 0 : struct filedesc *fdp = p->p_fd;
900 : int nfiles, oldnfiles;
901 : size_t copylen;
902 : struct file **newofile, **oldofile;
903 : char *newofileflags;
904 : u_int *newhimap, *newlomap;
905 :
906 0 : fdpassertlocked(fdp);
907 :
908 0 : oldnfiles = fdp->fd_nfiles;
909 0 : oldofile = fdp->fd_ofiles;
910 :
911 : /*
912 : * No space in current array.
913 : */
914 0 : if (fdp->fd_nfiles < NDEXTENT)
915 0 : nfiles = NDEXTENT;
916 : else
917 0 : nfiles = 2 * fdp->fd_nfiles;
918 :
919 0 : newofile = mallocarray(nfiles, OFILESIZE, M_FILEDESC, M_WAITOK);
920 : /*
921 : * Allocate all required chunks before calling free(9) to make
922 : * sure that ``fd_ofiles'' stays valid if we go to sleep.
923 : */
924 0 : if (NDHISLOTS(nfiles) > NDHISLOTS(fdp->fd_nfiles)) {
925 0 : newhimap = mallocarray(NDHISLOTS(nfiles), sizeof(u_int),
926 : M_FILEDESC, M_WAITOK);
927 0 : newlomap = mallocarray(NDLOSLOTS(nfiles), sizeof(u_int),
928 : M_FILEDESC, M_WAITOK);
929 0 : }
930 0 : newofileflags = (char *) &newofile[nfiles];
931 :
932 : /*
933 : * Copy the existing ofile and ofileflags arrays
934 : * and zero the new portion of each array.
935 : */
936 0 : copylen = sizeof(struct file *) * fdp->fd_nfiles;
937 0 : memcpy(newofile, fdp->fd_ofiles, copylen);
938 0 : memset((char *)newofile + copylen, 0,
939 : nfiles * sizeof(struct file *) - copylen);
940 0 : copylen = sizeof(char) * fdp->fd_nfiles;
941 0 : memcpy(newofileflags, fdp->fd_ofileflags, copylen);
942 0 : memset(newofileflags + copylen, 0, nfiles * sizeof(char) - copylen);
943 :
944 0 : if (NDHISLOTS(nfiles) > NDHISLOTS(fdp->fd_nfiles)) {
945 0 : copylen = NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int);
946 0 : memcpy(newhimap, fdp->fd_himap, copylen);
947 0 : memset((char *)newhimap + copylen, 0,
948 : NDHISLOTS(nfiles) * sizeof(u_int) - copylen);
949 :
950 0 : copylen = NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int);
951 0 : memcpy(newlomap, fdp->fd_lomap, copylen);
952 0 : memset((char *)newlomap + copylen, 0,
953 : NDLOSLOTS(nfiles) * sizeof(u_int) - copylen);
954 :
955 0 : if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
956 0 : free(fdp->fd_himap, M_FILEDESC,
957 0 : NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int));
958 0 : free(fdp->fd_lomap, M_FILEDESC,
959 0 : NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int));
960 0 : }
961 0 : fdp->fd_himap = newhimap;
962 0 : fdp->fd_lomap = newlomap;
963 0 : }
964 :
965 0 : mtx_enter(&fdp->fd_fplock);
966 0 : fdp->fd_ofiles = newofile;
967 0 : mtx_leave(&fdp->fd_fplock);
968 :
969 0 : fdp->fd_ofileflags = newofileflags;
970 0 : fdp->fd_nfiles = nfiles;
971 :
972 0 : if (oldnfiles > NDFILE)
973 0 : free(oldofile, M_FILEDESC, oldnfiles * OFILESIZE);
974 0 : }
975 :
976 : /*
977 : * Create a new open file structure and allocate
978 : * a file descriptor for the process that refers to it.
979 : */
980 : int
981 0 : falloc(struct proc *p, struct file **resultfp, int *resultfd)
982 : {
983 : struct file *fp;
984 0 : int error, i;
985 :
986 0 : KASSERT(resultfp != NULL);
987 0 : KASSERT(resultfd != NULL);
988 :
989 0 : fdpassertlocked(p->p_fd);
990 : restart:
991 0 : if ((error = fdalloc(p, 0, &i)) != 0) {
992 0 : if (error == ENOSPC) {
993 0 : fdexpand(p);
994 0 : goto restart;
995 : }
996 0 : return (error);
997 : }
998 :
999 0 : fp = fnew(p);
1000 0 : if (fp == NULL) {
1001 0 : fd_unused(p->p_fd, i);
1002 0 : return (ENFILE);
1003 : }
1004 :
1005 0 : FREF(fp);
1006 0 : *resultfp = fp;
1007 0 : *resultfd = i;
1008 :
1009 0 : return (0);
1010 0 : }
1011 :
1012 : struct file *
1013 0 : fnew(struct proc *p)
1014 : {
1015 : struct file *fp;
1016 : int nfiles;
1017 :
1018 0 : nfiles = atomic_inc_int_nv(&numfiles);
1019 0 : if (nfiles > maxfiles) {
1020 0 : atomic_dec_int(&numfiles);
1021 0 : tablefull("file");
1022 0 : return (NULL);
1023 : }
1024 :
1025 0 : fp = pool_get(&file_pool, PR_WAITOK|PR_ZERO);
1026 : /*
1027 : * We need to block interrupts as long as `f_mtx' is being taken
1028 : * with and without the KERNEL_LOCK().
1029 : */
1030 0 : mtx_init(&fp->f_mtx, IPL_MPFLOOR);
1031 0 : fp->f_count = 1;
1032 0 : fp->f_cred = p->p_ucred;
1033 0 : crhold(fp->f_cred);
1034 :
1035 0 : return (fp);
1036 0 : }
1037 :
1038 : /*
1039 : * Build a new filedesc structure.
1040 : */
1041 : struct filedesc *
1042 0 : fdinit(void)
1043 : {
1044 : struct filedesc0 *newfdp;
1045 :
1046 0 : newfdp = pool_get(&fdesc_pool, PR_WAITOK|PR_ZERO);
1047 0 : rw_init(&newfdp->fd_fd.fd_lock, "fdlock");
1048 0 : mtx_init(&newfdp->fd_fd.fd_fplock, IPL_MPFLOOR);
1049 :
1050 : /* Create the file descriptor table. */
1051 0 : newfdp->fd_fd.fd_refcnt = 1;
1052 0 : newfdp->fd_fd.fd_cmask = S_IWGRP|S_IWOTH;
1053 0 : newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles;
1054 0 : newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
1055 0 : newfdp->fd_fd.fd_nfiles = NDFILE;
1056 0 : newfdp->fd_fd.fd_himap = newfdp->fd_dhimap;
1057 0 : newfdp->fd_fd.fd_lomap = newfdp->fd_dlomap;
1058 :
1059 0 : newfdp->fd_fd.fd_freefile = 0;
1060 0 : newfdp->fd_fd.fd_lastfile = 0;
1061 :
1062 0 : return (&newfdp->fd_fd);
1063 : }
1064 :
1065 : /*
1066 : * Share a filedesc structure.
1067 : */
1068 : struct filedesc *
1069 0 : fdshare(struct process *pr)
1070 : {
1071 0 : pr->ps_fd->fd_refcnt++;
1072 0 : return (pr->ps_fd);
1073 : }
1074 :
1075 : /*
1076 : * Copy a filedesc structure.
1077 : */
1078 : struct filedesc *
1079 0 : fdcopy(struct process *pr)
1080 : {
1081 0 : struct filedesc *newfdp, *fdp = pr->ps_fd;
1082 : int i;
1083 :
1084 0 : newfdp = fdinit();
1085 :
1086 0 : fdplock(fdp);
1087 0 : if (fdp->fd_cdir) {
1088 0 : vref(fdp->fd_cdir);
1089 0 : newfdp->fd_cdir = fdp->fd_cdir;
1090 0 : }
1091 0 : if (fdp->fd_rdir) {
1092 0 : vref(fdp->fd_rdir);
1093 0 : newfdp->fd_rdir = fdp->fd_rdir;
1094 0 : }
1095 :
1096 : /*
1097 : * If the number of open files fits in the internal arrays
1098 : * of the open file structure, use them, otherwise allocate
1099 : * additional memory for the number of descriptors currently
1100 : * in use.
1101 : */
1102 0 : if (fdp->fd_lastfile >= NDFILE) {
1103 : /*
1104 : * Compute the smallest multiple of NDEXTENT needed
1105 : * for the file descriptors currently in use,
1106 : * allowing the table to shrink.
1107 : */
1108 0 : i = fdp->fd_nfiles;
1109 0 : while (i >= 2 * NDEXTENT && i > fdp->fd_lastfile * 2)
1110 0 : i /= 2;
1111 0 : newfdp->fd_ofiles = mallocarray(i, OFILESIZE, M_FILEDESC,
1112 : M_WAITOK | M_ZERO);
1113 0 : newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
1114 0 : newfdp->fd_nfiles = i;
1115 0 : }
1116 0 : if (NDHISLOTS(newfdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
1117 0 : newfdp->fd_himap = mallocarray(NDHISLOTS(newfdp->fd_nfiles),
1118 : sizeof(u_int), M_FILEDESC, M_WAITOK | M_ZERO);
1119 0 : newfdp->fd_lomap = mallocarray(NDLOSLOTS(newfdp->fd_nfiles),
1120 : sizeof(u_int), M_FILEDESC, M_WAITOK | M_ZERO);
1121 0 : }
1122 0 : newfdp->fd_freefile = fdp->fd_freefile;
1123 0 : newfdp->fd_flags = fdp->fd_flags;
1124 0 : newfdp->fd_cmask = fdp->fd_cmask;
1125 :
1126 0 : for (i = 0; i <= fdp->fd_lastfile; i++) {
1127 0 : struct file *fp = fdp->fd_ofiles[i];
1128 :
1129 0 : if (fp != NULL) {
1130 : /*
1131 : * XXX Gruesome hack. If count gets too high, fail
1132 : * to copy an fd, since fdcopy()'s callers do not
1133 : * permit it to indicate failure yet.
1134 : * Meanwhile, kqueue files have to be
1135 : * tied to the process that opened them to enforce
1136 : * their internal consistency, so close them here.
1137 : */
1138 0 : if (fp->f_count >= FDUP_MAX_COUNT ||
1139 0 : fp->f_type == DTYPE_KQUEUE) {
1140 0 : if (i < newfdp->fd_freefile)
1141 0 : newfdp->fd_freefile = i;
1142 0 : continue;
1143 : }
1144 :
1145 0 : FREF(fp);
1146 0 : newfdp->fd_ofiles[i] = fp;
1147 0 : newfdp->fd_ofileflags[i] = fdp->fd_ofileflags[i];
1148 0 : fd_used(newfdp, i);
1149 0 : }
1150 0 : }
1151 0 : fdpunlock(fdp);
1152 :
1153 0 : return (newfdp);
1154 : }
1155 :
1156 : /*
1157 : * Release a filedesc structure.
1158 : */
1159 : void
1160 0 : fdfree(struct proc *p)
1161 : {
1162 0 : struct filedesc *fdp = p->p_fd;
1163 : struct file *fp;
1164 : int fd;
1165 :
1166 0 : if (--fdp->fd_refcnt > 0)
1167 0 : return;
1168 0 : for (fd = 0; fd <= fdp->fd_lastfile; fd++) {
1169 0 : fp = fdp->fd_ofiles[fd];
1170 0 : if (fp != NULL) {
1171 0 : fdp->fd_ofiles[fd] = NULL;
1172 0 : knote_fdclose(p, fd);
1173 : /* closef() expects a refcount of 2 */
1174 0 : FREF(fp);
1175 0 : (void) closef(fp, p);
1176 0 : }
1177 : }
1178 0 : p->p_fd = NULL;
1179 0 : if (fdp->fd_nfiles > NDFILE)
1180 0 : free(fdp->fd_ofiles, M_FILEDESC, fdp->fd_nfiles * OFILESIZE);
1181 0 : if (NDHISLOTS(fdp->fd_nfiles) > NDHISLOTS(NDFILE)) {
1182 0 : free(fdp->fd_himap, M_FILEDESC,
1183 0 : NDHISLOTS(fdp->fd_nfiles) * sizeof(u_int));
1184 0 : free(fdp->fd_lomap, M_FILEDESC,
1185 0 : NDLOSLOTS(fdp->fd_nfiles) * sizeof(u_int));
1186 0 : }
1187 0 : if (fdp->fd_cdir)
1188 0 : vrele(fdp->fd_cdir);
1189 0 : if (fdp->fd_rdir)
1190 0 : vrele(fdp->fd_rdir);
1191 0 : pool_put(&fdesc_pool, fdp);
1192 0 : }
1193 :
1194 : /*
1195 : * Internal form of close.
1196 : * Decrement reference count on file structure.
1197 : * Note: p may be NULL when closing a file
1198 : * that was being passed in a message.
1199 : *
1200 : * The fp must have its usecount bumped and will be FRELEd here.
1201 : */
1202 : int
1203 0 : closef(struct file *fp, struct proc *p)
1204 : {
1205 : struct filedesc *fdp;
1206 :
1207 0 : if (fp == NULL)
1208 0 : return (0);
1209 :
1210 0 : KASSERTMSG(fp->f_count >= 2, "count (%u) < 2", fp->f_count);
1211 :
1212 0 : atomic_dec_int(&fp->f_count);
1213 :
1214 : /*
1215 : * POSIX record locking dictates that any close releases ALL
1216 : * locks owned by this process. This is handled by setting
1217 : * a flag in the unlock to free ONLY locks obeying POSIX
1218 : * semantics, and not to free BSD-style file locks.
1219 : * If the descriptor was in a message, POSIX-style locks
1220 : * aren't passed with the descriptor.
1221 : */
1222 :
1223 0 : if (p && ((fdp = p->p_fd) != NULL) &&
1224 0 : (fdp->fd_flags & FD_ADVLOCK) &&
1225 0 : fp->f_type == DTYPE_VNODE) {
1226 0 : struct vnode *vp = fp->f_data;
1227 0 : struct flock lf;
1228 :
1229 0 : lf.l_whence = SEEK_SET;
1230 0 : lf.l_start = 0;
1231 0 : lf.l_len = 0;
1232 0 : lf.l_type = F_UNLCK;
1233 0 : (void) VOP_ADVLOCK(vp, fdp, F_UNLCK, &lf, F_POSIX);
1234 0 : }
1235 :
1236 0 : return (FRELE(fp, p));
1237 0 : }
1238 :
1239 : int
1240 0 : fdrop(struct file *fp, struct proc *p)
1241 : {
1242 : int error;
1243 :
1244 0 : KASSERTMSG(fp->f_count == 0, "count (%u) != 0", fp->f_count);
1245 :
1246 0 : mtx_enter(&fhdlk);
1247 0 : if (fp->f_iflags & FIF_INSERTED)
1248 0 : LIST_REMOVE(fp, f_list);
1249 0 : mtx_leave(&fhdlk);
1250 :
1251 0 : if (fp->f_ops)
1252 0 : error = (*fp->f_ops->fo_close)(fp, p);
1253 : else
1254 : error = 0;
1255 :
1256 0 : crfree(fp->f_cred);
1257 0 : atomic_dec_int(&numfiles);
1258 0 : pool_put(&file_pool, fp);
1259 :
1260 0 : return (error);
1261 : }
1262 :
1263 : /*
1264 : * Apply an advisory lock on a file descriptor.
1265 : *
1266 : * Just attempt to get a record lock of the requested type on
1267 : * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
1268 : */
1269 : int
1270 0 : sys_flock(struct proc *p, void *v, register_t *retval)
1271 : {
1272 : struct sys_flock_args /* {
1273 : syscallarg(int) fd;
1274 : syscallarg(int) how;
1275 0 : } */ *uap = v;
1276 0 : int fd = SCARG(uap, fd);
1277 0 : int how = SCARG(uap, how);
1278 0 : struct filedesc *fdp = p->p_fd;
1279 : struct file *fp;
1280 : struct vnode *vp;
1281 0 : struct flock lf;
1282 : int error;
1283 :
1284 0 : if ((fp = fd_getfile(fdp, fd)) == NULL)
1285 0 : return (EBADF);
1286 0 : if (fp->f_type != DTYPE_VNODE) {
1287 : error = EOPNOTSUPP;
1288 0 : goto out;
1289 : }
1290 0 : vp = fp->f_data;
1291 0 : lf.l_whence = SEEK_SET;
1292 0 : lf.l_start = 0;
1293 0 : lf.l_len = 0;
1294 0 : if (how & LOCK_UN) {
1295 0 : lf.l_type = F_UNLCK;
1296 0 : fp->f_iflags &= ~FIF_HASLOCK;
1297 0 : error = VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
1298 0 : goto out;
1299 : }
1300 0 : if (how & LOCK_EX)
1301 0 : lf.l_type = F_WRLCK;
1302 0 : else if (how & LOCK_SH)
1303 0 : lf.l_type = F_RDLCK;
1304 : else {
1305 : error = EINVAL;
1306 0 : goto out;
1307 : }
1308 0 : fp->f_iflags |= FIF_HASLOCK;
1309 0 : if (how & LOCK_NB)
1310 0 : error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK);
1311 : else
1312 0 : error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT);
1313 : out:
1314 0 : FRELE(fp, p);
1315 0 : return (error);
1316 0 : }
1317 :
1318 : /*
1319 : * File Descriptor pseudo-device driver (/dev/fd/).
1320 : *
1321 : * Opening minor device N dup()s the file (if any) connected to file
1322 : * descriptor N belonging to the calling process. Note that this driver
1323 : * consists of only the ``open()'' routine, because all subsequent
1324 : * references to this file will be direct to the other driver.
1325 : */
1326 : int
1327 0 : filedescopen(dev_t dev, int mode, int type, struct proc *p)
1328 : {
1329 :
1330 : /*
1331 : * XXX Kludge: set curproc->p_dupfd to contain the value of the
1332 : * the file descriptor being sought for duplication. The error
1333 : * return ensures that the vnode for this device will be released
1334 : * by vn_open. Open will detect this special error and take the
1335 : * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
1336 : * will simply report the error.
1337 : */
1338 0 : p->p_dupfd = minor(dev);
1339 0 : return (ENODEV);
1340 : }
1341 :
1342 : /*
1343 : * Duplicate the specified descriptor to a free descriptor.
1344 : */
1345 : int
1346 0 : dupfdopen(struct proc *p, int indx, int mode)
1347 : {
1348 0 : struct filedesc *fdp = p->p_fd;
1349 0 : int dupfd = p->p_dupfd;
1350 : struct file *wfp;
1351 :
1352 0 : fdpassertlocked(fdp);
1353 :
1354 : /*
1355 : * Assume that the filename was user-specified; applications do
1356 : * not tend to open /dev/fd/# when they can just call dup()
1357 : */
1358 0 : if ((p->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) {
1359 0 : if (p->p_descfd == 255)
1360 0 : return (EPERM);
1361 0 : if (p->p_descfd != dupfd)
1362 0 : return (EPERM);
1363 : }
1364 :
1365 : /*
1366 : * If the to-be-dup'd fd number is greater than the allowed number
1367 : * of file descriptors, or the fd to be dup'd has already been
1368 : * closed, reject. Note, there is no need to check for new == old
1369 : * because fd_getfile will return NULL if the file at indx is
1370 : * newly created by falloc.
1371 : */
1372 0 : if ((wfp = fd_getfile(fdp, dupfd)) == NULL)
1373 0 : return (EBADF);
1374 :
1375 : /*
1376 : * Check that the mode the file is being opened for is a
1377 : * subset of the mode of the existing descriptor.
1378 : */
1379 0 : if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) {
1380 0 : FRELE(wfp, p);
1381 0 : return (EACCES);
1382 : }
1383 0 : if (wfp->f_count >= FDUP_MAX_COUNT) {
1384 0 : FRELE(wfp, p);
1385 0 : return (EDEADLK);
1386 : }
1387 :
1388 0 : KASSERT(wfp->f_iflags & FIF_INSERTED);
1389 :
1390 0 : mtx_enter(&fdp->fd_fplock);
1391 0 : KASSERT(fdp->fd_ofiles[indx] == NULL);
1392 0 : fdp->fd_ofiles[indx] = wfp;
1393 0 : mtx_leave(&fdp->fd_fplock);
1394 :
1395 0 : fdp->fd_ofileflags[indx] = (fdp->fd_ofileflags[indx] & UF_EXCLOSE) |
1396 0 : (fdp->fd_ofileflags[dupfd] & ~UF_EXCLOSE);
1397 :
1398 0 : return (0);
1399 0 : }
1400 :
1401 : /*
1402 : * Close any files on exec?
1403 : */
1404 : void
1405 0 : fdcloseexec(struct proc *p)
1406 : {
1407 0 : struct filedesc *fdp = p->p_fd;
1408 : int fd;
1409 :
1410 0 : fdplock(fdp);
1411 0 : for (fd = 0; fd <= fdp->fd_lastfile; fd++) {
1412 0 : fdp->fd_ofileflags[fd] &= ~UF_PLEDGED;
1413 0 : if (fdp->fd_ofileflags[fd] & UF_EXCLOSE)
1414 0 : (void) fdrelease(p, fd);
1415 : }
1416 0 : fdpunlock(fdp);
1417 0 : }
1418 :
1419 : int
1420 0 : sys_closefrom(struct proc *p, void *v, register_t *retval)
1421 : {
1422 0 : struct sys_closefrom_args *uap = v;
1423 0 : struct filedesc *fdp = p->p_fd;
1424 : u_int startfd, i;
1425 :
1426 0 : startfd = SCARG(uap, fd);
1427 0 : fdplock(fdp);
1428 :
1429 0 : if (startfd > fdp->fd_lastfile) {
1430 0 : fdpunlock(fdp);
1431 0 : return (EBADF);
1432 : }
1433 :
1434 0 : for (i = startfd; i <= fdp->fd_lastfile; i++)
1435 0 : fdrelease(p, i);
1436 :
1437 0 : fdpunlock(fdp);
1438 0 : return (0);
1439 0 : }
1440 :
1441 : int
1442 0 : sys_getdtablecount(struct proc *p, void *v, register_t *retval)
1443 : {
1444 0 : *retval = p->p_fd->fd_openfd;
1445 0 : return (0);
1446 : }
|