]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/kern/kern_descrip.c
xnu-517.3.7.tar.gz
[apple/xnu.git] / bsd / kern / kern_descrip.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
26/*
27 * Copyright (c) 1982, 1986, 1989, 1991, 1993
28 * The Regents of the University of California. All rights reserved.
29 * (c) UNIX System Laboratories, Inc.
30 * All or some portions of this file are derived from material licensed
31 * to the University of California by American Telephone and Telegraph
32 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33 * the permission of UNIX System Laboratories, Inc.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 * @(#)kern_descrip.c 8.8 (Berkeley) 2/14/95
64 */
65
66#include <sys/param.h>
67#include <sys/systm.h>
68#include <sys/filedesc.h>
69#include <sys/kernel.h>
70#include <sys/vnode.h>
71#include <sys/proc.h>
72#include <sys/file.h>
73#include <sys/socket.h>
74#include <sys/socketvar.h>
75#include <sys/stat.h>
76#include <sys/ioctl.h>
77#include <sys/fcntl.h>
78#include <sys/malloc.h>
79#include <sys/syslog.h>
80#include <sys/unistd.h>
81#include <sys/resourcevar.h>
82#include <sys/aio_kern.h>
83#include <sys/kern_audit.h>
84
85#include <sys/mount.h>
86
87/*
88 * Descriptor management.
89 */
90struct filelist filehead; /* head of list of open files */
91int nfiles; /* actual number of open files */
92
93static int frele_internal(struct file *);
94
95/*
96 * System calls on descriptors.
97 */
98/* ARGSUSED */
99int
100getdtablesize(p, uap, retval)
101 struct proc *p;
102 void *uap;
103 register_t *retval;
104{
105 *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
106 return (0);
107}
108
109/* ARGSUSED */
110int
111ogetdtablesize(p, uap, retval)
112 struct proc *p;
113 void *uap;
114 register_t *retval;
115{
116 *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, NOFILE);
117 return (0);
118}
119
120static __inline__
121void _fdrelse(fdp, fd)
122 register struct filedesc *fdp;
123 register int fd;
124{
125 if (fd < fdp->fd_freefile)
126 fdp->fd_freefile = fd;
127#if DIAGNOSTIC
128 if (fd > fdp->fd_lastfile)
129 panic("fdrelse: fd_lastfile inconsistent");
130#endif
131 fdp->fd_ofiles[fd] = NULL;
132 fdp->fd_ofileflags[fd] = 0;
133 while ((fd = fdp->fd_lastfile) > 0 &&
134 fdp->fd_ofiles[fd] == NULL &&
135 !(fdp->fd_ofileflags[fd] & UF_RESERVED))
136 fdp->fd_lastfile--;
137}
138
139/*
140 * Duplicate a file descriptor.
141 */
142struct dup_args {
143 u_int fd;
144};
145/* ARGSUSED */
146int
147dup(p, uap, retval)
148 struct proc *p;
149 struct dup_args *uap;
150 register_t *retval;
151{
152 register struct filedesc *fdp = p->p_fd;
153 register int old = uap->fd;
154 int new, error;
155
156 if ((u_int)old >= fdp->fd_nfiles ||
157 fdp->fd_ofiles[old] == NULL ||
158 (fdp->fd_ofileflags[old] & UF_RESERVED))
159 return (EBADF);
160 if (error = fdalloc(p, 0, &new))
161 return (error);
162 return (finishdup(fdp, old, new, retval));
163}
164
165/*
166 * Duplicate a file descriptor to a particular value.
167 */
168struct dup2_args {
169 u_int from;
170 u_int to;
171};
172/* ARGSUSED */
173int
174dup2(p, uap, retval)
175 struct proc *p;
176 struct dup2_args *uap;
177 register_t *retval;
178{
179 register struct filedesc *fdp = p->p_fd;
180 register int old = uap->from, new = uap->to;
181 int i, error;
182
183 if ((u_int)old >= fdp->fd_nfiles ||
184 fdp->fd_ofiles[old] == NULL ||
185 (fdp->fd_ofileflags[old] & UF_RESERVED) ||
186 (u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
187 (u_int)new >= maxfiles)
188 return (EBADF);
189 if (old == new) {
190 *retval = new;
191 return (0);
192 }
193 if ((u_int)new >= fdp->fd_nfiles) {
194 if (error = fdalloc(p, new, &i))
195 return (error);
196 if (new != i) {
197 _fdrelse(fdp, i);
198 goto closeit;
199 }
200 } else {
201 struct file **fpp;
202 char flags;
203closeit:
204 if ((flags = fdp->fd_ofileflags[new]) & UF_RESERVED)
205 return (EBADF);
206 fdp->fd_ofileflags[new] = (flags & ~UF_MAPPED) | UF_RESERVED;
207 /*
208 * dup2() must succeed even if the close has an error.
209 */
210 if (*(fpp = &fdp->fd_ofiles[new])) {
211 struct file *fp = *fpp;
212
213 *fpp = NULL;
214 (void) closef(fp, p);
215 }
216 }
217 return (finishdup(fdp, old, new, retval));
218}
219
220/*
221 * The file control system call.
222 */
223struct fcntl_args {
224 int fd;
225 int cmd;
226 int arg;
227};
228/* ARGSUSED */
229int
230fcntl(p, uap, retval)
231 struct proc *p;
232 register struct fcntl_args *uap;
233 register_t *retval;
234{
235 int fd = uap->fd;
236 register struct filedesc *fdp = p->p_fd;
237 register struct file *fp;
238 register char *pop;
239 struct vnode *vp, *devvp;
240 int i, tmp, error, error2, flg = F_POSIX;
241 struct flock fl;
242 fstore_t alloc_struct; /* structure for allocate command */
243 u_int32_t alloc_flags = 0;
244 off_t offset; /* used for F_SETSIZE */
245 int newmin;
246 struct radvisory ra_struct;
247 fbootstraptransfer_t fbt_struct; /* for F_READBOOTSTRAP and F_WRITEBOOTSTRAP */
248 struct log2phys l2p_struct; /* structure for allocate command */
249 daddr_t lbn, bn;
250 int devBlockSize = 0;
251
252 AUDIT_ARG(fd, uap->fd);
253 AUDIT_ARG(cmd, uap->cmd);
254 if ((u_int)fd >= fdp->fd_nfiles ||
255 (fp = fdp->fd_ofiles[fd]) == NULL ||
256 (fdp->fd_ofileflags[fd] & UF_RESERVED))
257 return (EBADF);
258 pop = &fdp->fd_ofileflags[fd];
259
260 switch (uap->cmd) {
261
262 case F_DUPFD:
263 newmin = (long)uap->arg;
264 if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
265 (u_int)newmin >= maxfiles)
266 return (EINVAL);
267 if (error = fdalloc(p, newmin, &i))
268 return (error);
269 return (finishdup(fdp, fd, i, retval));
270
271 case F_GETFD:
272 *retval = (*pop & UF_EXCLOSE)? 1 : 0;
273 return (0);
274
275 case F_SETFD:
276 *pop = (*pop &~ UF_EXCLOSE) |
277 ((long)(uap->arg) & 1)? UF_EXCLOSE : 0;
278 return (0);
279
280 case F_GETFL:
281 *retval = OFLAGS(fp->f_flag);
282 return (0);
283
284 case F_SETFL:
285 fp->f_flag &= ~FCNTLFLAGS;
286 fp->f_flag |= FFLAGS((long)uap->arg) & FCNTLFLAGS;
287 tmp = fp->f_flag & FNONBLOCK;
288 error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p);
289 if (error)
290 return (error);
291 tmp = fp->f_flag & FASYNC;
292 error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, p);
293 if (!error)
294 return (0);
295 fp->f_flag &= ~FNONBLOCK;
296 tmp = 0;
297 (void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p);
298 return (error);
299
300 case F_GETOWN:
301 if (fp->f_type == DTYPE_SOCKET) {
302 *retval = ((struct socket *)fp->f_data)->so_pgid;
303 return (0);
304 }
305 error = fo_ioctl(fp, (int)TIOCGPGRP, (caddr_t)retval, p);
306 *retval = -*retval;
307 return (error);
308
309 case F_SETOWN:
310 if (fp->f_type == DTYPE_SOCKET) {
311 ((struct socket *)fp->f_data)->so_pgid =
312 (long)uap->arg;
313 return (0);
314 }
315 if ((long)uap->arg <= 0) {
316 uap->arg = (int)(-(long)(uap->arg));
317 } else {
318 struct proc *p1 = pfind((long)uap->arg);
319 if (p1 == 0)
320 return (ESRCH);
321 uap->arg = (int)p1->p_pgrp->pg_id;
322 }
323 return (fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p));
324
325 case F_SETLKW:
326 flg |= F_WAIT;
327 /* Fall into F_SETLK */
328
329 case F_SETLK:
330 if (fp->f_type != DTYPE_VNODE)
331 return (EBADF);
332 vp = (struct vnode *)fp->f_data;
333 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
334 /* Copy in the lock structure */
335 error = copyin((caddr_t)uap->arg, (caddr_t)&fl,
336 sizeof (fl));
337 if (error)
338 return (error);
339 if (fl.l_whence == SEEK_CUR)
340 fl.l_start += fp->f_offset;
341 switch (fl.l_type) {
342
343 case F_RDLCK:
344 if ((fp->f_flag & FREAD) == 0)
345 return (EBADF);
346 p->p_flag |= P_ADVLOCK;
347 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
348
349 case F_WRLCK:
350 if ((fp->f_flag & FWRITE) == 0)
351 return (EBADF);
352 p->p_flag |= P_ADVLOCK;
353 return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg));
354
355 case F_UNLCK:
356 return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl,
357 F_POSIX));
358
359 default:
360 return (EINVAL);
361 }
362
363 case F_GETLK:
364 if (fp->f_type != DTYPE_VNODE)
365 return (EBADF);
366 vp = (struct vnode *)fp->f_data;
367 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
368 /* Copy in the lock structure */
369 error = copyin((caddr_t)uap->arg, (caddr_t)&fl,
370 sizeof (fl));
371 if (error)
372 return (error);
373 if (fl.l_whence == SEEK_CUR)
374 fl.l_start += fp->f_offset;
375 if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX))
376 return (error);
377 return (copyout((caddr_t)&fl, (caddr_t)uap->arg,
378 sizeof (fl)));
379
380 case F_PREALLOCATE:
381 if (fp->f_type != DTYPE_VNODE)
382 return (EBADF);
383
384 /* make sure that we have write permission */
385 if ((fp->f_flag & FWRITE) == 0)
386 return (EBADF);
387
388 error = copyin((caddr_t)uap->arg, (caddr_t)&alloc_struct,
389 sizeof (alloc_struct));
390 if (error)
391 return (error);
392
393 /* now set the space allocated to 0 */
394 alloc_struct.fst_bytesalloc = 0;
395
396 /*
397 * Do some simple parameter checking
398 */
399
400 /* set up the flags */
401
402 alloc_flags |= PREALLOCATE;
403
404 if (alloc_struct.fst_flags & F_ALLOCATECONTIG)
405 alloc_flags |= ALLOCATECONTIG;
406
407 if (alloc_struct.fst_flags & F_ALLOCATEALL)
408 alloc_flags |= ALLOCATEALL;
409
410 /*
411 * Do any position mode specific stuff. The only
412 * position mode supported now is PEOFPOSMODE
413 */
414
415 switch (alloc_struct.fst_posmode) {
416
417 case F_PEOFPOSMODE:
418 if (alloc_struct.fst_offset != 0)
419 return (EINVAL);
420
421 alloc_flags |= ALLOCATEFROMPEOF;
422 break;
423
424 case F_VOLPOSMODE:
425 if (alloc_struct.fst_offset <= 0)
426 return (EINVAL);
427
428 alloc_flags |= ALLOCATEFROMVOL;
429 break;
430
431 default:
432 return(EINVAL);
433 }
434
435 vp = (struct vnode *)fp->f_data;
436
437 /* lock the vnode and call allocate to get the space */
438 error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
439 if (error)
440 return (error);
441 error = VOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags,
442 &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset,
443 fp->f_cred, p);
444 VOP_UNLOCK(vp, 0, p);
445
446 if (error2 = copyout((caddr_t)&alloc_struct,
447 (caddr_t)uap->arg,
448 sizeof (alloc_struct))) {
449 if (error)
450 return(error);
451 else
452 return(error2);
453 }
454 return(error);
455
456 case F_SETSIZE:
457 if (fp->f_type != DTYPE_VNODE)
458 return (EBADF);
459
460 error = copyin((caddr_t)uap->arg, (caddr_t)&offset,
461 sizeof (off_t));
462 if (error)
463 return (error);
464
465 /*
466 * Make sure that we are root. Growing a file
467 * without zero filling the data is a security hole
468 * root would have access anyway so we'll allow it
469 */
470
471 if (!is_suser())
472 return (EACCES);
473
474 vp = (struct vnode *)fp->f_data;
475
476 /* lock the vnode and call allocate to get the space */
477 error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
478 if (error)
479 return (error);
480 error = VOP_TRUNCATE(vp,offset,IO_NOZEROFILL,fp->f_cred,p);
481 VOP_UNLOCK(vp,0,p);
482 return(error);
483
484 case F_RDAHEAD:
485 if (fp->f_type != DTYPE_VNODE)
486 return (EBADF);
487 vp = (struct vnode *)fp->f_data;
488
489 simple_lock(&vp->v_interlock);
490 if (uap->arg)
491 vp->v_flag &= ~VRAOFF;
492 else
493 vp->v_flag |= VRAOFF;
494 simple_unlock(&vp->v_interlock);
495 return (0);
496
497 case F_NOCACHE:
498 if (fp->f_type != DTYPE_VNODE)
499 return (EBADF);
500 vp = (struct vnode *)fp->f_data;
501
502 simple_lock(&vp->v_interlock);
503 if (uap->arg)
504 vp->v_flag |= VNOCACHE_DATA;
505 else
506 vp->v_flag &= ~VNOCACHE_DATA;
507 simple_unlock(&vp->v_interlock);
508 return (0);
509
510 case F_RDADVISE:
511 if (fp->f_type != DTYPE_VNODE)
512 return (EBADF);
513 vp = (struct vnode *)fp->f_data;
514
515 if (error = copyin((caddr_t)uap->arg,
516 (caddr_t)&ra_struct, sizeof (ra_struct)))
517 return(error);
518 return (VOP_IOCTL(vp, 1, (caddr_t)&ra_struct, 0, fp->f_cred, p));
519
520 case F_CHKCLEAN:
521 /*
522 * used by regression test to determine if
523 * all the dirty pages (via write) have been cleaned
524 * after a call to 'fsysnc'.
525 */
526 if (fp->f_type != DTYPE_VNODE)
527 return (EBADF);
528 vp = (struct vnode *)fp->f_data;
529
530 return (VOP_IOCTL(vp, 5, 0, 0, fp->f_cred, p));
531
532 case F_READBOOTSTRAP:
533 case F_WRITEBOOTSTRAP:
534 if (fp->f_type != DTYPE_VNODE)
535 return (EBADF);
536
537 error = copyin((caddr_t)uap->arg, (caddr_t)&fbt_struct,
538 sizeof (fbt_struct));
539 if (error)
540 return (error);
541
542 if (uap->cmd == F_WRITEBOOTSTRAP) {
543 /*
544 * Make sure that we are root. Updating the
545 * bootstrap on a disk could be a security hole
546 */
547 if (!is_suser())
548 return (EACCES);
549 }
550
551 vp = (struct vnode *)fp->f_data;
552 if (vp->v_tag != VT_HFS) /* XXX */
553 error = EINVAL;
554 else {
555 /* lock the vnode and call VOP_IOCTL to handle the I/O */
556 error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
557 if (error)
558 return (error);
559 error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2,
560 (caddr_t)&fbt_struct, 0, fp->f_cred, p);
561 VOP_UNLOCK(vp,0,p);
562 }
563 return(error);
564
565 case F_LOG2PHYS:
566 if (fp->f_type != DTYPE_VNODE)
567 return (EBADF);
568 vp = (struct vnode *)fp->f_data;
569 error = vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, p);
570 if (error)
571 return (error);
572 error = VOP_OFFTOBLK(vp, fp->f_offset, &lbn);
573 if (error)
574 return (error);
575 error = VOP_BLKTOOFF(vp, lbn, &offset);
576 if (error)
577 return (error);
578 error = VOP_BMAP(vp, lbn, &devvp, &bn, 0);
579 VOP_DEVBLOCKSIZE(devvp, &devBlockSize);
580 VOP_UNLOCK(vp, 0, p);
581 if (!error) {
582 l2p_struct.l2p_flags = 0; /* for now */
583 l2p_struct.l2p_contigbytes = 0; /* for now */
584 l2p_struct.l2p_devoffset = bn * devBlockSize;
585 l2p_struct.l2p_devoffset += fp->f_offset - offset;
586 error = copyout((caddr_t)&l2p_struct,
587 (caddr_t)uap->arg,
588 sizeof (l2p_struct));
589 }
590 return (error);
591
592 case F_GETPATH: {
593 char *pathbuf;
594 int len;
595 extern int vn_getpath(struct vnode *vp, char *pathbuf, int *len);
596
597 if (fp->f_type != DTYPE_VNODE)
598 return (EBADF);
599 vp = (struct vnode *)fp->f_data;
600
601 len = MAXPATHLEN;
602 MALLOC(pathbuf, char *, len, M_TEMP, M_WAITOK);
603 error = vn_getpath(vp, pathbuf, &len);
604 if (error == 0)
605 error = copyout((caddr_t)pathbuf, (caddr_t)uap->arg, len);
606 FREE(pathbuf, M_TEMP);
607 return error;
608 }
609
610 case F_FULLFSYNC: {
611 if (fp->f_type != DTYPE_VNODE)
612 return (EBADF);
613 vp = (struct vnode *)fp->f_data;
614
615 return (VOP_IOCTL(vp, 6, (caddr_t)NULL, 0, fp->f_cred, p));
616 }
617
618 default:
619 return (EINVAL);
620 }
621 /* NOTREACHED */
622}
623
624/*
625 * Common code for dup, dup2, and fcntl(F_DUPFD).
626 */
627int
628finishdup(fdp, old, new, retval)
629 register struct filedesc *fdp;
630 register int old, new;
631 register_t *retval;
632{
633 register struct file *fp;
634
635 if ((fp = fdp->fd_ofiles[old]) == NULL ||
636 (fdp->fd_ofileflags[old] & UF_RESERVED)) {
637 _fdrelse(fdp, new);
638 return (EBADF);
639 }
640 fdp->fd_ofiles[new] = fp;
641 fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
642 (void)fref(fp);
643 if (new > fdp->fd_lastfile)
644 fdp->fd_lastfile = new;
645 *retval = new;
646 return (0);
647}
648
649/*
650 * Close a file descriptor.
651 */
652struct close_args {
653 int fd;
654};
655/* ARGSUSED */
656int
657close(p, uap, retval)
658 struct proc *p;
659 struct close_args *uap;
660 register_t *retval;
661{
662 int fd = uap->fd;
663 register struct filedesc *fdp = p->p_fd;
664 register struct file *fp;
665
666 if ((u_int)fd >= fdp->fd_nfiles ||
667 (fp = fdp->fd_ofiles[fd]) == NULL ||
668 (fdp->fd_ofileflags[fd] & UF_RESERVED))
669 return (EBADF);
670
671 /* Keep people from using the filedesc while we are closing it */
672 fdp->fd_ofileflags[fd] |= UF_RESERVED;
673
674 /* cancel all async IO requests that can be cancelled. */
675 _aio_close( p, fd );
676
677 if (fd < fdp->fd_knlistsize)
678 knote_fdclose(p, fd);
679
680 _fdrelse(fdp, fd);
681 return (closef(fp, p));
682}
683
684/*
685 * Return status information about a file descriptor.
686 */
687struct fstat_args {
688 int fd;
689 struct stat *sb;
690};
691/* ARGSUSED */
692int
693fstat(p, uap, retval)
694 struct proc *p;
695 register struct fstat_args *uap;
696 register_t *retval;
697{
698 int fd = uap->fd;
699 register struct filedesc *fdp = p->p_fd;
700 register struct file *fp;
701 struct stat ub;
702 int error;
703
704 AUDIT_ARG(fd, uap->fd);
705 if ((u_int)fd >= fdp->fd_nfiles ||
706 (fp = fdp->fd_ofiles[fd]) == NULL ||
707 (fdp->fd_ofileflags[fd] & UF_RESERVED))
708 return (EBADF);
709 switch (fp->f_type) {
710
711 case DTYPE_VNODE:
712 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
713 if (error == 0) {
714 AUDIT_ARG(vnpath, (struct vnode *)fp->f_data, ARG_VNODE1);
715 }
716 break;
717
718 case DTYPE_SOCKET:
719 error = soo_stat((struct socket *)fp->f_data, &ub);
720 break;
721
722 case DTYPE_PSXSHM:
723 error = pshm_stat((void *)fp->f_data, &ub);
724 break;
725
726 case DTYPE_KQUEUE:
727 error = kqueue_stat(fp, &ub, p);
728 break;
729
730 default:
731 panic("fstat");
732 /*NOTREACHED*/
733 }
734 if (error == 0)
735 error = copyout((caddr_t)&ub, (caddr_t)uap->sb,
736 sizeof (ub));
737 return (error);
738}
739
740#if COMPAT_43
741/*
742 * Return status information about a file descriptor.
743 */
744struct ofstat_args {
745 int fd;
746 struct ostat *sb;
747};
748/* ARGSUSED */
749ofstat(p, uap, retval)
750 struct proc *p;
751 register struct ofstat_args *uap;
752 register_t *retval;
753{
754 int fd = uap->fd;
755 register struct filedesc *fdp = p->p_fd;
756 register struct file *fp;
757 struct stat ub;
758 struct ostat oub;
759 int error;
760
761 if ((u_int)fd >= fdp->fd_nfiles ||
762 (fp = fdp->fd_ofiles[fd]) == NULL ||
763 (fdp->fd_ofileflags[fd] & UF_RESERVED))
764 return (EBADF);
765 switch (fp->f_type) {
766
767 case DTYPE_VNODE:
768 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
769 break;
770
771 case DTYPE_SOCKET:
772 error = soo_stat((struct socket *)fp->f_data, &ub);
773 break;
774
775 default:
776 panic("ofstat");
777 /*NOTREACHED*/
778 }
779 cvtstat(&ub, &oub);
780 if (error == 0)
781 error = copyout((caddr_t)&oub, (caddr_t)uap->sb,
782 sizeof (oub));
783 return (error);
784}
785#endif /* COMPAT_43 */
786
787/*
788 * Return pathconf information about a file descriptor.
789 */
790struct fpathconf_args {
791 int fd;
792 int name;
793};
794/* ARGSUSED */
795fpathconf(p, uap, retval)
796 struct proc *p;
797 register struct fpathconf_args *uap;
798 register_t *retval;
799{
800 int fd = uap->fd;
801 struct filedesc *fdp = p->p_fd;
802 struct file *fp;
803 struct vnode *vp;
804
805 AUDIT_ARG(fd, uap->fd);
806 if ((u_int)fd >= fdp->fd_nfiles ||
807 (fp = fdp->fd_ofiles[fd]) == NULL ||
808 (fdp->fd_ofileflags[fd] & UF_RESERVED))
809 return (EBADF);
810 switch (fp->f_type) {
811
812 case DTYPE_SOCKET:
813 if (uap->name != _PC_PIPE_BUF)
814 return (EINVAL);
815 *retval = PIPE_BUF;
816 return (0);
817
818 case DTYPE_VNODE:
819 vp = (struct vnode *)fp->f_data;
820 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
821
822 return (VOP_PATHCONF(vp, uap->name, retval));
823
824 default:
825 panic("fpathconf");
826 }
827 /*NOTREACHED*/
828}
829
830/*
831 * Allocate a file descriptor for the process.
832 */
833int fdexpand;
834
835int
836fdalloc(p, want, result)
837 struct proc *p;
838 int want;
839 int *result;
840{
841 register struct filedesc *fdp = p->p_fd;
842 register int i;
843 int lim, last, nfiles, oldnfiles;
844 struct file **newofiles, **ofiles;
845 char *newofileflags, *ofileflags;
846
847 /*
848 * Search for a free descriptor starting at the higher
849 * of want or fd_freefile. If that fails, consider
850 * expanding the ofile array.
851 */
852 lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
853 for (;;) {
854 last = min(fdp->fd_nfiles, lim);
855 if ((i = want) < fdp->fd_freefile)
856 i = fdp->fd_freefile;
857 ofiles = &fdp->fd_ofiles[i];
858 ofileflags = &fdp->fd_ofileflags[i];
859 for (; i < last; i++) {
860 if (*ofiles == NULL && !(*ofileflags & UF_RESERVED)) {
861 *ofileflags = UF_RESERVED;
862 if (i > fdp->fd_lastfile)
863 fdp->fd_lastfile = i;
864 if (want <= fdp->fd_freefile)
865 fdp->fd_freefile = i;
866 *result = i;
867 return (0);
868 }
869 ofiles++; ofileflags++;
870 }
871
872 /*
873 * No space in current array. Expand?
874 */
875 if (fdp->fd_nfiles >= lim)
876 return (EMFILE);
877 if (fdp->fd_nfiles < NDEXTENT)
878 nfiles = NDEXTENT;
879 else
880 nfiles = 2 * fdp->fd_nfiles;
881 /* Enforce lim */
882 if (nfiles > lim)
883 nfiles = lim;
884 MALLOC_ZONE(newofiles, struct file **,
885 nfiles * OFILESIZE, M_OFILETABL, M_WAITOK);
886 if (fdp->fd_nfiles >= nfiles) {
887 FREE_ZONE(newofiles, nfiles * OFILESIZE, M_OFILETABL);
888 continue;
889 }
890 newofileflags = (char *) &newofiles[nfiles];
891 /*
892 * Copy the existing ofile and ofileflags arrays
893 * and zero the new portion of each array.
894 */
895 oldnfiles = fdp->fd_nfiles;
896 (void) memcpy(newofiles, fdp->fd_ofiles,
897 oldnfiles * sizeof *fdp->fd_ofiles);
898 (void) memset(&newofiles[oldnfiles], 0,
899 (nfiles - oldnfiles) * sizeof *fdp->fd_ofiles);
900
901 (void) memcpy(newofileflags, fdp->fd_ofileflags,
902 oldnfiles * sizeof *fdp->fd_ofileflags);
903 (void) memset(&newofileflags[oldnfiles], 0,
904 (nfiles - oldnfiles) *
905 sizeof *fdp->fd_ofileflags);
906 ofiles = fdp->fd_ofiles;
907 fdp->fd_ofiles = newofiles;
908 fdp->fd_ofileflags = newofileflags;
909 fdp->fd_nfiles = nfiles;
910 FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL);
911 fdexpand++;
912 }
913}
914
915/*
916 * Check to see whether n user file descriptors
917 * are available to the process p.
918 */
919int
920fdavail(p, n)
921 struct proc *p;
922 register int n;
923{
924 register struct filedesc *fdp = p->p_fd;
925 register struct file **fpp;
926 register char *flags;
927 register int i, lim;
928
929 lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
930 if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
931 return (1);
932 fpp = &fdp->fd_ofiles[fdp->fd_freefile];
933 flags = &fdp->fd_ofileflags[fdp->fd_freefile];
934 for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++)
935 if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0)
936 return (1);
937 return (0);
938}
939
940void
941fdrelse(p, fd)
942 struct proc *p;
943 int fd;
944{
945 _fdrelse(p->p_fd, fd);
946}
947
948int
949fdgetf(p, fd, resultfp)
950 register struct proc *p;
951 register int fd;
952 struct file **resultfp;
953{
954 register struct filedesc *fdp = p->p_fd;
955 struct file *fp;
956
957 if ((u_int)fd >= fdp->fd_nfiles ||
958 (fp = fdp->fd_ofiles[fd]) == NULL ||
959 (fdp->fd_ofileflags[fd] & UF_RESERVED))
960 return (EBADF);
961
962 if (resultfp)
963 *resultfp = fp;
964 return (0);
965}
966
967/*
968 * Create a new open file structure and allocate
969 * a file decriptor for the process that refers to it.
970 */
971int
972falloc(p, resultfp, resultfd)
973 register struct proc *p;
974 struct file **resultfp;
975 int *resultfd;
976{
977 register struct file *fp, *fq;
978 int error, i;
979
980 if (error = fdalloc(p, 0, &i))
981 return (error);
982 if (nfiles >= maxfiles) {
983 tablefull("file");
984 return (ENFILE);
985 }
986 /*
987 * Allocate a new file descriptor.
988 * If the process has file descriptor zero open, add to the list
989 * of open files at that point, otherwise put it at the front of
990 * the list of open files.
991 */
992 nfiles++;
993 MALLOC_ZONE(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
994 bzero(fp, sizeof(struct file));
995 p->p_fd->fd_ofiles[i] = fp;
996 fp->f_count = 1;
997 fp->f_cred = p->p_ucred;
998 crhold(fp->f_cred);
999 if (resultfp)
1000 *resultfp = fp;
1001 if (resultfd)
1002 *resultfd = i;
1003 if (fq = p->p_fd->fd_ofiles[0]) {
1004 LIST_INSERT_AFTER(fq, fp, f_list);
1005 } else {
1006 LIST_INSERT_HEAD(&filehead, fp, f_list);
1007 }
1008 return (0);
1009}
1010
1011/*
1012 * Free a file structure.
1013 */
1014void
1015ffree(fp)
1016 register struct file *fp;
1017{
1018 register struct file *fq;
1019 struct ucred *cred;
1020
1021 LIST_REMOVE(fp, f_list);
1022 cred = fp->f_cred;
1023 if (cred != NOCRED) {
1024 fp->f_cred = NOCRED;
1025 crfree(cred);
1026 }
1027
1028 nfiles--;
1029 memset(fp, 0xff, sizeof *fp);
1030 fp->f_count = (short)0xffff;
1031
1032 FREE_ZONE(fp, sizeof *fp, M_FILE);
1033}
1034
1035void
1036fdexec(p)
1037 struct proc *p;
1038{
1039 register struct filedesc *fdp = p->p_fd;
1040 register int i = fdp->fd_lastfile;
1041 register struct file **fpp = &fdp->fd_ofiles[i];
1042 register char *flags = &fdp->fd_ofileflags[i];
1043
1044 while (i >= 0) {
1045 if ((*flags & (UF_RESERVED|UF_EXCLOSE)) == UF_EXCLOSE) {
1046 register struct file *fp = *fpp;
1047
1048 if (i < fdp->fd_knlistsize)
1049 knote_fdclose(p, i);
1050
1051 *fpp = NULL; *flags = 0;
1052 if (i == fdp->fd_lastfile && i > 0)
1053 fdp->fd_lastfile--;
1054 closef(fp, p);
1055 }
1056 else
1057 *flags &= ~UF_MAPPED;
1058
1059 i--; fpp--; flags--;
1060 }
1061}
1062
1063/*
1064 * Copy a filedesc structure.
1065 */
1066struct filedesc *
1067fdcopy(p)
1068 struct proc *p;
1069{
1070 register struct filedesc *newfdp, *fdp = p->p_fd;
1071 register int i;
1072
1073 MALLOC_ZONE(newfdp, struct filedesc *,
1074 sizeof *newfdp, M_FILEDESC, M_WAITOK);
1075 (void) memcpy(newfdp, fdp, sizeof *newfdp);
1076 VREF(newfdp->fd_cdir);
1077 if (newfdp->fd_rdir)
1078 VREF(newfdp->fd_rdir);
1079 newfdp->fd_refcnt = 1;
1080
1081 /*
1082 * If the number of open files fits in the internal arrays
1083 * of the open file structure, use them, otherwise allocate
1084 * additional memory for the number of descriptors currently
1085 * in use.
1086 */
1087 if (newfdp->fd_lastfile < NDFILE)
1088 i = NDFILE;
1089 else {
1090 /*
1091 * Compute the smallest multiple of NDEXTENT needed
1092 * for the file descriptors currently in use,
1093 * allowing the table to shrink.
1094 */
1095 i = newfdp->fd_nfiles;
1096 while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
1097 i /= 2;
1098 }
1099 MALLOC_ZONE(newfdp->fd_ofiles, struct file **,
1100 i * OFILESIZE, M_OFILETABL, M_WAITOK);
1101 newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
1102 newfdp->fd_nfiles = i;
1103 if (fdp->fd_nfiles > 0) {
1104 register struct file **fpp;
1105 register char *flags;
1106
1107 (void) memcpy(newfdp->fd_ofiles, fdp->fd_ofiles,
1108 i * sizeof *fdp->fd_ofiles);
1109 (void) memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags,
1110 i * sizeof *fdp->fd_ofileflags);
1111
1112 /*
1113 * kq descriptors cannot be copied.
1114 */
1115 if (newfdp->fd_knlistsize != -1) {
1116 fpp = &newfdp->fd_ofiles[newfdp->fd_lastfile];
1117 for (i = newfdp->fd_lastfile; i >= 0; i--, fpp--) {
1118 if (*fpp != NULL && (*fpp)->f_type == DTYPE_KQUEUE) {
1119 *fpp = NULL;
1120 if (i < newfdp->fd_freefile)
1121 newfdp->fd_freefile = i;
1122 }
1123 if (*fpp == NULL && i == newfdp->fd_lastfile && i > 0)
1124 newfdp->fd_lastfile--;
1125 }
1126 newfdp->fd_knlist = NULL;
1127 newfdp->fd_knlistsize = -1;
1128 newfdp->fd_knhash = NULL;
1129 newfdp->fd_knhashmask = 0;
1130 }
1131
1132 fpp = newfdp->fd_ofiles;
1133 flags = newfdp->fd_ofileflags;
1134 for (i = newfdp->fd_lastfile; i-- >= 0; fpp++, flags++)
1135 if (*fpp != NULL && !(*flags & UF_RESERVED)) {
1136 (void)fref(*fpp);
1137 } else {
1138 *fpp = NULL;
1139 *flags = 0;
1140 }
1141 } else
1142 (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE);
1143
1144 return (newfdp);
1145}
1146
1147/*
1148 * Release a filedesc structure.
1149 */
1150void
1151fdfree(p)
1152 struct proc *p;
1153{
1154 struct filedesc *fdp;
1155 struct file *fp;
1156 int i;
1157 struct vnode *tvp;
1158
1159 /* Certain daemons might not have file descriptors */
1160 if ((fdp = p->p_fd) == NULL)
1161 return;
1162
1163 if (--fdp->fd_refcnt > 0)
1164 return;
1165
1166 /* Last reference: the structure can't change out from under us */
1167 if (fdp->fd_nfiles > 0) {
1168 for (i = fdp->fd_lastfile; i >= 0; i--)
1169#if 1 /* WORKAROUND */
1170 /*
1171 * Merlot: need to remove the bogus f_data check
1172 * from the following "if" statement. It's there
1173 * because of the network/kernel funnel race on a
1174 * close of a socket vs. fdfree on exit. See
1175 * Radar rdar://problem/3365650 for details, but
1176 * the sort version is the commment before the "if"
1177 * above is wrong under certain circumstances.
1178 *
1179 * We have to do this twice, in case knote_fdclose()
1180 * results in a block.
1181 *
1182 * This works because an fdfree() will set all fields
1183 * in the struct file to -1.
1184 */
1185 if ((fp = fdp->fd_ofiles[i]) != NULL &&
1186 fp->f_data != (caddr_t)-1) {
1187 if (i < fdp->fd_knlistsize)
1188 knote_fdclose(p, i);
1189 if (fp->f_data != (caddr_t)-1)
1190 (void) closef(fp, p);
1191 }
1192#else /* !WORKAROUND */
1193 if ((fp = fdp->fd_ofiles[i]) != NULL) {
1194 if (i < fdp->fd_knlistsize)
1195 knote_fdclose(p, i);
1196 (void) closef(fp, p);
1197 }
1198#endif /* !WORKAROUND */
1199 FREE_ZONE(fdp->fd_ofiles,
1200 fdp->fd_nfiles * OFILESIZE, M_OFILETABL);
1201 }
1202
1203 tvp = fdp->fd_cdir;
1204 fdp->fd_cdir = NULL;
1205 vrele(tvp);
1206
1207 if (fdp->fd_rdir) {
1208 tvp = fdp->fd_rdir;
1209 fdp->fd_rdir = NULL;
1210 vrele(tvp);
1211 }
1212
1213 if (fdp->fd_knlist)
1214 FREE(fdp->fd_knlist, M_KQUEUE);
1215 if (fdp->fd_knhash)
1216 FREE(fdp->fd_knhash, M_KQUEUE);
1217
1218 FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC);
1219}
1220
1221static int
1222closef_finish(fp, p)
1223 register struct file *fp;
1224 register struct proc *p;
1225{
1226 struct vnode *vp;
1227 struct flock lf;
1228 int error;
1229
1230 if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
1231 lf.l_whence = SEEK_SET;
1232 lf.l_start = 0;
1233 lf.l_len = 0;
1234 lf.l_type = F_UNLCK;
1235 vp = (struct vnode *)fp->f_data;
1236 (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
1237 }
1238 if (fp->f_ops)
1239 error = fo_close(fp, p);
1240 else
1241 error = 0;
1242 ffree(fp);
1243 return (error);
1244}
1245
1246/*
1247 * Internal form of close.
1248 * Decrement reference count on file structure.
1249 * Note: p may be NULL when closing a file
1250 * that was being passed in a message.
1251 */
1252int
1253closef(fp, p)
1254 register struct file *fp;
1255 register struct proc *p;
1256{
1257 struct vnode *vp;
1258 struct flock lf;
1259 int error;
1260
1261 if (fp == NULL)
1262 return (0);
1263 /*
1264 * POSIX record locking dictates that any close releases ALL
1265 * locks owned by this process. This is handled by setting
1266 * a flag in the unlock to free ONLY locks obeying POSIX
1267 * semantics, and not to free BSD-style file locks.
1268 * If the descriptor was in a message, POSIX-style locks
1269 * aren't passed with the descriptor.
1270 */
1271 if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
1272 lf.l_whence = SEEK_SET;
1273 lf.l_start = 0;
1274 lf.l_len = 0;
1275 lf.l_type = F_UNLCK;
1276 vp = (struct vnode *)fp->f_data;
1277 (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
1278 }
1279 if (frele_internal(fp) > 0)
1280 return (0);
1281 return(closef_finish(fp, p));
1282}
1283
1284/*
1285 * Apply an advisory lock on a file descriptor.
1286 *
1287 * Just attempt to get a record lock of the requested type on
1288 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
1289 */
1290struct flock_args {
1291 int fd;
1292 int how;
1293};
1294/* ARGSUSED */
1295int
1296flock(p, uap, retval)
1297 struct proc *p;
1298 register struct flock_args *uap;
1299 register_t *retval;
1300{
1301 int fd = uap->fd;
1302 int how = uap->how;
1303 register struct filedesc *fdp = p->p_fd;
1304 register struct file *fp;
1305 struct vnode *vp;
1306 struct flock lf;
1307
1308 AUDIT_ARG(fd, uap->fd);
1309 if ((u_int)fd >= fdp->fd_nfiles ||
1310 (fp = fdp->fd_ofiles[fd]) == NULL ||
1311 (fdp->fd_ofileflags[fd] & UF_RESERVED))
1312 return (EBADF);
1313 if (fp->f_type != DTYPE_VNODE)
1314 return (EOPNOTSUPP);
1315 vp = (struct vnode *)fp->f_data;
1316 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
1317 lf.l_whence = SEEK_SET;
1318 lf.l_start = 0;
1319 lf.l_len = 0;
1320 if (how & LOCK_UN) {
1321 lf.l_type = F_UNLCK;
1322 fp->f_flag &= ~FHASLOCK;
1323 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
1324 }
1325 if (how & LOCK_EX)
1326 lf.l_type = F_WRLCK;
1327 else if (how & LOCK_SH)
1328 lf.l_type = F_RDLCK;
1329 else
1330 return (EBADF);
1331 fp->f_flag |= FHASLOCK;
1332 if (how & LOCK_NB)
1333 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
1334 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
1335}
1336
1337/*
1338 * File Descriptor pseudo-device driver (/dev/fd/).
1339 *
1340 * Opening minor device N dup()s the file (if any) connected to file
1341 * descriptor N belonging to the calling process. Note that this driver
1342 * consists of only the ``open()'' routine, because all subsequent
1343 * references to this file will be direct to the other driver.
1344 */
1345/* ARGSUSED */
1346int
1347fdopen(dev, mode, type, p)
1348 dev_t dev;
1349 int mode, type;
1350 struct proc *p;
1351{
1352
1353 /*
1354 * XXX Kludge: set curproc->p_dupfd to contain the value of the
1355 * the file descriptor being sought for duplication. The error
1356 * return ensures that the vnode for this device will be released
1357 * by vn_open. Open will detect this special error and take the
1358 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
1359 * will simply report the error.
1360 */
1361 p->p_dupfd = minor(dev);
1362 return (ENODEV);
1363}
1364
1365/*
1366 * Duplicate the specified descriptor to a free descriptor.
1367 */
1368int
1369dupfdopen(fdp, indx, dfd, mode, error)
1370 register struct filedesc *fdp;
1371 register int indx, dfd;
1372 int mode;
1373 int error;
1374{
1375 register struct file *wfp;
1376 struct file *fp;
1377
1378 /*
1379 * If the to-be-dup'd fd number is greater than the allowed number
1380 * of file descriptors, or the fd to be dup'd has already been
1381 * closed, reject. Note, check for new == old is necessary as
1382 * falloc could allocate an already closed to-be-dup'd descriptor
1383 * as the new descriptor.
1384 */
1385 fp = fdp->fd_ofiles[indx];
1386 if ((u_int)dfd >= fdp->fd_nfiles ||
1387 (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp ||
1388 (fdp->fd_ofileflags[dfd] & UF_RESERVED))
1389 return (EBADF);
1390
1391 /*
1392 * There are two cases of interest here.
1393 *
1394 * For ENODEV simply dup (dfd) to file descriptor
1395 * (indx) and return.
1396 *
1397 * For ENXIO steal away the file structure from (dfd) and
1398 * store it in (indx). (dfd) is effectively closed by
1399 * this operation.
1400 *
1401 * Any other error code is just returned.
1402 */
1403 switch (error) {
1404 case ENODEV:
1405 /*
1406 * Check that the mode the file is being opened for is a
1407 * subset of the mode of the existing descriptor.
1408 */
1409 if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
1410 return (EACCES);
1411 (void)fref(wfp);
1412 if (indx > fdp->fd_lastfile)
1413 fdp->fd_lastfile = indx;;
1414 fdp->fd_ofiles[indx] = wfp;
1415 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
1416 return (0);
1417
1418 case ENXIO:
1419 /*
1420 * Steal away the file pointer from dfd, and stuff it into indx.
1421 */
1422 if (indx > fdp->fd_lastfile)
1423 fdp->fd_lastfile = indx;;
1424 fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
1425 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
1426 _fdrelse(fdp, dfd);
1427 return (0);
1428
1429 default:
1430 return (error);
1431 }
1432 /* NOTREACHED */
1433}
1434
1435/* Reference manipulation routines for the file structure */
1436
1437int
1438fref(struct file *fp)
1439{
1440 if (fp->f_count == (short)0xffff)
1441 return (-1);
1442 if (++fp->f_count <= 0)
1443 panic("fref: f_count");
1444 return ((int)fp->f_count);
1445}
1446
1447static int
1448frele_internal(struct file *fp)
1449{
1450 if (fp->f_count == (short)0xffff)
1451 panic("frele: stale");
1452 if (--fp->f_count < 0)
1453 panic("frele: count < 0");
1454 return ((int)fp->f_count);
1455}
1456
1457
1458int
1459frele(struct file *fp)
1460{
1461 int count;
1462 funnel_t * fnl;
1463 extern int disable_funnel;
1464
1465 fnl = thread_funnel_get();
1466 /*
1467 * If the funnels are merged then atleast a funnel should be held
1468 * else frele should come in with kernel funnel only
1469 */
1470 if (!disable_funnel && (fnl != kernel_flock)) {
1471 panic("frele: kernel funnel not held");
1472
1473 } else if (fnl == THR_FUNNEL_NULL) {
1474 panic("frele: no funnel held");
1475 }
1476
1477 if ((count = frele_internal(fp)) == 0) {
1478 /* some one closed the fd while we were blocked */
1479 (void)closef_finish(fp, current_proc());
1480 }
1481 return(count);
1482}
1483
1484int
1485fcount(struct file *fp)
1486{
1487 if (fp->f_count == (short)0xffff)
1488 panic("fcount: stale");
1489 return ((int)fp->f_count);
1490}
1491