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