]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_descrip.c
xnu-201.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
0b4e3aa0
A
429 if (alloc_struct.fst_offset != 0)
430 return (EINVAL);
1c79356b
A
431
432 alloc_flags |= ALLOCATEFROMPEOF;
433 break;
434
0b4e3aa0
A
435 case F_VOLPOSMODE:
436
437 if (alloc_struct.fst_offset <= 0)
438 return (EINVAL);
439
440 alloc_flags |= ALLOCATEFROMVOL;
441 break;
442
1c79356b
A
443 default:
444
445 return(EINVAL);
446
447 }
448
1c79356b
A
449 /* Now lock the vnode and call allocate to get the space */
450
451 vp = (struct vnode *)fp->f_data;
452
453 VOP_LOCK(vp,LK_EXCLUSIVE,p);
454 error = VOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags,
0b4e3aa0
A
455 &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset,
456 fp->f_cred, p);
1c79356b
A
457 VOP_UNLOCK(vp,0,p);
458
459 if (error2 = (copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg,
460 sizeof (alloc_struct)))) {
461 if (error) {
462 return(error);
463 } else {
464 return(error2);
465 }
466 }
467
468 return(error);
469
470 case F_SETSIZE:
471
472 /* Copy in the structure */
473
474 error = copyin((caddr_t)uap->arg, (caddr_t)&offset,
475 sizeof (off_t));
476
477 if (error)
478 return (error);
479
480
481 /* First make sure that we are root. Growing a file */
482 /* without zero filling the data is a security hole */
483 /* root would have access anyway so we'll allow it */
484
485 if (!is_suser()) {
486 return (EACCES);
487 }
488
489 /* Now lock the vnode and call allocate to get the space */
490
491 vp = (struct vnode *)fp->f_data;
492
493 VOP_LOCK(vp,LK_EXCLUSIVE,p);
494 error = VOP_TRUNCATE(vp,offset,IO_NOZEROFILL,fp->f_cred,p);
495 VOP_UNLOCK(vp,0,p);
496
497 return(error);
498
499 case F_RDAHEAD:
500 vp = (struct vnode *)fp->f_data;
501
502 simple_lock(&vp->v_interlock);
503 if (uap->arg)
504 vp->v_flag &= ~VRAOFF;
505 else
506 vp->v_flag |= VRAOFF;
507 simple_unlock(&vp->v_interlock);
508
509 return (0);
510
511 case F_NOCACHE:
512 vp = (struct vnode *)fp->f_data;
513
514 simple_lock(&vp->v_interlock);
515 if (uap->arg)
516 vp->v_flag |= VNOCACHE_DATA;
517 else
518 vp->v_flag &= ~VNOCACHE_DATA;
519 simple_unlock(&vp->v_interlock);
520
521 return (0);
522
523 case F_RDADVISE:
524 vp = (struct vnode *)fp->f_data;
525
526 if (error = copyin((caddr_t)uap->arg, (caddr_t)&ra_struct, sizeof (ra_struct)))
527 return(error);
528 return (VOP_IOCTL(vp, 1, &ra_struct, 0, fp->f_cred, p));
529
530 case F_READBOOTSTRAP:
531 case F_WRITEBOOTSTRAP:
532
533 /* Copy in the structure */
534
535 error = copyin((caddr_t)uap->arg, (caddr_t)&fbt_struct,
536 sizeof (fbt_struct));
537
538 if (error)
539 return (error);
540
541
542 if (uap->cmd == F_WRITEBOOTSTRAP) {
543 /* First make sure that we are root. Updating the */
544 /* bootstrap on a disk could be a security hole */
545
546 if (!is_suser()) {
547 return (EACCES);
548 }
549 };
550
551 /* Now lock the vnode and call VOP_IOCTL to handle the I/O: */
552
553 vp = (struct vnode *)fp->f_data;
554 if (vp->v_tag != VT_HFS) {
555 error = EINVAL;
556 } else {
557 VOP_LOCK(vp,LK_EXCLUSIVE,p);
558 error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2, &fbt_struct, 0, fp->f_cred, p);
559 VOP_UNLOCK(vp,0,p);
560 };
561
562 return(error);
563
564 case F_LOG2PHYS:
565 if (fp->f_type != DTYPE_VNODE)
566 return (EBADF);
567 vp = (struct vnode *)fp->f_data;
568 VOP_LOCK(vp, LK_EXCLUSIVE, p);
569 if (VOP_OFFTOBLK(vp, fp->f_offset, &lbn))
570 panic("fcntl LOG2PHYS OFFTOBLK");
571 if (VOP_BLKTOOFF(vp, lbn, &offset))
572 panic("fcntl LOG2PHYS BLKTOOFF1");
573 error = VOP_BMAP(vp, lbn, &devvp, &bn, 0);
574 VOP_DEVBLOCKSIZE(devvp, &devBlockSize);
575 VOP_UNLOCK(vp, 0, p);
576 if (!error) {
577 l2p_struct.l2p_flags = 0; /* for now */
578 l2p_struct.l2p_contigbytes = 0; /* for now */
579 l2p_struct.l2p_devoffset = bn * devBlockSize;
580 l2p_struct.l2p_devoffset += fp->f_offset - offset;
581 error = copyout((caddr_t)&l2p_struct,
582 (caddr_t)uap->arg,
583 sizeof (l2p_struct));
584 }
585 return (error);
586
587
588 default:
589 return (EINVAL);
590 }
591 /* NOTREACHED */
592}
593
594/*
595 * Common code for dup, dup2, and fcntl(F_DUPFD).
596 */
597int
598finishdup(fdp, old, new, retval)
599 register struct filedesc *fdp;
600 register int old, new;
601 register_t *retval;
602{
603 register struct file *fp;
604
605 if ((fp = fdp->fd_ofiles[old]) == NULL ||
606 (fdp->fd_ofileflags[old] & UF_RESERVED)) {
607 _fdrelse(fdp, new);
608 return (EBADF);
609 }
610 fdp->fd_ofiles[new] = fp;
611 fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
612 (void)fref(fp);
613 if (new > fdp->fd_lastfile)
614 fdp->fd_lastfile = new;
615 *retval = new;
616 return (0);
617}
618
619/*
620 * Close a file descriptor.
621 */
622struct close_args {
623 int fd;
624};
625/* ARGSUSED */
626int
627close(p, uap, retval)
628 struct proc *p;
629 struct close_args *uap;
630 register_t *retval;
631{
632 int fd = uap->fd;
633 register struct filedesc *fdp = p->p_fd;
634 register struct file *fp;
635
636 if ((u_int)fd >= fdp->fd_nfiles ||
637 (fp = fdp->fd_ofiles[fd]) == NULL ||
638 (fdp->fd_ofileflags[fd] & UF_RESERVED))
639 return (EBADF);
640 _fdrelse(fdp, fd);
641 return (closef(fp, p));
642}
643
644/*
645 * Return status information about a file descriptor.
646 */
647struct fstat_args {
648 int fd;
649 struct stat *sb;
650};
651/* ARGSUSED */
652int
653fstat(p, uap, retval)
654 struct proc *p;
655 register struct fstat_args *uap;
656 register_t *retval;
657{
658 int fd = uap->fd;
659 register struct filedesc *fdp = p->p_fd;
660 register struct file *fp;
661 struct stat ub;
662 int error;
663
664 if ((u_int)fd >= fdp->fd_nfiles ||
665 (fp = fdp->fd_ofiles[fd]) == NULL ||
666 (fdp->fd_ofileflags[fd] & UF_RESERVED))
667 return (EBADF);
668 switch (fp->f_type) {
669
670 case DTYPE_VNODE:
671 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
672 break;
673
674 case DTYPE_SOCKET:
675 error = soo_stat((struct socket *)fp->f_data, &ub);
676 break;
677
678 case DTYPE_PSXSHM:
679 error = pshm_stat((void *)fp->f_data, &ub);
680 break;
681 default:
682 panic("fstat");
683 /*NOTREACHED*/
684 }
685 if (error == 0)
686 error = copyout((caddr_t)&ub, (caddr_t)uap->sb,
687 sizeof (ub));
688 return (error);
689}
690
691#if COMPAT_43
692/*
693 * Return status information about a file descriptor.
694 */
695struct ofstat_args {
696 int fd;
697 struct ostat *sb;
698};
699/* ARGSUSED */
700ofstat(p, uap, retval)
701 struct proc *p;
702 register struct ofstat_args *uap;
703 register_t *retval;
704{
705 int fd = uap->fd;
706 register struct filedesc *fdp = p->p_fd;
707 register struct file *fp;
708 struct stat ub;
709 struct ostat oub;
710 int error;
711
712 if ((u_int)fd >= fdp->fd_nfiles ||
713 (fp = fdp->fd_ofiles[fd]) == NULL ||
714 (fdp->fd_ofileflags[fd] & UF_RESERVED))
715 return (EBADF);
716 switch (fp->f_type) {
717
718 case DTYPE_VNODE:
719 error = vn_stat((struct vnode *)fp->f_data, &ub, p);
720 break;
721
722 case DTYPE_SOCKET:
723 error = soo_stat((struct socket *)fp->f_data, &ub);
724 break;
725
726 default:
727 panic("ofstat");
728 /*NOTREACHED*/
729 }
730 cvtstat(&ub, &oub);
731 if (error == 0)
732 error = copyout((caddr_t)&oub, (caddr_t)uap->sb,
733 sizeof (oub));
734 return (error);
735}
736#endif /* COMPAT_43 */
737
738/*
739 * Return pathconf information about a file descriptor.
740 */
741struct fpathconf_args {
742 int fd;
743 int name;
744};
745/* ARGSUSED */
746fpathconf(p, uap, retval)
747 struct proc *p;
748 register struct fpathconf_args *uap;
749 register_t *retval;
750{
751 int fd = uap->fd;
752 struct filedesc *fdp = p->p_fd;
753 struct file *fp;
754 struct vnode *vp;
755
756 if ((u_int)fd >= fdp->fd_nfiles ||
757 (fp = fdp->fd_ofiles[fd]) == NULL ||
758 (fdp->fd_ofileflags[fd] & UF_RESERVED))
759 return (EBADF);
760 switch (fp->f_type) {
761
762 case DTYPE_SOCKET:
763 if (uap->name != _PC_PIPE_BUF)
764 return (EINVAL);
765 *retval = PIPE_BUF;
766 return (0);
767
768 case DTYPE_VNODE:
769 vp = (struct vnode *)fp->f_data;
770 return (VOP_PATHCONF(vp, uap->name, retval));
771
772 default:
773 panic("fpathconf");
774 }
775 /*NOTREACHED*/
776}
777
778/*
779 * Allocate a file descriptor for the process.
780 */
781int fdexpand;
782
783int
784fdalloc(p, want, result)
785 struct proc *p;
786 int want;
787 int *result;
788{
789 register struct filedesc *fdp = p->p_fd;
790 register int i;
791 int lim, last, nfiles, oldnfiles;
792 struct file **newofiles, **ofiles;
793 char *newofileflags, *ofileflags;
794
795 /*
796 * Search for a free descriptor starting at the higher
797 * of want or fd_freefile. If that fails, consider
798 * expanding the ofile array.
799 */
800 lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
801 for (;;) {
802 last = min(fdp->fd_nfiles, lim);
803 if ((i = want) < fdp->fd_freefile)
804 i = fdp->fd_freefile;
805 ofiles = &fdp->fd_ofiles[i];
806 ofileflags = &fdp->fd_ofileflags[i];
807 for (; i < last; i++) {
808 if (*ofiles == NULL && !(*ofileflags & UF_RESERVED)) {
809 *ofileflags = UF_RESERVED;
810 if (i > fdp->fd_lastfile)
811 fdp->fd_lastfile = i;
812 if (want <= fdp->fd_freefile)
813 fdp->fd_freefile = i;
814 *result = i;
815 return (0);
816 }
817 ofiles++; ofileflags++;
818 }
819
820 /*
821 * No space in current array. Expand?
822 */
823 if (fdp->fd_nfiles >= lim)
824 return (EMFILE);
825 if (fdp->fd_nfiles < NDEXTENT)
826 nfiles = NDEXTENT;
827 else
828 nfiles = 2 * fdp->fd_nfiles;
829 /* Enforce lim */
830 if (nfiles > lim)
831 nfiles = lim;
832 MALLOC_ZONE(newofiles, struct file **,
833 nfiles * OFILESIZE, M_OFILETABL, M_WAITOK);
834 if (fdp->fd_nfiles >= nfiles) {
835 FREE_ZONE(newofiles, nfiles * OFILESIZE, M_OFILETABL);
836 continue;
837 }
838 newofileflags = (char *) &newofiles[nfiles];
839 /*
840 * Copy the existing ofile and ofileflags arrays
841 * and zero the new portion of each array.
842 */
843 oldnfiles = fdp->fd_nfiles;
844 (void) memcpy(newofiles, fdp->fd_ofiles,
845 oldnfiles * sizeof *fdp->fd_ofiles);
846 (void) memset(&newofiles[oldnfiles], 0,
847 (nfiles - oldnfiles) * sizeof *fdp->fd_ofiles);
848
849 (void) memcpy(newofileflags, fdp->fd_ofileflags,
850 oldnfiles * sizeof *fdp->fd_ofileflags);
851 (void) memset(&newofileflags[oldnfiles], 0,
852 (nfiles - oldnfiles) *
853 sizeof *fdp->fd_ofileflags);
854 ofiles = fdp->fd_ofiles;
855 fdp->fd_ofiles = newofiles;
856 fdp->fd_ofileflags = newofileflags;
857 fdp->fd_nfiles = nfiles;
858 FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL);
859 fdexpand++;
860 }
861}
862
863/*
864 * Check to see whether n user file descriptors
865 * are available to the process p.
866 */
867int
868fdavail(p, n)
869 struct proc *p;
870 register int n;
871{
872 register struct filedesc *fdp = p->p_fd;
873 register struct file **fpp;
874 register char *flags;
875 register int i, lim;
876
877 lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
878 if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
879 return (1);
880 fpp = &fdp->fd_ofiles[fdp->fd_freefile];
881 flags = &fdp->fd_ofileflags[fdp->fd_freefile];
882 for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++)
883 if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0)
884 return (1);
885 return (0);
886}
887
888void
889fdrelse(p, fd)
890 struct proc *p;
891 int fd;
892{
893 _fdrelse(p->p_fd, fd);
894}
895
896int
897fdgetf(p, fd, resultfp)
898 register struct proc *p;
899 register int fd;
900 struct file **resultfp;
901{
902 register struct filedesc *fdp = p->p_fd;
903 struct file *fp;
904
905 if ((u_int)fd >= fdp->fd_nfiles ||
906 (fp = fdp->fd_ofiles[fd]) == NULL ||
907 (fdp->fd_ofileflags[fd] & UF_RESERVED))
908 return (EBADF);
909
910 if (resultfp)
911 *resultfp = fp;
912 return (0);
913}
914
915/*
916 * Create a new open file structure and allocate
917 * a file decriptor for the process that refers to it.
918 */
919int
920falloc(p, resultfp, resultfd)
921 register struct proc *p;
922 struct file **resultfp;
923 int *resultfd;
924{
925 register struct file *fp, *fq;
926 int error, i;
927
928 if (error = fdalloc(p, 0, &i))
929 return (error);
930 if (nfiles >= maxfiles) {
931 tablefull("file");
932 return (ENFILE);
933 }
934 /*
935 * Allocate a new file descriptor.
936 * If the process has file descriptor zero open, add to the list
937 * of open files at that point, otherwise put it at the front of
938 * the list of open files.
939 */
940 nfiles++;
941 MALLOC_ZONE(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
942 bzero(fp, sizeof(struct file));
943 if (fq = p->p_fd->fd_ofiles[0]) {
944 LIST_INSERT_AFTER(fq, fp, f_list);
945 } else {
946 LIST_INSERT_HEAD(&filehead, fp, f_list);
947 }
948 p->p_fd->fd_ofiles[i] = fp;
949 fp->f_count = 1;
950 fp->f_cred = p->p_ucred;
951 crhold(fp->f_cred);
952 if (resultfp)
953 *resultfp = fp;
954 if (resultfd)
955 *resultfd = i;
956 return (0);
957}
958
959/*
960 * Free a file structure.
961 */
962void
963ffree(fp)
964 register struct file *fp;
965{
966 register struct file *fq;
967 struct ucred *cred;
968
969 LIST_REMOVE(fp, f_list);
970 cred = fp->f_cred;
971 if (cred != NOCRED) {
972 fp->f_cred = NOCRED;
973 crfree(cred);
974 }
975#if 1 || DIAGNOSTIC
976 fp->f_count = 0;
977#endif
978 nfiles--;
979 FREE_ZONE(fp, sizeof *fp, M_FILE);
980}
981
982void
983fdexec(p)
984 struct proc *p;
985{
986 register struct filedesc *fdp = p->p_fd;
987 register int i = fdp->fd_lastfile;
988 register struct file **fpp = &fdp->fd_ofiles[i];
989 register char *flags = &fdp->fd_ofileflags[i];
990
991 while (i >= 0) {
992 if ((*flags & (UF_RESERVED|UF_EXCLOSE)) == UF_EXCLOSE) {
993 register struct file *fp = *fpp;
994
995 *fpp = NULL; *flags = 0;
996 if (i == fdp->fd_lastfile && i > 0)
997 fdp->fd_lastfile--;
998 closef(fp, p);
999 }
1000 else
1001 *flags &= ~UF_MAPPED;
1002
1003 i--; fpp--; flags--;
1004 }
1005}
1006
1007/*
1008 * Copy a filedesc structure.
1009 */
1010struct filedesc *
1011fdcopy(p)
1012 struct proc *p;
1013{
1014 register struct filedesc *newfdp, *fdp = p->p_fd;
1015 register int i;
1016
1017 MALLOC_ZONE(newfdp, struct filedesc *,
1018 sizeof *newfdp, M_FILEDESC, M_WAITOK);
1019 (void) memcpy(newfdp, fdp, sizeof *newfdp);
1020 VREF(newfdp->fd_cdir);
1021 if (newfdp->fd_rdir)
1022 VREF(newfdp->fd_rdir);
1023 newfdp->fd_refcnt = 1;
1024
1025 /*
1026 * If the number of open files fits in the internal arrays
1027 * of the open file structure, use them, otherwise allocate
1028 * additional memory for the number of descriptors currently
1029 * in use.
1030 */
1031 if (newfdp->fd_lastfile < NDFILE)
1032 i = NDFILE;
1033 else {
1034 /*
1035 * Compute the smallest multiple of NDEXTENT needed
1036 * for the file descriptors currently in use,
1037 * allowing the table to shrink.
1038 */
1039 i = newfdp->fd_nfiles;
1040 while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
1041 i /= 2;
1042 }
1043 MALLOC_ZONE(newfdp->fd_ofiles, struct file **,
1044 i * OFILESIZE, M_OFILETABL, M_WAITOK);
1045 newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
1046 newfdp->fd_nfiles = i;
1047 if (fdp->fd_nfiles > 0) {
1048 register struct file **fpp;
1049 register char *flags;
1050
1051 (void) memcpy(newfdp->fd_ofiles, fdp->fd_ofiles,
1052 i * sizeof *fdp->fd_ofiles);
1053 (void) memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags,
1054 i * sizeof *fdp->fd_ofileflags);
1055
1056 fpp = newfdp->fd_ofiles;
1057 flags = newfdp->fd_ofileflags;
1058 for (i = newfdp->fd_lastfile; i-- >= 0; fpp++, flags++)
1059 if (*fpp != NULL && !(*flags & UF_RESERVED)) {
1060 (void)fref(*fpp);
1061 } else {
1062 *fpp = NULL;
1063 *flags = 0;
1064 }
1065 }
1066 else
1067 (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE);
1068
1069 return (newfdp);
1070}
1071
1072/*
1073 * Release a filedesc structure.
1074 */
1075void
1076fdfree(p)
1077 struct proc *p;
1078{
1079 register struct filedesc *fdp;
1080 register struct file **fpp;
1081 register int i;
1082
1083 if ((fdp = p->p_fd) == NULL)
1084 return;
1085 if (--fdp->fd_refcnt > 0)
1086 return;
1087 p->p_fd = NULL;
1088 if (fdp->fd_nfiles > 0) {
1089 fpp = fdp->fd_ofiles;
1090 for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
1091 if (*fpp)
1092 (void) closef(*fpp, p);
1093 FREE_ZONE(fdp->fd_ofiles,
1094 fdp->fd_nfiles * OFILESIZE, M_OFILETABL);
1095 }
1096 vrele(fdp->fd_cdir);
1097 if (fdp->fd_rdir)
1098 vrele(fdp->fd_rdir);
1099 FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC);
1100}
1101
1102/*
1103 * Internal form of close.
1104 * Decrement reference count on file structure.
1105 * Note: p may be NULL when closing a file
1106 * that was being passed in a message.
1107 */
1108int
1109closef(fp, p)
1110 register struct file *fp;
1111 register struct proc *p;
1112{
1113 struct vnode *vp;
1114 struct flock lf;
1115 int error;
1116
1117 if (fp == NULL)
1118 return (0);
1119 /*
1120 * POSIX record locking dictates that any close releases ALL
1121 * locks owned by this process. This is handled by setting
1122 * a flag in the unlock to free ONLY locks obeying POSIX
1123 * semantics, and not to free BSD-style file locks.
1124 * If the descriptor was in a message, POSIX-style locks
1125 * aren't passed with the descriptor.
1126 */
1127 if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
1128 lf.l_whence = SEEK_SET;
1129 lf.l_start = 0;
1130 lf.l_len = 0;
1131 lf.l_type = F_UNLCK;
1132 vp = (struct vnode *)fp->f_data;
1133 (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX);
1134 }
1135 if (frele(fp) > 0)
1136 return (0);
1137 if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
1138 lf.l_whence = SEEK_SET;
1139 lf.l_start = 0;
1140 lf.l_len = 0;
1141 lf.l_type = F_UNLCK;
1142 vp = (struct vnode *)fp->f_data;
1143 (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
1144 }
1145 if (fp->f_ops)
1146 error = (*fp->f_ops->fo_close)(fp, p);
1147 else
1148 error = 0;
1149 ffree(fp);
1150 return (error);
1151}
1152
1153/*
1154 * Apply an advisory lock on a file descriptor.
1155 *
1156 * Just attempt to get a record lock of the requested type on
1157 * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
1158 */
1159struct flock_args {
1160 int fd;
1161 int how;
1162};
1163/* ARGSUSED */
1164int
1165flock(p, uap, retval)
1166 struct proc *p;
1167 register struct flock_args *uap;
1168 register_t *retval;
1169{
1170 int fd = uap->fd;
1171 int how = uap->how;
1172 register struct filedesc *fdp = p->p_fd;
1173 register struct file *fp;
1174 struct vnode *vp;
1175 struct flock lf;
1176
1177 if ((u_int)fd >= fdp->fd_nfiles ||
1178 (fp = fdp->fd_ofiles[fd]) == NULL ||
1179 (fdp->fd_ofileflags[fd] & UF_RESERVED))
1180 return (EBADF);
1181 if (fp->f_type != DTYPE_VNODE)
1182 return (EOPNOTSUPP);
1183 vp = (struct vnode *)fp->f_data;
1184 lf.l_whence = SEEK_SET;
1185 lf.l_start = 0;
1186 lf.l_len = 0;
1187 if (how & LOCK_UN) {
1188 lf.l_type = F_UNLCK;
1189 fp->f_flag &= ~FHASLOCK;
1190 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
1191 }
1192 if (how & LOCK_EX)
1193 lf.l_type = F_WRLCK;
1194 else if (how & LOCK_SH)
1195 lf.l_type = F_RDLCK;
1196 else
1197 return (EBADF);
1198 fp->f_flag |= FHASLOCK;
1199 if (how & LOCK_NB)
1200 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
1201 return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
1202}
1203
1204/*
1205 * File Descriptor pseudo-device driver (/dev/fd/).
1206 *
1207 * Opening minor device N dup()s the file (if any) connected to file
1208 * descriptor N belonging to the calling process. Note that this driver
1209 * consists of only the ``open()'' routine, because all subsequent
1210 * references to this file will be direct to the other driver.
1211 */
1212/* ARGSUSED */
1213int
1214fdopen(dev, mode, type, p)
1215 dev_t dev;
1216 int mode, type;
1217 struct proc *p;
1218{
1219
1220 /*
1221 * XXX Kludge: set curproc->p_dupfd to contain the value of the
1222 * the file descriptor being sought for duplication. The error
1223 * return ensures that the vnode for this device will be released
1224 * by vn_open. Open will detect this special error and take the
1225 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
1226 * will simply report the error.
1227 */
1228 p->p_dupfd = minor(dev);
1229 return (ENODEV);
1230}
1231
1232/*
1233 * Duplicate the specified descriptor to a free descriptor.
1234 */
1235int
1236dupfdopen(fdp, indx, dfd, mode, error)
1237 register struct filedesc *fdp;
1238 register int indx, dfd;
1239 int mode;
1240 int error;
1241{
1242 register struct file *wfp;
1243 struct file *fp;
1244
1245 /*
1246 * If the to-be-dup'd fd number is greater than the allowed number
1247 * of file descriptors, or the fd to be dup'd has already been
1248 * closed, reject. Note, check for new == old is necessary as
1249 * falloc could allocate an already closed to-be-dup'd descriptor
1250 * as the new descriptor.
1251 */
1252 fp = fdp->fd_ofiles[indx];
1253 if ((u_int)dfd >= fdp->fd_nfiles ||
1254 (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp ||
1255 (fdp->fd_ofileflags[dfd] & UF_RESERVED))
1256 return (EBADF);
1257
1258 /*
1259 * There are two cases of interest here.
1260 *
1261 * For ENODEV simply dup (dfd) to file descriptor
1262 * (indx) and return.
1263 *
1264 * For ENXIO steal away the file structure from (dfd) and
1265 * store it in (indx). (dfd) is effectively closed by
1266 * this operation.
1267 *
1268 * Any other error code is just returned.
1269 */
1270 switch (error) {
1271 case ENODEV:
1272 /*
1273 * Check that the mode the file is being opened for is a
1274 * subset of the mode of the existing descriptor.
1275 */
1276 if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
1277 return (EACCES);
1278 (void)fref(wfp);
1279 if (indx > fdp->fd_lastfile)
1280 fdp->fd_lastfile = indx;;
1281 fdp->fd_ofiles[indx] = wfp;
1282 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
1283 return (0);
1284
1285 case ENXIO:
1286 /*
1287 * Steal away the file pointer from dfd, and stuff it into indx.
1288 */
1289 if (indx > fdp->fd_lastfile)
1290 fdp->fd_lastfile = indx;;
1291 fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
1292 fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
1293 _fdrelse(fdp, dfd);
1294 return (0);
1295
1296 default:
1297 return (error);
1298 }
1299 /* NOTREACHED */
1300}
1301
1302/* Reference manipulation routines for the file structure */
1303
1304int
1305fref(struct file *fp)
1306{
1307 if (++fp->f_count <= 0)
1308 panic("fref: f_count");
1309 return ((int)fp->f_count);
1310}
1311
1312int
1313frele(struct file *fp)
1314{
1315 if (--fp->f_count < 0)
1316 panic("frele: count < 0");
1317 return ((int)fp->f_count);
1318}
1319
1320int
1321fcount(struct file *fp)
1322{
1323 return ((int)fp->f_count);
1324}
1325