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