]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
e5568f75 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
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. | |
1c79356b | 11 | * |
e5568f75 A |
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 | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
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. | |
1c79356b A |
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> | |
91447636 A |
67 | #include <sys/vnode_internal.h> |
68 | #include <sys/proc_internal.h> | |
69 | #include <sys/kauth.h> | |
70 | #include <sys/file_internal.h> | |
1c79356b A |
71 | #include <sys/socket.h> |
72 | #include <sys/socketvar.h> | |
73 | #include <sys/stat.h> | |
74 | #include <sys/ioctl.h> | |
75 | #include <sys/fcntl.h> | |
76 | #include <sys/malloc.h> | |
91447636 | 77 | #include <sys/mman.h> |
1c79356b A |
78 | #include <sys/syslog.h> |
79 | #include <sys/unistd.h> | |
80 | #include <sys/resourcevar.h> | |
55e303ae | 81 | #include <sys/aio_kern.h> |
91447636 A |
82 | #include <sys/ev.h> |
83 | #include <kern/lock.h> | |
e5568f75 A |
84 | |
85 | #include <bsm/audit_kernel.h> | |
1c79356b | 86 | |
91447636 A |
87 | #include <sys/mount_internal.h> |
88 | #include <sys/kdebug.h> | |
89 | #include <sys/sysproto.h> | |
90 | #include <sys/pipe.h> | |
91 | #include <kern/kern_types.h> | |
92 | #include <kern/kalloc.h> | |
b36670ce | 93 | #include <libkern/OSAtomic.h> |
91447636 A |
94 | |
95 | struct psemnode; | |
96 | struct pshmnode; | |
97 | ||
98 | int fdopen(dev_t dev, int mode, int type, struct proc *p); | |
99 | int ogetdtablesize(struct proc *p, void *uap, register_t *retval); | |
100 | int finishdup(struct proc * p, struct filedesc *fdp, int old, int new, register_t *retval); | |
101 | ||
102 | int closef(struct fileglob *fg, struct proc *p); | |
103 | int falloc_locked(struct proc *p, struct fileproc **resultfp, int *resultfd, int locked); | |
104 | void fddrop(struct proc *p, int fd); | |
105 | int fdgetf_noref(struct proc *p, int fd, struct fileproc **resultfp); | |
106 | void fg_drop(struct fileproc * fp); | |
107 | void fg_free(struct fileglob *fg); | |
108 | void fg_ref(struct fileproc * fp); | |
109 | int fp_getfpshm(struct proc *p, int fd, struct fileproc **resultfp, struct pshmnode **resultpshm); | |
110 | ||
111 | static int closef_finish(struct fileproc *fp, struct fileglob *fg, struct proc *p); | |
112 | ||
113 | extern void file_lock_init(void); | |
114 | extern int is_suser(void); | |
115 | extern int kqueue_stat(struct fileproc *fp, struct stat *st, struct proc *p); | |
116 | extern int soo_stat(struct socket *so, struct stat *ub); | |
117 | extern int vn_path_package_check(vnode_t vp, char *path, int pathlen, int *component); | |
118 | ||
119 | extern kauth_scope_t kauth_scope_fileop; | |
120 | ||
121 | #define f_flag f_fglob->fg_flag | |
122 | #define f_type f_fglob->fg_type | |
123 | #define f_msgcount f_fglob->fg_msgcount | |
124 | #define f_cred f_fglob->fg_cred | |
125 | #define f_ops f_fglob->fg_ops | |
126 | #define f_offset f_fglob->fg_offset | |
127 | #define f_data f_fglob->fg_data | |
1c79356b A |
128 | /* |
129 | * Descriptor management. | |
130 | */ | |
131 | struct filelist filehead; /* head of list of open files */ | |
91447636 A |
132 | struct fmsglist fmsghead; /* head of list of open files */ |
133 | struct fmsglist fmsg_ithead; /* head of list of open files */ | |
1c79356b A |
134 | int nfiles; /* actual number of open files */ |
135 | ||
91447636 A |
136 | |
137 | lck_grp_attr_t * file_lck_grp_attr; | |
138 | lck_grp_t * file_lck_grp; | |
139 | lck_attr_t * file_lck_attr; | |
140 | ||
141 | lck_mtx_t * uipc_lock; | |
142 | lck_mtx_t * file_iterate_lcok; | |
143 | lck_mtx_t * file_flist_lock; | |
144 | ||
145 | ||
146 | void | |
147 | file_lock_init(void) | |
148 | { | |
149 | ||
150 | /* allocate file lock group attribute and group */ | |
151 | file_lck_grp_attr= lck_grp_attr_alloc_init(); | |
152 | lck_grp_attr_setstat(file_lck_grp_attr); | |
153 | ||
154 | file_lck_grp = lck_grp_alloc_init("file", file_lck_grp_attr); | |
155 | ||
156 | /* Allocate file lock attribute */ | |
157 | file_lck_attr = lck_attr_alloc_init(); | |
158 | //lck_attr_setdebug(file_lck_attr); | |
159 | ||
160 | uipc_lock = lck_mtx_alloc_init(file_lck_grp, file_lck_attr); | |
161 | file_iterate_lcok = lck_mtx_alloc_init(file_lck_grp, file_lck_attr); | |
162 | file_flist_lock = lck_mtx_alloc_init(file_lck_grp, file_lck_attr); | |
163 | ||
164 | ||
165 | ||
166 | } | |
167 | ||
168 | ||
169 | void | |
170 | proc_fdlock(struct proc *p) | |
171 | { | |
172 | lck_mtx_lock(&p->p_fdmlock); | |
173 | } | |
174 | ||
175 | void | |
176 | proc_fdunlock(struct proc *p) | |
177 | { | |
178 | lck_mtx_unlock(&p->p_fdmlock); | |
179 | } | |
9bccf70c | 180 | |
1c79356b A |
181 | /* |
182 | * System calls on descriptors. | |
183 | */ | |
91447636 | 184 | |
1c79356b | 185 | int |
91447636 | 186 | getdtablesize(struct proc *p, __unused struct getdtablesize_args *uap, register_t *retval) |
1c79356b | 187 | { |
91447636 | 188 | proc_fdlock(p); |
1c79356b | 189 | *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); |
91447636 A |
190 | proc_fdunlock(p); |
191 | ||
1c79356b A |
192 | return (0); |
193 | } | |
194 | ||
1c79356b | 195 | int |
91447636 | 196 | ogetdtablesize(struct proc *p, __unused void *uap, register_t *retval) |
1c79356b | 197 | { |
91447636 | 198 | proc_fdlock(p); |
1c79356b | 199 | *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, NOFILE); |
91447636 A |
200 | proc_fdunlock(p); |
201 | ||
1c79356b A |
202 | return (0); |
203 | } | |
204 | ||
91447636 A |
205 | static __inline__ void |
206 | _fdrelse(struct filedesc *fdp, int fd) | |
1c79356b A |
207 | { |
208 | if (fd < fdp->fd_freefile) | |
209 | fdp->fd_freefile = fd; | |
210 | #if DIAGNOSTIC | |
211 | if (fd > fdp->fd_lastfile) | |
212 | panic("fdrelse: fd_lastfile inconsistent"); | |
213 | #endif | |
214 | fdp->fd_ofiles[fd] = NULL; | |
215 | fdp->fd_ofileflags[fd] = 0; | |
91447636 | 216 | |
1c79356b A |
217 | while ((fd = fdp->fd_lastfile) > 0 && |
218 | fdp->fd_ofiles[fd] == NULL && | |
219 | !(fdp->fd_ofileflags[fd] & UF_RESERVED)) | |
220 | fdp->fd_lastfile--; | |
221 | } | |
222 | ||
223 | /* | |
224 | * Duplicate a file descriptor. | |
225 | */ | |
1c79356b A |
226 | /* ARGSUSED */ |
227 | int | |
228 | dup(p, uap, retval) | |
229 | struct proc *p; | |
230 | struct dup_args *uap; | |
231 | register_t *retval; | |
232 | { | |
233 | register struct filedesc *fdp = p->p_fd; | |
234 | register int old = uap->fd; | |
235 | int new, error; | |
91447636 | 236 | struct fileproc *fp; |
1c79356b | 237 | |
91447636 A |
238 | proc_fdlock(p); |
239 | if ( (error = fp_lookup(p, old, &fp, 1)) ) { | |
240 | proc_fdunlock(p); | |
241 | return(error); | |
242 | } | |
243 | if ( (error = fdalloc(p, 0, &new)) ) { | |
244 | fp_drop(p, old, fp, 1); | |
245 | proc_fdunlock(p); | |
1c79356b | 246 | return (error); |
91447636 A |
247 | } |
248 | error = finishdup(p, fdp, old, new, retval); | |
249 | fp_drop(p, old, fp, 1); | |
250 | proc_fdunlock(p); | |
251 | ||
252 | return (error); | |
1c79356b A |
253 | } |
254 | ||
255 | /* | |
256 | * Duplicate a file descriptor to a particular value. | |
257 | */ | |
1c79356b A |
258 | /* ARGSUSED */ |
259 | int | |
260 | dup2(p, uap, retval) | |
261 | struct proc *p; | |
262 | struct dup2_args *uap; | |
263 | register_t *retval; | |
264 | { | |
265 | register struct filedesc *fdp = p->p_fd; | |
266 | register int old = uap->from, new = uap->to; | |
267 | int i, error; | |
91447636 | 268 | struct fileproc *fp; |
1c79356b | 269 | |
91447636 A |
270 | proc_fdlock(p); |
271 | ||
272 | if ( (error = fp_lookup(p, old, &fp, 1)) ) { | |
273 | proc_fdunlock(p); | |
274 | return(error); | |
275 | } | |
276 | if (new < 0 || | |
277 | new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || | |
278 | new >= maxfiles) { | |
279 | fp_drop(p, old, fp, 1); | |
280 | proc_fdunlock(p); | |
1c79356b | 281 | return (EBADF); |
91447636 | 282 | } |
1c79356b | 283 | if (old == new) { |
91447636 | 284 | fp_drop(p, old, fp, 1); |
1c79356b | 285 | *retval = new; |
91447636 | 286 | proc_fdunlock(p); |
1c79356b A |
287 | return (0); |
288 | } | |
91447636 A |
289 | if (new < 0 || new >= fdp->fd_nfiles) { |
290 | if ( (error = fdalloc(p, new, &i)) ) { | |
291 | fp_drop(p, old, fp, 1); | |
292 | proc_fdunlock(p); | |
1c79356b | 293 | return (error); |
91447636 | 294 | } |
1c79356b A |
295 | if (new != i) { |
296 | _fdrelse(fdp, i); | |
297 | goto closeit; | |
298 | } | |
fa4905b1 | 299 | } else { |
91447636 | 300 | struct fileproc **fpp; |
1c79356b A |
301 | char flags; |
302 | closeit: | |
91447636 A |
303 | flags = fdp->fd_ofileflags[new]; |
304 | if ((flags & (UF_RESERVED | UF_CLOSING)) == UF_RESERVED) { | |
305 | fp_drop(p, old, fp, 1); | |
306 | proc_fdunlock(p); | |
1c79356b | 307 | return (EBADF); |
91447636 A |
308 | } |
309 | ||
1c79356b A |
310 | /* |
311 | * dup2() must succeed even if the close has an error. | |
312 | */ | |
313 | if (*(fpp = &fdp->fd_ofiles[new])) { | |
91447636 | 314 | struct fileproc *nfp = *fpp; |
1c79356b | 315 | |
91447636 | 316 | close_internal(p, new, nfp, (CLOSEINT_LOCKED | CLOSEINT_WAITONCLOSE | CLOSEINT_NOFDRELSE | CLOSEINT_NOFDNOREF)); |
fa4905b1 | 317 | *fpp = NULL; |
1c79356b A |
318 | } |
319 | } | |
91447636 A |
320 | error = finishdup(p, fdp, old, new, retval); |
321 | fp_drop(p, old, fp, 1); | |
322 | proc_fdunlock(p); | |
323 | ||
324 | return(error); | |
1c79356b A |
325 | } |
326 | ||
327 | /* | |
328 | * The file control system call. | |
329 | */ | |
1c79356b A |
330 | int |
331 | fcntl(p, uap, retval) | |
332 | struct proc *p; | |
91447636 | 333 | struct fcntl_args *uap; |
1c79356b A |
334 | register_t *retval; |
335 | { | |
336 | int fd = uap->fd; | |
91447636 A |
337 | struct filedesc *fdp = p->p_fd; |
338 | struct fileproc *fp; | |
339 | char *pop; | |
340 | struct vnode *vp; | |
1c79356b A |
341 | int i, tmp, error, error2, flg = F_POSIX; |
342 | struct flock fl; | |
91447636 A |
343 | struct vfs_context context; |
344 | off_t offset; | |
1c79356b | 345 | int newmin; |
91447636 | 346 | daddr64_t lbn, bn; |
1c79356b | 347 | int devBlockSize = 0; |
91447636 A |
348 | unsigned int fflag; |
349 | user_addr_t argp; | |
1c79356b | 350 | |
55e303ae A |
351 | AUDIT_ARG(fd, uap->fd); |
352 | AUDIT_ARG(cmd, uap->cmd); | |
91447636 A |
353 | |
354 | proc_fdlock(p); | |
355 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
356 | proc_fdunlock(p); | |
357 | return(error); | |
358 | } | |
359 | context.vc_proc = p; | |
360 | context.vc_ucred = fp->f_cred; | |
361 | if (proc_is64bit(p)) { | |
362 | argp = uap->arg; | |
363 | } | |
364 | else { | |
365 | /* since the arg parameter is defined as a long but may be either | |
366 | * a long or a pointer we must take care to handle sign extension | |
367 | * issues. Our sys call munger will sign extend a long when we are | |
368 | * called from a 32-bit process. Since we can never have an address | |
369 | * greater than 32-bits from a 32-bit process we lop off the top | |
370 | * 32-bits to avoid getting the wrong address | |
371 | */ | |
372 | argp = CAST_USER_ADDR_T(uap->arg); | |
373 | } | |
374 | ||
1c79356b | 375 | pop = &fdp->fd_ofileflags[fd]; |
55e303ae | 376 | |
1c79356b A |
377 | switch (uap->cmd) { |
378 | ||
379 | case F_DUPFD: | |
91447636 | 380 | newmin = CAST_DOWN(int, uap->arg); |
1c79356b | 381 | if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || |
91447636 A |
382 | newmin >= maxfiles) { |
383 | error = EINVAL; | |
384 | goto out; | |
385 | } | |
386 | if ( (error = fdalloc(p, newmin, &i)) ) | |
387 | goto out; | |
388 | error = finishdup(p, fdp, fd, i, retval); | |
389 | goto out; | |
1c79356b A |
390 | |
391 | case F_GETFD: | |
392 | *retval = (*pop & UF_EXCLOSE)? 1 : 0; | |
91447636 A |
393 | error = 0; |
394 | goto out; | |
1c79356b A |
395 | |
396 | case F_SETFD: | |
397 | *pop = (*pop &~ UF_EXCLOSE) | | |
91447636 A |
398 | (uap->arg & 1)? UF_EXCLOSE : 0; |
399 | error = 0; | |
400 | goto out; | |
1c79356b A |
401 | |
402 | case F_GETFL: | |
403 | *retval = OFLAGS(fp->f_flag); | |
91447636 A |
404 | error = 0; |
405 | goto out; | |
1c79356b A |
406 | |
407 | case F_SETFL: | |
408 | fp->f_flag &= ~FCNTLFLAGS; | |
91447636 A |
409 | tmp = CAST_DOWN(int, uap->arg); |
410 | fp->f_flag |= FFLAGS(tmp) & FCNTLFLAGS; | |
1c79356b | 411 | tmp = fp->f_flag & FNONBLOCK; |
9bccf70c | 412 | error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p); |
1c79356b | 413 | if (error) |
91447636 | 414 | goto out; |
1c79356b | 415 | tmp = fp->f_flag & FASYNC; |
9bccf70c | 416 | error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, p); |
1c79356b | 417 | if (!error) |
91447636 | 418 | goto out; |
1c79356b A |
419 | fp->f_flag &= ~FNONBLOCK; |
420 | tmp = 0; | |
9bccf70c | 421 | (void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p); |
91447636 | 422 | goto out; |
1c79356b A |
423 | |
424 | case F_GETOWN: | |
425 | if (fp->f_type == DTYPE_SOCKET) { | |
426 | *retval = ((struct socket *)fp->f_data)->so_pgid; | |
91447636 A |
427 | error = 0; |
428 | goto out; | |
1c79356b | 429 | } |
9bccf70c | 430 | error = fo_ioctl(fp, (int)TIOCGPGRP, (caddr_t)retval, p); |
1c79356b | 431 | *retval = -*retval; |
91447636 | 432 | goto out; |
1c79356b A |
433 | |
434 | case F_SETOWN: | |
91447636 | 435 | tmp = CAST_DOWN(pid_t, uap->arg); |
1c79356b | 436 | if (fp->f_type == DTYPE_SOCKET) { |
91447636 A |
437 | ((struct socket *)fp->f_data)->so_pgid = tmp; |
438 | error =0; | |
439 | goto out; | |
1c79356b | 440 | } |
91447636 A |
441 | if (fp->f_type == DTYPE_PIPE) { |
442 | error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); | |
443 | goto out; | |
444 | } | |
445 | ||
446 | if (tmp <= 0) { | |
447 | tmp = -tmp; | |
1c79356b | 448 | } else { |
91447636 A |
449 | struct proc *p1 = pfind(tmp); |
450 | if (p1 == 0) { | |
451 | error = ESRCH; | |
452 | goto out; | |
453 | } | |
454 | tmp = (int)p1->p_pgrp->pg_id; | |
1c79356b | 455 | } |
91447636 A |
456 | error = fo_ioctl(fp, (int)TIOCSPGRP, (caddr_t)&tmp, p); |
457 | goto out; | |
1c79356b A |
458 | |
459 | case F_SETLKW: | |
460 | flg |= F_WAIT; | |
461 | /* Fall into F_SETLK */ | |
462 | ||
463 | case F_SETLK: | |
91447636 A |
464 | if (fp->f_type != DTYPE_VNODE) { |
465 | error = EBADF; | |
466 | goto out; | |
467 | } | |
1c79356b | 468 | vp = (struct vnode *)fp->f_data; |
ccc36f2f | 469 | |
91447636 A |
470 | fflag = fp->f_flag; |
471 | offset = fp->f_offset; | |
472 | proc_fdunlock(p); | |
473 | ||
1c79356b | 474 | /* Copy in the lock structure */ |
91447636 A |
475 | error = copyin(argp, (caddr_t)&fl, sizeof (fl)); |
476 | if (error) { | |
477 | goto outdrop; | |
478 | } | |
479 | if ( (error = vnode_getwithref(vp)) ) { | |
480 | goto outdrop; | |
481 | } | |
1c79356b | 482 | if (fl.l_whence == SEEK_CUR) |
91447636 A |
483 | fl.l_start += offset; |
484 | ||
1c79356b A |
485 | switch (fl.l_type) { |
486 | ||
487 | case F_RDLCK: | |
91447636 A |
488 | if ((fflag & FREAD) == 0) { |
489 | (void)vnode_put(vp); | |
ccc36f2f | 490 | error = EBADF; |
91447636 A |
491 | goto outdrop; |
492 | } | |
b36670ce | 493 | OSBitOrAtomic(P_LADVLOCK, &p->p_ladvflag); |
91447636 A |
494 | error = VNOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg, &context); |
495 | (void)vnode_put(vp); | |
496 | goto outdrop; | |
1c79356b A |
497 | |
498 | case F_WRLCK: | |
91447636 A |
499 | if ((fflag & FWRITE) == 0) { |
500 | (void)vnode_put(vp); | |
ccc36f2f | 501 | error = EBADF; |
91447636 A |
502 | goto outdrop; |
503 | } | |
b36670ce | 504 | OSBitOrAtomic(P_LADVLOCK, &p->p_ladvflag); |
91447636 A |
505 | error = VNOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg, &context); |
506 | (void)vnode_put(vp); | |
507 | goto outdrop; | |
1c79356b A |
508 | |
509 | case F_UNLCK: | |
91447636 A |
510 | error = VNOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, |
511 | F_POSIX, &context); | |
512 | (void)vnode_put(vp); | |
513 | goto outdrop; | |
1c79356b A |
514 | |
515 | default: | |
91447636 | 516 | (void)vnode_put(vp); |
ccc36f2f | 517 | error = EINVAL; |
91447636 | 518 | goto outdrop; |
1c79356b A |
519 | } |
520 | ||
521 | case F_GETLK: | |
91447636 A |
522 | if (fp->f_type != DTYPE_VNODE) { |
523 | error = EBADF; | |
524 | goto out; | |
525 | } | |
1c79356b | 526 | vp = (struct vnode *)fp->f_data; |
ccc36f2f | 527 | |
91447636 A |
528 | offset = fp->f_offset; |
529 | proc_fdunlock(p); | |
530 | ||
1c79356b | 531 | /* Copy in the lock structure */ |
91447636 | 532 | error = copyin(argp, (caddr_t)&fl, sizeof (fl)); |
1c79356b | 533 | if (error) |
91447636 A |
534 | goto outdrop; |
535 | ||
536 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
537 | if (fl.l_whence == SEEK_CUR) | |
538 | fl.l_start += offset; | |
539 | ||
540 | error = VNOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX, &context); | |
541 | ||
542 | (void)vnode_put(vp); | |
543 | ||
544 | if (error == 0) | |
545 | error = copyout((caddr_t)&fl, argp, sizeof (fl)); | |
546 | } | |
547 | goto outdrop; | |
548 | ||
549 | case F_PREALLOCATE: { | |
550 | fstore_t alloc_struct; /* structure for allocate command */ | |
551 | u_int32_t alloc_flags = 0; | |
552 | ||
553 | if (fp->f_type != DTYPE_VNODE) { | |
554 | error = EBADF; | |
555 | goto out; | |
556 | } | |
1c79356b | 557 | |
ccc36f2f | 558 | vp = (struct vnode *)fp->f_data; |
91447636 | 559 | proc_fdunlock(p); |
9bccf70c A |
560 | |
561 | /* make sure that we have write permission */ | |
ccc36f2f A |
562 | if ((fp->f_flag & FWRITE) == 0) { |
563 | error = EBADF; | |
91447636 | 564 | goto outdrop; |
ccc36f2f | 565 | } |
1c79356b | 566 | |
91447636 | 567 | error = copyin(argp, (caddr_t)&alloc_struct, sizeof (alloc_struct)); |
1c79356b | 568 | if (error) |
91447636 | 569 | goto outdrop; |
1c79356b | 570 | |
9bccf70c | 571 | /* now set the space allocated to 0 */ |
1c79356b A |
572 | alloc_struct.fst_bytesalloc = 0; |
573 | ||
9bccf70c A |
574 | /* |
575 | * Do some simple parameter checking | |
576 | */ | |
1c79356b A |
577 | |
578 | /* set up the flags */ | |
579 | ||
580 | alloc_flags |= PREALLOCATE; | |
581 | ||
9bccf70c | 582 | if (alloc_struct.fst_flags & F_ALLOCATECONTIG) |
1c79356b | 583 | alloc_flags |= ALLOCATECONTIG; |
1c79356b | 584 | |
9bccf70c A |
585 | if (alloc_struct.fst_flags & F_ALLOCATEALL) |
586 | alloc_flags |= ALLOCATEALL; | |
1c79356b | 587 | |
9bccf70c A |
588 | /* |
589 | * Do any position mode specific stuff. The only | |
590 | * position mode supported now is PEOFPOSMODE | |
591 | */ | |
1c79356b A |
592 | |
593 | switch (alloc_struct.fst_posmode) { | |
594 | ||
595 | case F_PEOFPOSMODE: | |
91447636 | 596 | if (alloc_struct.fst_offset != 0) { |
ccc36f2f | 597 | error = EINVAL; |
91447636 A |
598 | goto outdrop; |
599 | } | |
600 | ||
601 | alloc_flags |= ALLOCATEFROMPEOF; | |
1c79356b A |
602 | break; |
603 | ||
0b4e3aa0 | 604 | case F_VOLPOSMODE: |
91447636 | 605 | if (alloc_struct.fst_offset <= 0) { |
ccc36f2f | 606 | error = EINVAL; |
91447636 A |
607 | goto outdrop; |
608 | } | |
609 | ||
610 | alloc_flags |= ALLOCATEFROMVOL; | |
0b4e3aa0 A |
611 | break; |
612 | ||
91447636 | 613 | default: { |
ccc36f2f | 614 | error = EINVAL; |
91447636 A |
615 | goto outdrop; |
616 | } | |
1c79356b | 617 | } |
91447636 A |
618 | if ( (error = vnode_getwithref(vp)) == 0 ) { |
619 | /* | |
620 | * call allocate to get the space | |
621 | */ | |
622 | error = VNOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags, | |
623 | &alloc_struct.fst_bytesalloc, alloc_struct.fst_offset, | |
624 | &context); | |
625 | (void)vnode_put(vp); | |
1c79356b | 626 | |
91447636 | 627 | error2 = copyout((caddr_t)&alloc_struct, argp, sizeof (alloc_struct)); |
1c79356b | 628 | |
91447636 | 629 | if (error == 0) |
ccc36f2f | 630 | error = error2; |
1c79356b | 631 | } |
91447636 | 632 | goto outdrop; |
1c79356b | 633 | |
91447636 | 634 | } |
9bccf70c | 635 | case F_SETSIZE: |
91447636 A |
636 | if (fp->f_type != DTYPE_VNODE) { |
637 | error = EBADF; | |
638 | goto out; | |
639 | } | |
640 | proc_fdunlock(p); | |
ccc36f2f | 641 | |
91447636 | 642 | error = copyin(argp, (caddr_t)&offset, sizeof (off_t)); |
1c79356b | 643 | if (error) |
91447636 | 644 | goto outdrop; |
1c79356b | 645 | |
9bccf70c A |
646 | /* |
647 | * Make sure that we are root. Growing a file | |
648 | * without zero filling the data is a security hole | |
649 | * root would have access anyway so we'll allow it | |
650 | */ | |
1c79356b | 651 | |
ccc36f2f A |
652 | if (!is_suser()) { |
653 | error = EACCES; | |
91447636 | 654 | goto outdrop; |
ccc36f2f | 655 | } |
91447636 | 656 | vp = (struct vnode *)fp->f_data; |
1c79356b | 657 | |
91447636 A |
658 | if ( (error = vnode_getwithref(vp)) == 0 ) { |
659 | /* | |
660 | * set the file size | |
661 | */ | |
662 | error = vnode_setsize(vp, offset, IO_NOZEROFILL, &context); | |
663 | ||
664 | (void)vnode_put(vp); | |
665 | } | |
666 | goto outdrop; | |
9bccf70c A |
667 | |
668 | case F_RDAHEAD: | |
91447636 A |
669 | if (fp->f_type != DTYPE_VNODE) { |
670 | error = EBADF; | |
671 | goto out; | |
672 | } | |
9bccf70c | 673 | vp = (struct vnode *)fp->f_data; |
91447636 | 674 | proc_fdunlock(p); |
9bccf70c | 675 | |
91447636 A |
676 | if ( (error = vnode_getwithref(vp)) == 0) { |
677 | if (uap->arg) | |
678 | vnode_clearnoreadahead(vp); | |
679 | else | |
680 | vnode_setnoreadahead(vp); | |
681 | ||
682 | (void)vnode_put(vp); | |
683 | } | |
684 | goto outdrop; | |
1c79356b | 685 | |
9bccf70c | 686 | case F_NOCACHE: |
91447636 A |
687 | if (fp->f_type != DTYPE_VNODE) { |
688 | error = EBADF; | |
689 | goto out; | |
690 | } | |
9bccf70c | 691 | vp = (struct vnode *)fp->f_data; |
91447636 | 692 | proc_fdunlock(p); |
9bccf70c | 693 | |
91447636 A |
694 | if ( (error = vnode_getwithref(vp)) == 0 ) { |
695 | if (uap->arg) | |
696 | vnode_setnocache(vp); | |
697 | else | |
698 | vnode_clearnocache(vp); | |
1c79356b | 699 | |
91447636 A |
700 | (void)vnode_put(vp); |
701 | } | |
702 | goto outdrop; | |
1c79356b | 703 | |
91447636 A |
704 | case F_RDADVISE: { |
705 | struct radvisory ra_struct; | |
9bccf70c | 706 | |
91447636 A |
707 | if (fp->f_type != DTYPE_VNODE) { |
708 | error = EBADF; | |
709 | goto out; | |
710 | } | |
55e303ae | 711 | vp = (struct vnode *)fp->f_data; |
91447636 | 712 | proc_fdunlock(p); |
55e303ae | 713 | |
91447636 A |
714 | if ( (error = copyin(argp, (caddr_t)&ra_struct, sizeof (ra_struct))) ) |
715 | goto outdrop; | |
716 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
717 | error = VNOP_IOCTL(vp, F_RDADVISE, (caddr_t)&ra_struct, 0, &context); | |
718 | ||
719 | (void)vnode_put(vp); | |
720 | } | |
721 | goto outdrop; | |
722 | } | |
55e303ae | 723 | |
1c79356b | 724 | case F_READBOOTSTRAP: |
91447636 A |
725 | case F_WRITEBOOTSTRAP: { |
726 | fbootstraptransfer_t fbt_struct; | |
727 | user_fbootstraptransfer_t user_fbt_struct; | |
728 | int sizeof_struct; | |
729 | caddr_t boot_structp; | |
730 | ||
731 | if (fp->f_type != DTYPE_VNODE) { | |
732 | error = EBADF; | |
733 | goto out; | |
734 | } | |
ccc36f2f | 735 | vp = (struct vnode *)fp->f_data; |
91447636 | 736 | proc_fdunlock(p); |
1c79356b | 737 | |
91447636 A |
738 | if (IS_64BIT_PROCESS(p)) { |
739 | sizeof_struct = sizeof(user_fbt_struct); | |
740 | boot_structp = (caddr_t) &user_fbt_struct; | |
741 | } | |
742 | else { | |
743 | sizeof_struct = sizeof(fbt_struct); | |
744 | boot_structp = (caddr_t) &fbt_struct; | |
745 | } | |
746 | error = copyin(argp, boot_structp, sizeof_struct); | |
1c79356b | 747 | if (error) |
91447636 A |
748 | goto outdrop; |
749 | if ( (error = vnode_getwithref(vp)) ) { | |
750 | goto outdrop; | |
751 | } | |
1c79356b | 752 | if (uap->cmd == F_WRITEBOOTSTRAP) { |
91447636 A |
753 | /* |
754 | * Make sure that we are root. Updating the | |
755 | * bootstrap on a disk could be a security hole | |
756 | */ | |
ccc36f2f | 757 | if (!is_suser()) { |
91447636 | 758 | (void)vnode_put(vp); |
ccc36f2f | 759 | error = EACCES; |
91447636 | 760 | goto outdrop; |
ccc36f2f | 761 | } |
9bccf70c | 762 | } |
91447636 | 763 | if (strcmp(vnode_mount(vp)->mnt_vfsstat.f_fstypename, "hfs") != 0) { |
9bccf70c | 764 | error = EINVAL; |
91447636 A |
765 | } else { |
766 | /* | |
767 | * call vnop_ioctl to handle the I/O | |
768 | */ | |
769 | error = VNOP_IOCTL(vp, uap->cmd, boot_structp, 0, &context); | |
9bccf70c | 770 | } |
91447636 A |
771 | (void)vnode_put(vp); |
772 | goto outdrop; | |
773 | } | |
774 | case F_LOG2PHYS: { | |
775 | struct log2phys l2p_struct; /* structure for allocate command */ | |
9bccf70c | 776 | |
91447636 A |
777 | if (fp->f_type != DTYPE_VNODE) { |
778 | error = EBADF; | |
779 | goto out; | |
780 | } | |
1c79356b | 781 | vp = (struct vnode *)fp->f_data; |
91447636 A |
782 | proc_fdunlock(p); |
783 | if ( (error = vnode_getwithref(vp)) ) { | |
784 | goto outdrop; | |
785 | } | |
786 | error = VNOP_OFFTOBLK(vp, fp->f_offset, &lbn); | |
787 | if (error) { | |
788 | (void)vnode_put(vp); | |
789 | goto outdrop; | |
790 | } | |
791 | error = VNOP_BLKTOOFF(vp, lbn, &offset); | |
792 | if (error) { | |
793 | (void)vnode_put(vp); | |
794 | goto outdrop; | |
795 | } | |
796 | devBlockSize = vfs_devblocksize(vnode_mount(vp)); | |
797 | ||
798 | error = VNOP_BLOCKMAP(vp, offset, devBlockSize, &bn, NULL, NULL, 0, &context); | |
799 | ||
800 | (void)vnode_put(vp); | |
ccc36f2f | 801 | |
1c79356b A |
802 | if (!error) { |
803 | l2p_struct.l2p_flags = 0; /* for now */ | |
804 | l2p_struct.l2p_contigbytes = 0; /* for now */ | |
805 | l2p_struct.l2p_devoffset = bn * devBlockSize; | |
806 | l2p_struct.l2p_devoffset += fp->f_offset - offset; | |
91447636 A |
807 | error = copyout((caddr_t)&l2p_struct, argp, sizeof (l2p_struct)); |
808 | } | |
809 | goto outdrop; | |
1c79356b | 810 | } |
55e303ae | 811 | case F_GETPATH: { |
91447636 A |
812 | char *pathbufp; |
813 | int pathlen; | |
55e303ae | 814 | |
91447636 A |
815 | if (fp->f_type != DTYPE_VNODE) { |
816 | error = EBADF; | |
817 | goto out; | |
818 | } | |
55e303ae | 819 | vp = (struct vnode *)fp->f_data; |
91447636 | 820 | proc_fdunlock(p); |
55e303ae | 821 | |
91447636 A |
822 | pathlen = MAXPATHLEN; |
823 | MALLOC(pathbufp, char *, pathlen, M_TEMP, M_WAITOK); | |
824 | if (pathbufp == NULL) { | |
825 | error = ENOMEM; | |
826 | goto outdrop; | |
827 | } | |
828 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
829 | error = vn_getpath(vp, pathbufp, &pathlen); | |
830 | (void)vnode_put(vp); | |
4a249263 | 831 | |
91447636 A |
832 | if (error == 0) |
833 | error = copyout((caddr_t)pathbufp, argp, pathlen); | |
834 | } | |
835 | FREE(pathbufp, M_TEMP); | |
836 | goto outdrop; | |
55e303ae A |
837 | } |
838 | ||
91447636 A |
839 | case F_PATHPKG_CHECK: { |
840 | char *pathbufp; | |
841 | size_t pathlen; | |
842 | ||
843 | if (fp->f_type != DTYPE_VNODE) { | |
844 | error = EBADF; | |
845 | goto out; | |
846 | } | |
55e303ae | 847 | vp = (struct vnode *)fp->f_data; |
91447636 | 848 | proc_fdunlock(p); |
55e303ae | 849 | |
91447636 A |
850 | pathlen = MAXPATHLEN; |
851 | pathbufp = kalloc(MAXPATHLEN); | |
852 | ||
853 | if ( (error = copyinstr(argp, pathbufp, MAXPATHLEN, &pathlen)) == 0 ) { | |
854 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
855 | error = vn_path_package_check(vp, pathbufp, pathlen, retval); | |
856 | ||
857 | (void)vnode_put(vp); | |
858 | } | |
859 | } | |
860 | kfree(pathbufp, MAXPATHLEN); | |
861 | goto outdrop; | |
862 | } | |
863 | ||
864 | case F_CHKCLEAN: // used by regression tests to see if all dirty pages got cleaned by fsync() | |
865 | case F_FULLFSYNC: // fsync + flush the journal + DKIOCSYNCHRONIZECACHE | |
866 | case F_FREEZE_FS: // freeze all other fs operations for the fs of this fd | |
867 | case F_THAW_FS: { // thaw all frozen fs operations for the fs of this fd | |
868 | if (fp->f_type != DTYPE_VNODE) { | |
869 | error = EBADF; | |
870 | goto out; | |
871 | } | |
872 | vp = (struct vnode *)fp->f_data; | |
873 | proc_fdunlock(p); | |
ccc36f2f | 874 | |
91447636 A |
875 | if ( (error = vnode_getwithref(vp)) == 0 ) { |
876 | error = VNOP_IOCTL(vp, uap->cmd, (caddr_t)NULL, 0, &context); | |
877 | ||
878 | (void)vnode_put(vp); | |
879 | } | |
ccc36f2f | 880 | break; |
55e303ae A |
881 | } |
882 | ||
1c79356b | 883 | default: |
91447636 A |
884 | if (uap->cmd < FCNTL_FS_SPECIFIC_BASE) { |
885 | error = EINVAL; | |
886 | goto out; | |
887 | } | |
888 | ||
889 | // if it's a fs-specific fcntl() then just pass it through | |
890 | ||
891 | if (fp->f_type != DTYPE_VNODE) { | |
892 | error = EBADF; | |
893 | goto out; | |
894 | } | |
895 | vp = (struct vnode *)fp->f_data; | |
896 | proc_fdunlock(p); | |
897 | ||
898 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
899 | error = VNOP_IOCTL(vp, uap->cmd, CAST_DOWN(caddr_t, argp), 0, &context); | |
900 | ||
901 | (void)vnode_put(vp); | |
902 | } | |
903 | break; | |
904 | ||
1c79356b | 905 | } |
ccc36f2f | 906 | |
91447636 A |
907 | outdrop: |
908 | AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1); | |
909 | fp_drop(p, fd, fp, 0); | |
910 | return(error); | |
911 | out: | |
912 | fp_drop(p, fd, fp, 1); | |
913 | proc_fdunlock(p); | |
914 | return(error); | |
1c79356b A |
915 | } |
916 | ||
917 | /* | |
918 | * Common code for dup, dup2, and fcntl(F_DUPFD). | |
919 | */ | |
920 | int | |
91447636 | 921 | finishdup(struct proc * p, struct filedesc *fdp, int old, int new, register_t *retval) |
1c79356b | 922 | { |
91447636 A |
923 | struct fileproc *nfp; |
924 | struct fileproc *ofp; | |
1c79356b | 925 | |
91447636 | 926 | if ((ofp = fdp->fd_ofiles[old]) == NULL || |
1c79356b A |
927 | (fdp->fd_ofileflags[old] & UF_RESERVED)) { |
928 | _fdrelse(fdp, new); | |
929 | return (EBADF); | |
930 | } | |
91447636 A |
931 | fg_ref(ofp); |
932 | proc_fdunlock(p); | |
933 | ||
934 | MALLOC_ZONE(nfp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK); | |
935 | bzero(nfp, sizeof(struct fileproc)); | |
936 | ||
937 | proc_fdlock(p); | |
938 | nfp->f_flags = ofp->f_flags; | |
939 | nfp->f_fglob = ofp->f_fglob; | |
940 | nfp->f_iocount = 0; | |
941 | ||
942 | fdp->fd_ofiles[new] = nfp; | |
1c79356b | 943 | fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; |
1c79356b A |
944 | if (new > fdp->fd_lastfile) |
945 | fdp->fd_lastfile = new; | |
946 | *retval = new; | |
947 | return (0); | |
948 | } | |
949 | ||
91447636 | 950 | |
1c79356b | 951 | int |
91447636 | 952 | close(struct proc *p, struct close_args *uap, __unused register_t *retval) |
1c79356b | 953 | { |
91447636 | 954 | struct fileproc *fp; |
1c79356b | 955 | int fd = uap->fd; |
91447636 | 956 | int error =0; |
1c79356b | 957 | |
e5568f75 | 958 | AUDIT_SYSCLOSE(p, fd); |
91447636 A |
959 | |
960 | proc_fdlock(p); | |
961 | ||
962 | if ( (error = fp_lookup(p,fd,&fp, 1)) ) { | |
963 | proc_fdunlock(p); | |
964 | return(error); | |
965 | } | |
966 | ||
967 | error = close_internal(p, fd, fp, CLOSEINT_LOCKED | CLOSEINT_WAITONCLOSE); | |
968 | ||
969 | proc_fdunlock(p); | |
970 | ||
971 | return(error); | |
972 | } | |
973 | ||
974 | ||
975 | /* | |
976 | * Close a file descriptor. | |
977 | */ | |
978 | int | |
979 | close_internal(struct proc *p, int fd, struct fileproc *fp, int flags) | |
980 | { | |
981 | struct filedesc *fdp = p->p_fd; | |
982 | int error =0; | |
983 | int locked = flags & CLOSEINT_LOCKED; | |
984 | int waitonclose = flags & CLOSEINT_WAITONCLOSE; | |
985 | int norelse = flags & CLOSEINT_NOFDRELSE; | |
986 | int nofdref = flags & CLOSEINT_NOFDNOREF; | |
987 | int slpstate = PRIBIO; | |
988 | ||
989 | if (!locked) | |
990 | proc_fdlock(p); | |
55e303ae A |
991 | |
992 | /* Keep people from using the filedesc while we are closing it */ | |
993 | fdp->fd_ofileflags[fd] |= UF_RESERVED; | |
55e303ae | 994 | |
91447636 A |
995 | fdp->fd_ofileflags[fd] |= UF_CLOSING; |
996 | ||
997 | ||
998 | if ((waitonclose && ((fp->f_flags & FP_CLOSING) == FP_CLOSING))) { | |
999 | if (nofdref == 0) | |
1000 | fp_drop(p, fd, fp, 1); | |
1001 | fp->f_flags |= FP_WAITCLOSE; | |
1002 | if (!locked) | |
1003 | slpstate |= PDROP; | |
1004 | msleep(&fp->f_flags, &p->p_fdmlock, slpstate, "close wait",0) ; | |
1005 | return(EBADF); | |
1006 | } | |
1007 | ||
1008 | fp->f_flags |= FP_CLOSING; | |
1009 | if (nofdref) | |
1010 | fp->f_iocount++; | |
1011 | ||
1012 | if ( (fp->f_flags & FP_AIOISSUED) || kauth_authorize_fileop_has_listeners() ) { | |
1013 | ||
1014 | proc_fdunlock(p); | |
1015 | ||
1016 | if ( (fp->f_type == DTYPE_VNODE) && kauth_authorize_fileop_has_listeners() ) { | |
1017 | /* | |
1018 | * call out to allow 3rd party notification of close. | |
1019 | * Ignore result of kauth_authorize_fileop call. | |
1020 | */ | |
1021 | if (vnode_getwithref((vnode_t)fp->f_data) == 0) { | |
1022 | u_int fileop_flags = 0; | |
1023 | if ((fp->f_flags & FP_WRITTEN) != 0) | |
1024 | fileop_flags |= KAUTH_FILEOP_CLOSE_MODIFIED; | |
1025 | kauth_authorize_fileop(fp->f_fglob->fg_cred, KAUTH_FILEOP_CLOSE, | |
1026 | (uintptr_t)fp->f_data, (uintptr_t)fileop_flags); | |
1027 | vnode_put((vnode_t)fp->f_data); | |
1028 | } | |
1029 | } | |
1030 | if (fp->f_flags & FP_AIOISSUED) | |
1031 | /* | |
1032 | * cancel all async IO requests that can be cancelled. | |
1033 | */ | |
1034 | _aio_close( p, fd ); | |
1035 | ||
1036 | proc_fdlock(p); | |
1037 | } | |
1038 | ||
1039 | if (fd < fdp->fd_knlistsize) | |
55e303ae A |
1040 | knote_fdclose(p, fd); |
1041 | ||
91447636 A |
1042 | if (fp->f_flags & FP_WAITEVENT) |
1043 | (void)waitevent_close(p, fp); | |
1044 | ||
1045 | if ((fp->f_flags & FP_INCHRREAD) == 0) | |
1046 | fileproc_drain(p, fp); | |
1047 | if (norelse == 0) | |
1048 | _fdrelse(fdp, fd); | |
1049 | error = closef_locked(fp, fp->f_fglob, p); | |
1050 | if ((fp->f_flags & FP_WAITCLOSE) == FP_WAITCLOSE) | |
1051 | wakeup(&fp->f_flags); | |
1052 | fp->f_flags &= ~(FP_WAITCLOSE | FP_CLOSING); | |
1053 | ||
1054 | if (!locked) | |
1055 | proc_fdunlock(p); | |
1056 | ||
1057 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1058 | return(error); | |
1c79356b A |
1059 | } |
1060 | ||
1061 | /* | |
1062 | * Return status information about a file descriptor. | |
91447636 A |
1063 | * |
1064 | * XXX switch on node type is bogus; need a stat in struct fileops instead. | |
1c79356b | 1065 | */ |
91447636 A |
1066 | static int |
1067 | fstat1(struct proc *p, int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) | |
1c79356b | 1068 | { |
91447636 A |
1069 | struct fileproc *fp; |
1070 | struct stat sb; | |
1071 | struct user_stat user_sb; | |
1072 | int error, my_size; | |
1073 | int funnel_state; | |
1074 | short type; | |
1075 | caddr_t data; | |
1076 | kauth_filesec_t fsec; | |
1077 | ssize_t xsecurity_bufsize; | |
1078 | int entrycount; | |
1079 | struct vfs_context context; | |
1c79356b | 1080 | |
91447636 A |
1081 | |
1082 | AUDIT_ARG(fd, fd); | |
1083 | ||
1084 | if ((error = fp_lookup(p, fd, &fp, 0)) != 0) | |
1085 | return(error); | |
1086 | type = fp->f_type; | |
1087 | data = fp->f_data; | |
1088 | fsec = KAUTH_FILESEC_NONE; | |
1089 | ||
1090 | switch (type) { | |
1c79356b A |
1091 | |
1092 | case DTYPE_VNODE: | |
91447636 A |
1093 | context.vc_proc = current_proc(); |
1094 | context.vc_ucred = kauth_cred_get(); | |
1095 | if ((error = vnode_getwithref((vnode_t)data)) == 0) { | |
1096 | /* | |
1097 | * If the caller has the file open, and is not requesting extended security, | |
1098 | * we are going to let them get the basic stat information. | |
1099 | */ | |
1100 | if (xsecurity == USER_ADDR_NULL) { | |
1101 | error = vn_stat_noauth((vnode_t)data, &sb, NULL, &context); | |
1102 | } else { | |
1103 | error = vn_stat((vnode_t)data, &sb, &fsec, &context); | |
1104 | } | |
1105 | ||
1106 | AUDIT_ARG(vnpath, (struct vnode *)data, ARG_VNODE1); | |
1107 | (void)vnode_put((vnode_t)data); | |
55e303ae | 1108 | } |
1c79356b A |
1109 | break; |
1110 | ||
1111 | case DTYPE_SOCKET: | |
91447636 A |
1112 | error = soo_stat((struct socket *)data, &sb); |
1113 | break; | |
1114 | ||
1115 | case DTYPE_PIPE: | |
1116 | error = pipe_stat((void *)data, &sb); | |
1c79356b A |
1117 | break; |
1118 | ||
1119 | case DTYPE_PSXSHM: | |
91447636 | 1120 | error = pshm_stat((void *)data, &sb); |
1c79356b | 1121 | break; |
55e303ae A |
1122 | |
1123 | case DTYPE_KQUEUE: | |
91447636 A |
1124 | funnel_state = thread_funnel_set(kernel_flock, TRUE); |
1125 | error = kqueue_stat(fp, &sb, p); | |
1126 | thread_funnel_set(kernel_flock, funnel_state); | |
1127 | break; | |
55e303ae | 1128 | |
1c79356b | 1129 | default: |
91447636 A |
1130 | error = EBADF; |
1131 | goto out; | |
1132 | } | |
1133 | /* Zap spare fields */ | |
1134 | sb.st_lspare = 0; | |
1135 | sb.st_qspare[0] = 0LL; | |
1136 | sb.st_qspare[1] = 0LL; | |
1137 | if (error == 0) { | |
1138 | caddr_t sbp; | |
1139 | if (IS_64BIT_PROCESS(current_proc())) { | |
1140 | munge_stat(&sb, &user_sb); | |
1141 | my_size = sizeof(user_sb); | |
1142 | sbp = (caddr_t)&user_sb; | |
1143 | } | |
1144 | else { | |
1145 | my_size = sizeof(sb); | |
1146 | sbp = (caddr_t)&sb; | |
1147 | } | |
1148 | error = copyout(sbp, ub, my_size); | |
1c79356b | 1149 | } |
1c79356b | 1150 | |
91447636 A |
1151 | /* caller wants extended security information? */ |
1152 | if (xsecurity != USER_ADDR_NULL) { | |
1c79356b | 1153 | |
91447636 A |
1154 | /* did we get any? */ |
1155 | if (fsec == KAUTH_FILESEC_NONE) { | |
1156 | if (susize(xsecurity_size, 0) != 0) { | |
1157 | error = EFAULT; | |
1158 | goto out; | |
1159 | } | |
1160 | } else { | |
1161 | /* find the user buffer size */ | |
1162 | xsecurity_bufsize = fusize(xsecurity_size); | |
1c79356b | 1163 | |
91447636 A |
1164 | /* copy out the actual data size */ |
1165 | if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) { | |
1166 | error = EFAULT; | |
1167 | goto out; | |
1168 | } | |
1c79356b | 1169 | |
91447636 A |
1170 | /* if the caller supplied enough room, copy out to it */ |
1171 | if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec)) | |
1172 | error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec)); | |
1173 | } | |
1c79356b | 1174 | } |
91447636 A |
1175 | out: |
1176 | fp_drop(p, fd, fp, 0); | |
1177 | if (fsec != NULL) | |
1178 | kauth_filesec_free(fsec); | |
1c79356b A |
1179 | return (error); |
1180 | } | |
91447636 A |
1181 | |
1182 | int | |
1183 | fstat_extended(struct proc *p, struct fstat_extended_args *uap, __unused register_t *retval) | |
1184 | { | |
1185 | return(fstat1(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size)); | |
1186 | } | |
1187 | ||
1188 | int | |
1189 | fstat(struct proc *p, register struct fstat_args *uap, __unused register_t *retval) | |
1190 | { | |
1191 | return(fstat1(p, uap->fd, uap->ub, 0, 0)); | |
1192 | } | |
1c79356b A |
1193 | |
1194 | /* | |
1195 | * Return pathconf information about a file descriptor. | |
1196 | */ | |
91447636 | 1197 | int |
1c79356b A |
1198 | fpathconf(p, uap, retval) |
1199 | struct proc *p; | |
1200 | register struct fpathconf_args *uap; | |
1201 | register_t *retval; | |
1202 | { | |
1203 | int fd = uap->fd; | |
91447636 | 1204 | struct fileproc *fp; |
1c79356b | 1205 | struct vnode *vp; |
91447636 A |
1206 | struct vfs_context context; |
1207 | int error = 0; | |
1208 | short type; | |
1209 | caddr_t data; | |
1210 | ||
1c79356b | 1211 | |
55e303ae | 1212 | AUDIT_ARG(fd, uap->fd); |
91447636 A |
1213 | if ( (error = fp_lookup(p, fd, &fp, 0)) ) |
1214 | return(error); | |
1215 | type = fp->f_type; | |
1216 | data = fp->f_data; | |
1217 | ||
1218 | switch (type) { | |
1c79356b A |
1219 | |
1220 | case DTYPE_SOCKET: | |
91447636 A |
1221 | if (uap->name != _PC_PIPE_BUF) { |
1222 | error = EINVAL; | |
1223 | goto out; | |
1224 | } | |
1c79356b | 1225 | *retval = PIPE_BUF; |
91447636 A |
1226 | error = 0; |
1227 | goto out; | |
1228 | ||
1229 | case DTYPE_PIPE: | |
1230 | *retval = PIPE_BUF; | |
1231 | error = 0; | |
1232 | goto out; | |
1c79356b A |
1233 | |
1234 | case DTYPE_VNODE: | |
91447636 A |
1235 | vp = (struct vnode *)data; |
1236 | ||
1237 | if ( (error = vnode_getwithref(vp)) == 0) { | |
1238 | AUDIT_ARG(vnpath, vp, ARG_VNODE1); | |
1239 | ||
1240 | context.vc_proc = p; | |
1241 | context.vc_ucred = kauth_cred_get(); | |
1242 | ||
1243 | error = vn_pathconf(vp, uap->name, retval, &context); | |
1244 | ||
1245 | (void)vnode_put(vp); | |
1246 | } | |
1247 | goto out; | |
55e303ae | 1248 | |
91447636 A |
1249 | case DTYPE_PSXSHM: |
1250 | case DTYPE_KQUEUE: | |
1251 | error = EINVAL; | |
1252 | goto out; | |
1c79356b A |
1253 | |
1254 | default: | |
91447636 | 1255 | panic("fpathconf (unrecognized - %d)", type); |
1c79356b A |
1256 | } |
1257 | /*NOTREACHED*/ | |
91447636 A |
1258 | out: |
1259 | fp_drop(p, fd, fp, 0); | |
1260 | return(error); | |
1c79356b A |
1261 | } |
1262 | ||
1263 | /* | |
1264 | * Allocate a file descriptor for the process. | |
1265 | */ | |
1266 | int fdexpand; | |
1267 | ||
1268 | int | |
1269 | fdalloc(p, want, result) | |
1270 | struct proc *p; | |
1271 | int want; | |
1272 | int *result; | |
1273 | { | |
1274 | register struct filedesc *fdp = p->p_fd; | |
1275 | register int i; | |
91447636 A |
1276 | int lim, last, numfiles, oldnfiles; |
1277 | struct fileproc **newofiles, **ofiles; | |
1c79356b A |
1278 | char *newofileflags, *ofileflags; |
1279 | ||
1280 | /* | |
1281 | * Search for a free descriptor starting at the higher | |
1282 | * of want or fd_freefile. If that fails, consider | |
1283 | * expanding the ofile array. | |
1284 | */ | |
1285 | lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); | |
1286 | for (;;) { | |
1287 | last = min(fdp->fd_nfiles, lim); | |
1288 | if ((i = want) < fdp->fd_freefile) | |
1289 | i = fdp->fd_freefile; | |
1290 | ofiles = &fdp->fd_ofiles[i]; | |
1291 | ofileflags = &fdp->fd_ofileflags[i]; | |
1292 | for (; i < last; i++) { | |
1293 | if (*ofiles == NULL && !(*ofileflags & UF_RESERVED)) { | |
1294 | *ofileflags = UF_RESERVED; | |
1295 | if (i > fdp->fd_lastfile) | |
1296 | fdp->fd_lastfile = i; | |
1297 | if (want <= fdp->fd_freefile) | |
1298 | fdp->fd_freefile = i; | |
1299 | *result = i; | |
1300 | return (0); | |
1301 | } | |
1302 | ofiles++; ofileflags++; | |
1303 | } | |
1304 | ||
1305 | /* | |
1306 | * No space in current array. Expand? | |
1307 | */ | |
1308 | if (fdp->fd_nfiles >= lim) | |
1309 | return (EMFILE); | |
1310 | if (fdp->fd_nfiles < NDEXTENT) | |
91447636 | 1311 | numfiles = NDEXTENT; |
1c79356b | 1312 | else |
91447636 | 1313 | numfiles = 2 * fdp->fd_nfiles; |
1c79356b | 1314 | /* Enforce lim */ |
91447636 A |
1315 | if (numfiles > lim) |
1316 | numfiles = lim; | |
1317 | proc_fdunlock(p); | |
1318 | MALLOC_ZONE(newofiles, struct fileproc **, | |
1319 | numfiles * OFILESIZE, M_OFILETABL, M_WAITOK); | |
1320 | proc_fdlock(p); | |
1321 | if (newofiles == NULL) { | |
1322 | return (ENOMEM); | |
1323 | } | |
1324 | if (fdp->fd_nfiles >= numfiles) { | |
1325 | FREE_ZONE(newofiles, numfiles * OFILESIZE, M_OFILETABL); | |
1c79356b A |
1326 | continue; |
1327 | } | |
91447636 | 1328 | newofileflags = (char *) &newofiles[numfiles]; |
1c79356b A |
1329 | /* |
1330 | * Copy the existing ofile and ofileflags arrays | |
1331 | * and zero the new portion of each array. | |
1332 | */ | |
1333 | oldnfiles = fdp->fd_nfiles; | |
1334 | (void) memcpy(newofiles, fdp->fd_ofiles, | |
1335 | oldnfiles * sizeof *fdp->fd_ofiles); | |
1336 | (void) memset(&newofiles[oldnfiles], 0, | |
91447636 | 1337 | (numfiles - oldnfiles) * sizeof *fdp->fd_ofiles); |
1c79356b A |
1338 | |
1339 | (void) memcpy(newofileflags, fdp->fd_ofileflags, | |
1340 | oldnfiles * sizeof *fdp->fd_ofileflags); | |
1341 | (void) memset(&newofileflags[oldnfiles], 0, | |
91447636 | 1342 | (numfiles - oldnfiles) * |
1c79356b A |
1343 | sizeof *fdp->fd_ofileflags); |
1344 | ofiles = fdp->fd_ofiles; | |
1345 | fdp->fd_ofiles = newofiles; | |
1346 | fdp->fd_ofileflags = newofileflags; | |
91447636 | 1347 | fdp->fd_nfiles = numfiles; |
1c79356b A |
1348 | FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL); |
1349 | fdexpand++; | |
1350 | } | |
1351 | } | |
1352 | ||
91447636 A |
1353 | /* |
1354 | * Check to see whether n user file descriptors | |
1355 | * are available to the process p. | |
1356 | */ | |
1357 | int | |
1358 | fdavail(p, n) | |
1359 | struct proc *p; | |
1360 | int n; | |
1361 | { | |
1362 | struct filedesc *fdp = p->p_fd; | |
1363 | struct fileproc **fpp; | |
1364 | char *flags; | |
1365 | int i, lim; | |
1366 | ||
1367 | lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); | |
1368 | if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) | |
1369 | return (1); | |
1370 | fpp = &fdp->fd_ofiles[fdp->fd_freefile]; | |
1371 | flags = &fdp->fd_ofileflags[fdp->fd_freefile]; | |
1372 | for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++) | |
1373 | if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0) | |
1374 | return (1); | |
1375 | return (0); | |
1376 | } | |
1377 | ||
1378 | void | |
1379 | fdrelse(p, fd) | |
1380 | struct proc *p; | |
1381 | int fd; | |
1382 | { | |
1383 | _fdrelse(p->p_fd, fd); | |
1384 | } | |
1385 | ||
1386 | void | |
1387 | fddrop(p, fd) | |
1388 | struct proc *p; | |
1389 | int fd; | |
1390 | { | |
1391 | struct filedesc *fdp = p->p_fd; | |
1392 | struct fileproc *fp; | |
1393 | ||
1394 | if (fd < fdp->fd_freefile) | |
1395 | fdp->fd_freefile = fd; | |
1396 | #if DIAGNOSTIC | |
1397 | if (fd > fdp->fd_lastfile) | |
1398 | panic("fdrelse: fd_lastfile inconsistent"); | |
1399 | #endif | |
1400 | fp = fdp->fd_ofiles[fd]; | |
1401 | fdp->fd_ofiles[fd] = NULL; | |
1402 | fdp->fd_ofileflags[fd] = 0; | |
1403 | ||
1404 | while ((fd = fdp->fd_lastfile) > 0 && | |
1405 | fdp->fd_ofiles[fd] == NULL && | |
1406 | !(fdp->fd_ofileflags[fd] & UF_RESERVED)) | |
1407 | fdp->fd_lastfile--; | |
1408 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1409 | } | |
1410 | ||
1411 | ||
1412 | int | |
1413 | fdgetf_noref(p, fd, resultfp) | |
1414 | struct proc *p; | |
1415 | int fd; | |
1416 | struct fileproc **resultfp; | |
1417 | { | |
1418 | struct filedesc *fdp = p->p_fd; | |
1419 | struct fileproc *fp; | |
1420 | ||
1421 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1422 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1423 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1424 | return (EBADF); | |
1425 | } | |
1426 | if (resultfp) | |
1427 | *resultfp = fp; | |
1428 | return (0); | |
1429 | } | |
1430 | ||
1431 | ||
1432 | /* should be called only when proc_fdlock is held */ | |
1433 | void | |
1434 | fp_setflags(proc_t p, struct fileproc * fp, int flags) | |
1435 | { | |
1436 | proc_fdlock(p); | |
1437 | fp->f_flags |= flags; | |
1438 | proc_fdunlock(p); | |
1439 | } | |
1440 | ||
1441 | void | |
1442 | fp_clearflags(proc_t p, struct fileproc * fp, int flags) | |
1443 | { | |
1444 | ||
1445 | proc_fdlock(p); | |
1446 | if (fp) | |
1447 | fp->f_flags &= ~flags; | |
1448 | proc_fdunlock(p); | |
1449 | } | |
1450 | ||
1451 | int | |
1452 | fp_getfvp(p, fd, resultfp, resultvp) | |
1453 | struct proc *p; | |
1454 | int fd; | |
1455 | struct fileproc **resultfp; | |
1456 | struct vnode **resultvp; | |
1457 | { | |
1458 | struct filedesc *fdp = p->p_fd; | |
1459 | struct fileproc *fp; | |
1460 | ||
1461 | proc_fdlock(p); | |
1462 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1463 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1464 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1465 | proc_fdunlock(p); | |
1466 | return (EBADF); | |
1467 | } | |
1468 | if (fp->f_type != DTYPE_VNODE) { | |
1469 | proc_fdunlock(p); | |
1470 | return(ENOTSUP); | |
1471 | } | |
1472 | fp->f_iocount++; | |
1473 | ||
1474 | if (resultfp) | |
1475 | *resultfp = fp; | |
1476 | if (resultvp) | |
1477 | *resultvp = (struct vnode *)fp->f_data; | |
1478 | proc_fdunlock(p); | |
1479 | ||
1480 | return (0); | |
1481 | } | |
1482 | ||
1483 | ||
1484 | /* | |
1485 | * Returns: EBADF The file descriptor is invalid | |
1486 | * EOPNOTSUPP The file descriptor is not a socket | |
1487 | * 0 Success | |
1488 | * | |
1489 | * Notes: EOPNOTSUPP should probably be ENOTSOCK; this function is only | |
1490 | * ever called from accept1(). | |
1491 | */ | |
1492 | int | |
1493 | fp_getfsock(p, fd, resultfp, results) | |
1494 | struct proc *p; | |
1495 | int fd; | |
1496 | struct fileproc **resultfp; | |
1497 | struct socket **results; | |
1498 | { | |
1499 | struct filedesc *fdp = p->p_fd; | |
1500 | struct fileproc *fp; | |
1501 | ||
1502 | proc_fdlock(p); | |
1503 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1504 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1505 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1506 | proc_fdunlock(p); | |
1507 | return (EBADF); | |
1508 | } | |
1509 | if (fp->f_type != DTYPE_SOCKET) { | |
1510 | proc_fdunlock(p); | |
1511 | return(EOPNOTSUPP); | |
1512 | } | |
1513 | fp->f_iocount++; | |
1514 | ||
1515 | if (resultfp) | |
1516 | *resultfp = fp; | |
1517 | if (results) | |
1518 | *results = (struct socket *)fp->f_data; | |
1519 | proc_fdunlock(p); | |
1520 | ||
1521 | return (0); | |
1522 | } | |
1523 | ||
1524 | ||
1525 | int | |
1526 | fp_getfkq(p, fd, resultfp, resultkq) | |
1527 | struct proc *p; | |
1528 | int fd; | |
1529 | struct fileproc **resultfp; | |
1530 | struct kqueue **resultkq; | |
1531 | { | |
1532 | struct filedesc *fdp = p->p_fd; | |
1533 | struct fileproc *fp; | |
1534 | ||
1535 | proc_fdlock(p); | |
1536 | if ( fd < 0 || fd >= fdp->fd_nfiles || | |
1537 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1538 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1539 | proc_fdunlock(p); | |
1540 | return (EBADF); | |
1541 | } | |
1542 | if (fp->f_type != DTYPE_KQUEUE) { | |
1543 | proc_fdunlock(p); | |
1544 | return(EBADF); | |
1545 | } | |
1546 | fp->f_iocount++; | |
1547 | ||
1548 | if (resultfp) | |
1549 | *resultfp = fp; | |
1550 | if (resultkq) | |
1551 | *resultkq = (struct kqueue *)fp->f_data; | |
1552 | proc_fdunlock(p); | |
1553 | ||
1554 | return (0); | |
1555 | } | |
1556 | ||
1557 | int | |
1558 | fp_getfpshm(p, fd, resultfp, resultpshm) | |
1559 | struct proc *p; | |
1560 | int fd; | |
1561 | struct fileproc **resultfp; | |
1562 | struct pshmnode **resultpshm; | |
1563 | { | |
1564 | struct filedesc *fdp = p->p_fd; | |
1565 | struct fileproc *fp; | |
1566 | ||
1567 | proc_fdlock(p); | |
1568 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1569 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1570 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1571 | proc_fdunlock(p); | |
1572 | return (EBADF); | |
1573 | } | |
1574 | if (fp->f_type != DTYPE_PSXSHM) { | |
1575 | ||
1576 | proc_fdunlock(p); | |
1577 | return(EBADF); | |
1578 | } | |
1579 | fp->f_iocount++; | |
1580 | ||
1581 | if (resultfp) | |
1582 | *resultfp = fp; | |
1583 | if (resultpshm) | |
1584 | *resultpshm = (struct pshmnode *)fp->f_data; | |
1585 | proc_fdunlock(p); | |
1586 | ||
1587 | return (0); | |
1588 | } | |
1589 | ||
1590 | ||
1591 | int | |
1592 | fp_getfpsem(p, fd, resultfp, resultpsem) | |
1593 | struct proc *p; | |
1594 | int fd; | |
1595 | struct fileproc **resultfp; | |
1596 | struct psemnode **resultpsem; | |
1597 | { | |
1598 | struct filedesc *fdp = p->p_fd; | |
1599 | struct fileproc *fp; | |
1600 | ||
1601 | proc_fdlock(p); | |
1602 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1603 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1604 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1605 | proc_fdunlock(p); | |
1606 | return (EBADF); | |
1607 | } | |
1608 | if (fp->f_type != DTYPE_PSXSEM) { | |
1609 | proc_fdunlock(p); | |
1610 | return(EBADF); | |
1611 | } | |
1612 | fp->f_iocount++; | |
1613 | ||
1614 | if (resultfp) | |
1615 | *resultfp = fp; | |
1616 | if (resultpsem) | |
1617 | *resultpsem = (struct psemnode *)fp->f_data; | |
1618 | proc_fdunlock(p); | |
1619 | ||
1620 | return (0); | |
1621 | } | |
1622 | int | |
1623 | fp_lookup(p, fd, resultfp, locked) | |
1624 | struct proc *p; | |
1625 | int fd; | |
1626 | struct fileproc **resultfp; | |
1627 | int locked; | |
1628 | { | |
1629 | struct filedesc *fdp = p->p_fd; | |
1630 | struct fileproc *fp; | |
1631 | ||
1632 | if (!locked) | |
1633 | proc_fdlock(p); | |
1634 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1635 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1636 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1637 | if (!locked) | |
1638 | proc_fdunlock(p); | |
1639 | return (EBADF); | |
1640 | } | |
1641 | fp->f_iocount++; | |
1642 | ||
1643 | if (resultfp) | |
1644 | *resultfp = fp; | |
1645 | if (!locked) | |
1646 | proc_fdunlock(p); | |
1647 | ||
1648 | return (0); | |
1649 | } | |
1650 | ||
1651 | int | |
1652 | fp_drop_written(proc_t p, int fd, struct fileproc *fp) | |
1653 | { | |
1654 | int error; | |
1655 | ||
1656 | proc_fdlock(p); | |
1657 | ||
1658 | fp->f_flags |= FP_WRITTEN; | |
1659 | ||
1660 | error = fp_drop(p, fd, fp, 1); | |
1661 | ||
1662 | proc_fdunlock(p); | |
1663 | ||
1664 | return (error); | |
1665 | } | |
1666 | ||
1667 | ||
1668 | int | |
1669 | fp_drop_event(proc_t p, int fd, struct fileproc *fp) | |
1670 | { | |
1671 | int error; | |
1672 | ||
1673 | proc_fdlock(p); | |
1674 | ||
1675 | fp->f_flags |= FP_WAITEVENT; | |
1676 | ||
1677 | error = fp_drop(p, fd, fp, 1); | |
1678 | ||
1679 | proc_fdunlock(p); | |
1680 | ||
1681 | return (error); | |
1682 | } | |
1683 | ||
1c79356b | 1684 | int |
91447636 | 1685 | fp_drop(p, fd, fp, locked) |
1c79356b | 1686 | struct proc *p; |
91447636 A |
1687 | int fd; |
1688 | struct fileproc *fp; | |
1689 | int locked; | |
1c79356b | 1690 | { |
91447636 | 1691 | struct filedesc *fdp = p->p_fd; |
1c79356b | 1692 | |
91447636 A |
1693 | if (!locked) |
1694 | proc_fdlock(p); | |
1695 | if ((fp == FILEPROC_NULL) && (fd < 0 || fd >= fdp->fd_nfiles || | |
1696 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1697 | ((fdp->fd_ofileflags[fd] & UF_RESERVED) && | |
1698 | !(fdp->fd_ofileflags[fd] & UF_CLOSING)))) { | |
1699 | if (!locked) | |
1700 | proc_fdunlock(p); | |
1701 | return (EBADF); | |
1702 | } | |
1703 | fp->f_iocount--; | |
1704 | ||
1705 | if (p->p_fpdrainwait && fp->f_iocount == 0) { | |
1706 | p->p_fpdrainwait = 0; | |
1707 | wakeup(&p->p_fpdrainwait); | |
1708 | } | |
1709 | if (!locked) | |
1710 | proc_fdunlock(p); | |
1711 | ||
1c79356b A |
1712 | return (0); |
1713 | } | |
1714 | ||
91447636 A |
1715 | int |
1716 | file_vnode(int fd, struct vnode **vpp) | |
1c79356b | 1717 | { |
91447636 A |
1718 | struct proc * p = current_proc(); |
1719 | struct fileproc *fp; | |
1720 | int error; | |
1721 | ||
1722 | proc_fdlock(p); | |
1723 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
1724 | proc_fdunlock(p); | |
1725 | return(error); | |
1726 | } | |
1727 | if (fp->f_type != DTYPE_VNODE) { | |
1728 | fp_drop(p, fd, fp,1); | |
1729 | proc_fdunlock(p); | |
1730 | return(EINVAL); | |
1731 | } | |
1732 | *vpp = (struct vnode *)fp->f_data; | |
1733 | proc_fdunlock(p); | |
1734 | ||
1735 | return(0); | |
1c79356b A |
1736 | } |
1737 | ||
91447636 | 1738 | |
1c79356b | 1739 | int |
91447636 | 1740 | file_socket(int fd, struct socket **sp) |
1c79356b | 1741 | { |
91447636 A |
1742 | struct proc * p = current_proc(); |
1743 | struct fileproc *fp; | |
1744 | int error; | |
1745 | ||
1746 | proc_fdlock(p); | |
1747 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
1748 | proc_fdunlock(p); | |
1749 | return(error); | |
1750 | } | |
1751 | if (fp->f_type != DTYPE_SOCKET) { | |
1752 | fp_drop(p, fd, fp,1); | |
1753 | proc_fdunlock(p); | |
1754 | return(ENOTSOCK); | |
1755 | } | |
1756 | *sp = (struct socket *)fp->f_data; | |
1757 | proc_fdunlock(p); | |
1c79356b | 1758 | |
91447636 A |
1759 | return(0); |
1760 | } | |
1761 | ||
1762 | int | |
1763 | file_flags(int fd, int * flags) | |
1764 | { | |
1765 | ||
1766 | struct proc * p = current_proc(); | |
1767 | struct fileproc *fp; | |
1768 | int error; | |
1769 | ||
1770 | proc_fdlock(p); | |
1771 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
1772 | proc_fdunlock(p); | |
1773 | return(error); | |
1774 | } | |
1775 | *flags = (int)fp->f_flag; | |
1776 | fp_drop(p, fd, fp,1); | |
1777 | proc_fdunlock(p); | |
1778 | ||
1779 | return(0); | |
1780 | } | |
1781 | ||
1782 | ||
1783 | int | |
1784 | file_drop(int fd) | |
1785 | { | |
1786 | struct fileproc *fp; | |
1787 | struct proc *p = current_proc(); | |
1788 | ||
1789 | proc_fdlock(p); | |
1790 | if (fd < 0 || fd >= p->p_fd->fd_nfiles || | |
1791 | (fp = p->p_fd->fd_ofiles[fd]) == NULL || | |
1792 | ((p->p_fd->fd_ofileflags[fd] & UF_RESERVED) && | |
1793 | !(p->p_fd->fd_ofileflags[fd] & UF_CLOSING))) { | |
1794 | proc_fdunlock(p); | |
1c79356b | 1795 | return (EBADF); |
91447636 A |
1796 | } |
1797 | fp->f_iocount --; | |
1798 | ||
1799 | if (p->p_fpdrainwait && fp->f_iocount == 0) { | |
1800 | p->p_fpdrainwait = 0; | |
1801 | wakeup(&p->p_fpdrainwait); | |
1802 | } | |
1803 | proc_fdunlock(p); | |
1804 | return(0); | |
1805 | ||
1c79356b | 1806 | |
1c79356b A |
1807 | } |
1808 | ||
91447636 A |
1809 | int |
1810 | falloc(p, resultfp, resultfd ) | |
1811 | struct proc *p; | |
1812 | struct fileproc **resultfp; | |
1813 | int *resultfd; | |
1814 | { | |
1815 | int error; | |
1816 | ||
1817 | proc_fdlock(p); | |
1818 | error = falloc_locked(p, resultfp, resultfd, 1); | |
1819 | proc_fdunlock(p); | |
1820 | ||
1821 | return(error); | |
1822 | } | |
1c79356b A |
1823 | /* |
1824 | * Create a new open file structure and allocate | |
1825 | * a file decriptor for the process that refers to it. | |
1826 | */ | |
1827 | int | |
91447636 A |
1828 | falloc_locked(p, resultfp, resultfd, locked) |
1829 | struct proc *p; | |
1830 | struct fileproc **resultfp; | |
1c79356b | 1831 | int *resultfd; |
91447636 | 1832 | int locked; |
1c79356b | 1833 | { |
91447636 A |
1834 | struct fileproc *fp, *fq; |
1835 | struct fileglob *fg; | |
1836 | int error, nfd; | |
1837 | ||
1838 | if (!locked) | |
1839 | proc_fdlock(p); | |
1840 | if ( (error = fdalloc(p, 0, &nfd)) ) { | |
1841 | if (!locked) | |
1842 | proc_fdunlock(p); | |
1c79356b | 1843 | return (error); |
91447636 | 1844 | } |
1c79356b | 1845 | if (nfiles >= maxfiles) { |
91447636 A |
1846 | if (!locked) |
1847 | proc_fdunlock(p); | |
1c79356b A |
1848 | tablefull("file"); |
1849 | return (ENFILE); | |
1850 | } | |
1851 | /* | |
1852 | * Allocate a new file descriptor. | |
1853 | * If the process has file descriptor zero open, add to the list | |
1854 | * of open files at that point, otherwise put it at the front of | |
1855 | * the list of open files. | |
1856 | */ | |
91447636 A |
1857 | proc_fdunlock(p); |
1858 | ||
1859 | MALLOC_ZONE(fp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK); | |
1860 | MALLOC_ZONE(fg, struct fileglob *, sizeof(struct fileglob), M_FILEGLOB, M_WAITOK); | |
1861 | bzero(fp, sizeof(struct fileproc)); | |
1862 | bzero(fg, sizeof(struct fileglob)); | |
1863 | lck_mtx_init(&fg->fg_lock, file_lck_grp, file_lck_attr); | |
1864 | ||
1865 | fp->f_iocount = 1; | |
1866 | fg->fg_count = 1; | |
1867 | fp->f_fglob = fg; | |
1868 | ||
1869 | proc_fdlock(p); | |
1870 | ||
1871 | fp->f_cred = kauth_cred_proc_ref(p); | |
1872 | ||
1873 | lck_mtx_lock(file_flist_lock); | |
1874 | ||
1c79356b | 1875 | nfiles++; |
91447636 A |
1876 | |
1877 | if ( (fq = p->p_fd->fd_ofiles[0]) ) { | |
1878 | LIST_INSERT_AFTER(fq->f_fglob, fg, f_list); | |
1879 | } else { | |
1880 | LIST_INSERT_HEAD(&filehead, fg, f_list); | |
1881 | } | |
1882 | lck_mtx_unlock(file_flist_lock); | |
1883 | ||
1884 | p->p_fd->fd_ofiles[nfd] = fp; | |
1885 | ||
1886 | if (!locked) | |
1887 | proc_fdunlock(p); | |
1888 | ||
1c79356b A |
1889 | if (resultfp) |
1890 | *resultfp = fp; | |
1891 | if (resultfd) | |
91447636 A |
1892 | *resultfd = nfd; |
1893 | ||
1c79356b A |
1894 | return (0); |
1895 | } | |
1896 | ||
1897 | /* | |
1898 | * Free a file structure. | |
1899 | */ | |
1900 | void | |
91447636 A |
1901 | fg_free(fg) |
1902 | struct fileglob *fg; | |
1c79356b | 1903 | { |
91447636 A |
1904 | kauth_cred_t cred; |
1905 | ||
1906 | lck_mtx_lock(file_flist_lock); | |
1907 | LIST_REMOVE(fg, f_list); | |
1908 | nfiles--; | |
1909 | lck_mtx_unlock(file_flist_lock); | |
1c79356b | 1910 | |
91447636 | 1911 | cred = fg->fg_cred; |
1c79356b | 1912 | if (cred != NOCRED) { |
91447636 A |
1913 | fg->fg_cred = NOCRED; |
1914 | kauth_cred_rele(cred); | |
1c79356b | 1915 | } |
91447636 | 1916 | lck_mtx_destroy(&fg->fg_lock, file_lck_grp); |
fa4905b1 | 1917 | |
91447636 | 1918 | FREE_ZONE(fg, sizeof *fg, M_FILEGLOB); |
1c79356b A |
1919 | } |
1920 | ||
1921 | void | |
1922 | fdexec(p) | |
1923 | struct proc *p; | |
1924 | { | |
91447636 A |
1925 | struct filedesc *fdp = p->p_fd; |
1926 | int i = fdp->fd_lastfile; | |
1927 | struct fileproc **fpp = &fdp->fd_ofiles[i]; | |
1928 | char *flags = &fdp->fd_ofileflags[i]; | |
1929 | int funnel_state; | |
1930 | ||
1931 | funnel_state = thread_funnel_set(kernel_flock, FALSE); | |
1932 | proc_fdlock(p); | |
1c79356b A |
1933 | |
1934 | while (i >= 0) { | |
1935 | if ((*flags & (UF_RESERVED|UF_EXCLOSE)) == UF_EXCLOSE) { | |
91447636 | 1936 | struct fileproc *fp = *fpp; |
1c79356b | 1937 | |
55e303ae A |
1938 | if (i < fdp->fd_knlistsize) |
1939 | knote_fdclose(p, i); | |
1940 | ||
1c79356b A |
1941 | *fpp = NULL; *flags = 0; |
1942 | if (i == fdp->fd_lastfile && i > 0) | |
1943 | fdp->fd_lastfile--; | |
91447636 A |
1944 | closef_locked(fp, fp->f_fglob, p); |
1945 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1c79356b | 1946 | } |
1c79356b A |
1947 | |
1948 | i--; fpp--; flags--; | |
1949 | } | |
91447636 A |
1950 | proc_fdunlock(p); |
1951 | thread_funnel_set(kernel_flock, funnel_state); | |
1c79356b A |
1952 | } |
1953 | ||
1954 | /* | |
1955 | * Copy a filedesc structure. | |
1956 | */ | |
1957 | struct filedesc * | |
1958 | fdcopy(p) | |
1959 | struct proc *p; | |
1960 | { | |
91447636 A |
1961 | struct filedesc *newfdp, *fdp = p->p_fd; |
1962 | int i; | |
1963 | struct fileproc *ofp, *fp; | |
1964 | vnode_t v_dir; | |
1c79356b A |
1965 | |
1966 | MALLOC_ZONE(newfdp, struct filedesc *, | |
1967 | sizeof *newfdp, M_FILEDESC, M_WAITOK); | |
91447636 A |
1968 | if (newfdp == NULL) |
1969 | return(NULL); | |
1970 | ||
1971 | proc_fdlock(p); | |
1972 | ||
1973 | /* | |
1974 | * the FD_CHROOT flag will be inherited via this copy | |
1975 | */ | |
1c79356b | 1976 | (void) memcpy(newfdp, fdp, sizeof *newfdp); |
91447636 A |
1977 | |
1978 | /* | |
1979 | * for both fd_cdir and fd_rdir make sure we get | |
1980 | * a valid reference... if we can't, than set | |
1981 | * set the pointer(s) to NULL in the child... this | |
1982 | * will keep us from using a non-referenced vp | |
1983 | * and allows us to do the vnode_rele only on | |
1984 | * a properly referenced vp | |
1985 | */ | |
1986 | if ( (v_dir = newfdp->fd_cdir) ) { | |
1987 | if (vnode_getwithref(v_dir) == 0) { | |
1988 | if ( (vnode_ref(v_dir)) ) | |
1989 | newfdp->fd_cdir = NULL; | |
1990 | vnode_put(v_dir); | |
1991 | } else | |
1992 | newfdp->fd_cdir = NULL; | |
1993 | } | |
1994 | if (newfdp->fd_cdir == NULL && fdp->fd_cdir) { | |
1995 | /* | |
1996 | * we couldn't get a new reference on | |
1997 | * the current working directory being | |
1998 | * inherited... we might as well drop | |
1999 | * our reference from the parent also | |
2000 | * since the vnode has gone DEAD making | |
2001 | * it useless... by dropping it we'll | |
2002 | * be that much closer to recyling it | |
2003 | */ | |
2004 | vnode_rele(fdp->fd_cdir); | |
2005 | fdp->fd_cdir = NULL; | |
2006 | } | |
2007 | ||
2008 | if ( (v_dir = newfdp->fd_rdir) ) { | |
2009 | if (vnode_getwithref(v_dir) == 0) { | |
2010 | if ( (vnode_ref(v_dir)) ) | |
2011 | newfdp->fd_rdir = NULL; | |
2012 | vnode_put(v_dir); | |
2013 | } else | |
2014 | newfdp->fd_rdir = NULL; | |
2015 | } | |
2016 | if (newfdp->fd_rdir == NULL && fdp->fd_rdir) { | |
2017 | /* | |
2018 | * we couldn't get a new reference on | |
2019 | * the root directory being | |
2020 | * inherited... we might as well drop | |
2021 | * our reference from the parent also | |
2022 | * since the vnode has gone DEAD making | |
2023 | * it useless... by dropping it we'll | |
2024 | * be that much closer to recyling it | |
2025 | */ | |
2026 | vnode_rele(fdp->fd_rdir); | |
2027 | fdp->fd_rdir = NULL; | |
2028 | } | |
1c79356b A |
2029 | newfdp->fd_refcnt = 1; |
2030 | ||
2031 | /* | |
2032 | * If the number of open files fits in the internal arrays | |
2033 | * of the open file structure, use them, otherwise allocate | |
2034 | * additional memory for the number of descriptors currently | |
2035 | * in use. | |
2036 | */ | |
2037 | if (newfdp->fd_lastfile < NDFILE) | |
2038 | i = NDFILE; | |
2039 | else { | |
2040 | /* | |
2041 | * Compute the smallest multiple of NDEXTENT needed | |
2042 | * for the file descriptors currently in use, | |
2043 | * allowing the table to shrink. | |
2044 | */ | |
2045 | i = newfdp->fd_nfiles; | |
2046 | while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2) | |
2047 | i /= 2; | |
2048 | } | |
91447636 A |
2049 | proc_fdunlock(p); |
2050 | ||
2051 | MALLOC_ZONE(newfdp->fd_ofiles, struct fileproc **, | |
1c79356b | 2052 | i * OFILESIZE, M_OFILETABL, M_WAITOK); |
91447636 A |
2053 | if (newfdp->fd_ofiles == NULL) { |
2054 | if (newfdp->fd_cdir) | |
2055 | vnode_rele(newfdp->fd_cdir); | |
2056 | if (newfdp->fd_rdir) | |
2057 | vnode_rele(newfdp->fd_rdir); | |
2058 | ||
2059 | FREE_ZONE(newfdp, sizeof *newfdp, M_FILEDESC); | |
2060 | return(NULL); | |
2061 | } | |
2062 | proc_fdlock(p); | |
2063 | ||
1c79356b A |
2064 | newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; |
2065 | newfdp->fd_nfiles = i; | |
91447636 | 2066 | |
1c79356b | 2067 | if (fdp->fd_nfiles > 0) { |
91447636 A |
2068 | struct fileproc **fpp; |
2069 | char *flags; | |
1c79356b A |
2070 | |
2071 | (void) memcpy(newfdp->fd_ofiles, fdp->fd_ofiles, | |
2072 | i * sizeof *fdp->fd_ofiles); | |
2073 | (void) memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags, | |
2074 | i * sizeof *fdp->fd_ofileflags); | |
2075 | ||
55e303ae A |
2076 | /* |
2077 | * kq descriptors cannot be copied. | |
2078 | */ | |
2079 | if (newfdp->fd_knlistsize != -1) { | |
2080 | fpp = &newfdp->fd_ofiles[newfdp->fd_lastfile]; | |
2081 | for (i = newfdp->fd_lastfile; i >= 0; i--, fpp--) { | |
2082 | if (*fpp != NULL && (*fpp)->f_type == DTYPE_KQUEUE) { | |
2083 | *fpp = NULL; | |
2084 | if (i < newfdp->fd_freefile) | |
2085 | newfdp->fd_freefile = i; | |
2086 | } | |
2087 | if (*fpp == NULL && i == newfdp->fd_lastfile && i > 0) | |
2088 | newfdp->fd_lastfile--; | |
2089 | } | |
2090 | newfdp->fd_knlist = NULL; | |
2091 | newfdp->fd_knlistsize = -1; | |
2092 | newfdp->fd_knhash = NULL; | |
2093 | newfdp->fd_knhashmask = 0; | |
2094 | } | |
1c79356b A |
2095 | fpp = newfdp->fd_ofiles; |
2096 | flags = newfdp->fd_ofileflags; | |
91447636 | 2097 | |
1c79356b | 2098 | for (i = newfdp->fd_lastfile; i-- >= 0; fpp++, flags++) |
91447636 A |
2099 | if ((ofp = *fpp) != NULL && !(*flags & UF_RESERVED)) { |
2100 | MALLOC_ZONE(fp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK); | |
2101 | bzero(fp, sizeof(struct fileproc)); | |
2102 | fp->f_flags = ofp->f_flags; | |
2103 | //fp->f_iocount = ofp->f_iocount; | |
2104 | fp->f_iocount = 0; | |
2105 | fp->f_fglob = ofp->f_fglob; | |
2106 | (void)fg_ref(fp); | |
2107 | *fpp = fp; | |
1c79356b A |
2108 | } else { |
2109 | *fpp = NULL; | |
2110 | *flags = 0; | |
2111 | } | |
fa4905b1 | 2112 | } else |
1c79356b A |
2113 | (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE); |
2114 | ||
91447636 | 2115 | proc_fdunlock(p); |
1c79356b A |
2116 | return (newfdp); |
2117 | } | |
2118 | ||
2119 | /* | |
2120 | * Release a filedesc structure. | |
2121 | */ | |
2122 | void | |
2123 | fdfree(p) | |
2124 | struct proc *p; | |
2125 | { | |
fa4905b1 | 2126 | struct filedesc *fdp; |
91447636 | 2127 | struct fileproc *fp; |
fa4905b1 | 2128 | int i; |
91447636 A |
2129 | |
2130 | proc_fdlock(p); | |
1c79356b | 2131 | |
55e303ae | 2132 | /* Certain daemons might not have file descriptors */ |
91447636 | 2133 | fdp = p->p_fd; |
55e303ae | 2134 | |
91447636 A |
2135 | if ((fdp == NULL) || (--fdp->fd_refcnt > 0)) { |
2136 | proc_fdunlock(p); | |
1c79356b | 2137 | return; |
91447636 A |
2138 | } |
2139 | if (fdp->fd_refcnt == 0xffff) | |
2140 | panic("fdfree: bad fd_refcnt"); | |
55e303ae A |
2141 | |
2142 | /* Last reference: the structure can't change out from under us */ | |
91447636 A |
2143 | |
2144 | if (fdp->fd_nfiles > 0 && fdp->fd_ofiles) { | |
2145 | for (i = fdp->fd_lastfile; i >= 0; i--) { | |
55e303ae | 2146 | if ((fp = fdp->fd_ofiles[i]) != NULL) { |
91447636 A |
2147 | |
2148 | if (fdp->fd_ofileflags[i] & UF_RESERVED) | |
2149 | panic("fdfree: found fp with UF_RESERVED\n"); | |
2150 | ||
2151 | /* closef drops the iocount ... */ | |
2152 | if ((fp->f_flags & FP_INCHRREAD) != 0) | |
2153 | fp->f_iocount++; | |
2154 | fdp->fd_ofiles[i] = NULL; | |
2155 | fdp->fd_ofileflags[i] |= UF_RESERVED; | |
2156 | ||
55e303ae A |
2157 | if (i < fdp->fd_knlistsize) |
2158 | knote_fdclose(p, i); | |
91447636 A |
2159 | if (fp->f_flags & FP_WAITEVENT) |
2160 | (void)waitevent_close(p, fp); | |
2161 | (void) closef_locked(fp, fp->f_fglob, p); | |
2162 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
55e303ae | 2163 | } |
91447636 A |
2164 | } |
2165 | FREE_ZONE(fdp->fd_ofiles, fdp->fd_nfiles * OFILESIZE, M_OFILETABL); | |
2166 | fdp->fd_ofiles = NULL; | |
2167 | fdp->fd_nfiles = 0; | |
2168 | } | |
55e303ae | 2169 | |
91447636 A |
2170 | proc_fdunlock(p); |
2171 | ||
2172 | if (fdp->fd_cdir) | |
2173 | vnode_rele(fdp->fd_cdir); | |
2174 | if (fdp->fd_rdir) | |
2175 | vnode_rele(fdp->fd_rdir); | |
55e303ae | 2176 | |
91447636 A |
2177 | proc_fdlock(p); |
2178 | p->p_fd = NULL; | |
2179 | proc_fdunlock(p); | |
55e303ae A |
2180 | |
2181 | if (fdp->fd_knlist) | |
2182 | FREE(fdp->fd_knlist, M_KQUEUE); | |
2183 | if (fdp->fd_knhash) | |
2184 | FREE(fdp->fd_knhash, M_KQUEUE); | |
2185 | ||
1c79356b A |
2186 | FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC); |
2187 | } | |
2188 | ||
9bccf70c | 2189 | static int |
91447636 A |
2190 | closef_finish(fp, fg, p) |
2191 | struct fileproc *fp; | |
2192 | struct fileglob *fg; | |
2193 | struct proc *p; | |
9bccf70c A |
2194 | { |
2195 | struct vnode *vp; | |
2196 | struct flock lf; | |
2197 | int error; | |
91447636 | 2198 | struct vfs_context context; |
9bccf70c | 2199 | |
91447636 | 2200 | if ((fg->fg_flag & FHASLOCK) && fg->fg_type == DTYPE_VNODE) { |
9bccf70c A |
2201 | lf.l_whence = SEEK_SET; |
2202 | lf.l_start = 0; | |
2203 | lf.l_len = 0; | |
2204 | lf.l_type = F_UNLCK; | |
91447636 A |
2205 | vp = (struct vnode *)fg->fg_data; |
2206 | context.vc_proc = p; | |
2207 | context.vc_ucred = fg->fg_cred; | |
2208 | ||
2209 | (void) VNOP_ADVLOCK(vp, (caddr_t)fg, F_UNLCK, &lf, F_FLOCK, &context); | |
9bccf70c | 2210 | } |
91447636 A |
2211 | if (fg->fg_ops) |
2212 | error = fo_close(fg, p); | |
9bccf70c A |
2213 | else |
2214 | error = 0; | |
91447636 A |
2215 | |
2216 | if (((fp != (struct fileproc *)0) && ((fp->f_flags & FP_INCHRREAD) != 0))) { | |
2217 | proc_fdlock(p); | |
2218 | if ( ((fp->f_flags & FP_INCHRREAD) != 0) ) { | |
2219 | fileproc_drain(p, fp); | |
2220 | } | |
2221 | proc_fdunlock(p); | |
2222 | } | |
2223 | fg_free(fg); | |
2224 | ||
9bccf70c A |
2225 | return (error); |
2226 | } | |
2227 | ||
91447636 A |
2228 | int |
2229 | closef(fg, p) | |
2230 | struct fileglob *fg; | |
2231 | struct proc *p; | |
2232 | { | |
2233 | int error; | |
2234 | ||
2235 | proc_fdlock(p); | |
2236 | error = closef_locked((struct fileproc *)0, fg, p); | |
2237 | proc_fdunlock(p); | |
2238 | ||
2239 | return(error); | |
2240 | } | |
1c79356b A |
2241 | /* |
2242 | * Internal form of close. | |
2243 | * Decrement reference count on file structure. | |
2244 | * Note: p may be NULL when closing a file | |
2245 | * that was being passed in a message. | |
2246 | */ | |
2247 | int | |
91447636 A |
2248 | closef_locked(fp, fg, p) |
2249 | struct fileproc *fp; | |
2250 | struct fileglob *fg; | |
2251 | struct proc *p; | |
1c79356b A |
2252 | { |
2253 | struct vnode *vp; | |
2254 | struct flock lf; | |
91447636 | 2255 | struct vfs_context context; |
1c79356b A |
2256 | int error; |
2257 | ||
91447636 | 2258 | if (fg == NULL) { |
1c79356b | 2259 | return (0); |
91447636 | 2260 | } |
1c79356b A |
2261 | /* |
2262 | * POSIX record locking dictates that any close releases ALL | |
2263 | * locks owned by this process. This is handled by setting | |
2264 | * a flag in the unlock to free ONLY locks obeying POSIX | |
2265 | * semantics, and not to free BSD-style file locks. | |
2266 | * If the descriptor was in a message, POSIX-style locks | |
2267 | * aren't passed with the descriptor. | |
2268 | */ | |
b36670ce | 2269 | if (p && (p->p_ladvflag & P_LADVLOCK) && fg->fg_type == DTYPE_VNODE) { |
91447636 A |
2270 | proc_fdunlock(p); |
2271 | ||
1c79356b A |
2272 | lf.l_whence = SEEK_SET; |
2273 | lf.l_start = 0; | |
2274 | lf.l_len = 0; | |
2275 | lf.l_type = F_UNLCK; | |
91447636 A |
2276 | vp = (struct vnode *)fg->fg_data; |
2277 | ||
2278 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
2279 | context.vc_proc = p; | |
2280 | context.vc_ucred = fg->fg_cred; | |
2281 | (void) VNOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX, &context); | |
2282 | ||
2283 | (void)vnode_put(vp); | |
2284 | } | |
2285 | proc_fdlock(p); | |
1c79356b | 2286 | } |
91447636 A |
2287 | lck_mtx_lock(&fg->fg_lock); |
2288 | fg->fg_count--; | |
2289 | ||
2290 | if (fg->fg_count > 0) { | |
2291 | lck_mtx_unlock(&fg->fg_lock); | |
1c79356b | 2292 | return (0); |
91447636 A |
2293 | } |
2294 | if (fg->fg_count != 0) | |
2295 | panic("fg: being freed with bad fg_count (%d)", fg, fg->fg_count); | |
2296 | ||
2297 | if (fp && (fp->f_flags & FP_WRITTEN)) | |
2298 | fg->fg_flag |= FWASWRITTEN; | |
2299 | ||
2300 | fg->fg_lflags |= FG_TERM; | |
2301 | lck_mtx_unlock(&fg->fg_lock); | |
2302 | ||
2303 | proc_fdunlock(p); | |
2304 | error = closef_finish(fp, fg, p); | |
2305 | proc_fdlock(p); | |
2306 | ||
2307 | return(error); | |
2308 | } | |
2309 | ||
2310 | ||
2311 | extern int selwait; | |
2312 | void | |
2313 | fileproc_drain(struct proc *p, struct fileproc * fp) | |
2314 | { | |
2315 | fp->f_iocount-- ; /* (the one the close holds) */ | |
2316 | ||
2317 | while (fp->f_iocount) { | |
2318 | if (((fp->f_flags & FP_INSELECT)== FP_INSELECT)) { | |
2319 | wait_queue_wakeup_all((wait_queue_t)fp->f_waddr, &selwait, THREAD_INTERRUPTED); | |
2320 | } else { | |
2321 | if (fp->f_fglob->fg_ops->fo_drain) { | |
2322 | (*fp->f_fglob->fg_ops->fo_drain)(fp, p); | |
2323 | } | |
2324 | } | |
2325 | p->p_fpdrainwait = 1; | |
2326 | ||
2327 | msleep(&p->p_fpdrainwait, &p->p_fdmlock, PRIBIO, "fpdrain",0); | |
2328 | ||
2329 | //panic("successful wait after drain\n"); | |
2330 | } | |
2331 | } | |
2332 | ||
2333 | int | |
2334 | fp_free(struct proc * p, int fd, struct fileproc * fp) | |
2335 | { | |
2336 | proc_fdlock(p); | |
2337 | fdrelse(p, fd); | |
2338 | proc_fdunlock(p); | |
2339 | ||
2340 | fg_free(fp->f_fglob); | |
2341 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1c79356b A |
2342 | } |
2343 | ||
91447636 | 2344 | |
1c79356b A |
2345 | /* |
2346 | * Apply an advisory lock on a file descriptor. | |
2347 | * | |
2348 | * Just attempt to get a record lock of the requested type on | |
2349 | * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). | |
2350 | */ | |
1c79356b | 2351 | int |
91447636 | 2352 | flock(struct proc *p, register struct flock_args *uap, __unused register_t *retval) |
1c79356b A |
2353 | { |
2354 | int fd = uap->fd; | |
2355 | int how = uap->how; | |
91447636 | 2356 | struct fileproc *fp; |
1c79356b A |
2357 | struct vnode *vp; |
2358 | struct flock lf; | |
91447636 A |
2359 | struct vfs_context context; |
2360 | int error=0; | |
1c79356b | 2361 | |
55e303ae | 2362 | AUDIT_ARG(fd, uap->fd); |
91447636 A |
2363 | if ( (error = fp_getfvp(p, fd, &fp, &vp)) ) { |
2364 | return(error); | |
2365 | } | |
2366 | if ( (error = vnode_getwithref(vp)) ) { | |
2367 | goto out1; | |
2368 | } | |
55e303ae | 2369 | AUDIT_ARG(vnpath, vp, ARG_VNODE1); |
91447636 A |
2370 | |
2371 | context.vc_proc = p; | |
2372 | context.vc_ucred = fp->f_cred; | |
2373 | ||
1c79356b A |
2374 | lf.l_whence = SEEK_SET; |
2375 | lf.l_start = 0; | |
2376 | lf.l_len = 0; | |
2377 | if (how & LOCK_UN) { | |
2378 | lf.l_type = F_UNLCK; | |
2379 | fp->f_flag &= ~FHASLOCK; | |
91447636 A |
2380 | error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_UNLCK, &lf, F_FLOCK, &context); |
2381 | goto out; | |
1c79356b A |
2382 | } |
2383 | if (how & LOCK_EX) | |
2384 | lf.l_type = F_WRLCK; | |
2385 | else if (how & LOCK_SH) | |
2386 | lf.l_type = F_RDLCK; | |
91447636 A |
2387 | else { |
2388 | error = EBADF; | |
2389 | goto out; | |
2390 | } | |
1c79356b | 2391 | fp->f_flag |= FHASLOCK; |
91447636 A |
2392 | if (how & LOCK_NB) { |
2393 | error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, F_FLOCK, &context); | |
2394 | goto out; | |
2395 | } | |
2396 | error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, F_FLOCK|F_WAIT, &context); | |
2397 | out: | |
2398 | (void)vnode_put(vp); | |
2399 | out1: | |
2400 | fp_drop(p, fd, fp, 0); | |
2401 | return(error); | |
2402 | ||
1c79356b A |
2403 | } |
2404 | ||
2405 | /* | |
2406 | * File Descriptor pseudo-device driver (/dev/fd/). | |
2407 | * | |
2408 | * Opening minor device N dup()s the file (if any) connected to file | |
2409 | * descriptor N belonging to the calling process. Note that this driver | |
2410 | * consists of only the ``open()'' routine, because all subsequent | |
2411 | * references to this file will be direct to the other driver. | |
2412 | */ | |
1c79356b | 2413 | int |
91447636 | 2414 | fdopen(dev_t dev, __unused int mode, __unused int type, struct proc *p) |
1c79356b A |
2415 | { |
2416 | ||
2417 | /* | |
2418 | * XXX Kludge: set curproc->p_dupfd to contain the value of the | |
2419 | * the file descriptor being sought for duplication. The error | |
2420 | * return ensures that the vnode for this device will be released | |
2421 | * by vn_open. Open will detect this special error and take the | |
91447636 | 2422 | * actions in dupfdopen below. Other callers of vn_open or vnop_open |
1c79356b A |
2423 | * will simply report the error. |
2424 | */ | |
2425 | p->p_dupfd = minor(dev); | |
2426 | return (ENODEV); | |
2427 | } | |
2428 | ||
2429 | /* | |
2430 | * Duplicate the specified descriptor to a free descriptor. | |
2431 | */ | |
2432 | int | |
2433 | dupfdopen(fdp, indx, dfd, mode, error) | |
2434 | register struct filedesc *fdp; | |
2435 | register int indx, dfd; | |
2436 | int mode; | |
2437 | int error; | |
2438 | { | |
91447636 A |
2439 | struct fileproc *wfp; |
2440 | struct fileproc *fp; | |
2441 | struct proc * p = current_proc(); | |
1c79356b A |
2442 | |
2443 | /* | |
2444 | * If the to-be-dup'd fd number is greater than the allowed number | |
2445 | * of file descriptors, or the fd to be dup'd has already been | |
2446 | * closed, reject. Note, check for new == old is necessary as | |
2447 | * falloc could allocate an already closed to-be-dup'd descriptor | |
2448 | * as the new descriptor. | |
2449 | */ | |
91447636 A |
2450 | proc_fdlock(p); |
2451 | ||
1c79356b | 2452 | fp = fdp->fd_ofiles[indx]; |
91447636 | 2453 | if (dfd < 0 || dfd >= fdp->fd_nfiles || |
1c79356b | 2454 | (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp || |
91447636 | 2455 | (fdp->fd_ofileflags[dfd] & UF_RESERVED)) { |
1c79356b | 2456 | |
91447636 A |
2457 | proc_fdunlock(p); |
2458 | return (EBADF); | |
2459 | } | |
1c79356b A |
2460 | /* |
2461 | * There are two cases of interest here. | |
2462 | * | |
2463 | * For ENODEV simply dup (dfd) to file descriptor | |
2464 | * (indx) and return. | |
2465 | * | |
2466 | * For ENXIO steal away the file structure from (dfd) and | |
2467 | * store it in (indx). (dfd) is effectively closed by | |
2468 | * this operation. | |
2469 | * | |
2470 | * Any other error code is just returned. | |
2471 | */ | |
2472 | switch (error) { | |
2473 | case ENODEV: | |
2474 | /* | |
2475 | * Check that the mode the file is being opened for is a | |
2476 | * subset of the mode of the existing descriptor. | |
2477 | */ | |
91447636 A |
2478 | if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) { |
2479 | proc_fdunlock(p); | |
1c79356b | 2480 | return (EACCES); |
91447636 | 2481 | } |
1c79356b | 2482 | if (indx > fdp->fd_lastfile) |
91447636 A |
2483 | fdp->fd_lastfile = indx; |
2484 | (void)fg_ref(wfp); | |
2485 | ||
2486 | if (fp->f_fglob) | |
2487 | fg_free(fp->f_fglob); | |
2488 | fp->f_fglob = wfp->f_fglob; | |
2489 | ||
1c79356b | 2490 | fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; |
91447636 A |
2491 | |
2492 | proc_fdunlock(p); | |
1c79356b A |
2493 | return (0); |
2494 | ||
2495 | case ENXIO: | |
2496 | /* | |
2497 | * Steal away the file pointer from dfd, and stuff it into indx. | |
2498 | */ | |
2499 | if (indx > fdp->fd_lastfile) | |
91447636 A |
2500 | fdp->fd_lastfile = indx; |
2501 | ||
2502 | if (fp->f_fglob) | |
2503 | fg_free(fp->f_fglob); | |
2504 | fp->f_fglob = wfp->f_fglob; | |
2505 | ||
1c79356b A |
2506 | fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; |
2507 | _fdrelse(fdp, dfd); | |
91447636 A |
2508 | |
2509 | proc_fdunlock(p); | |
2510 | ||
2511 | FREE_ZONE(wfp, sizeof *fp, M_FILEPROC); | |
2512 | ||
1c79356b A |
2513 | return (0); |
2514 | ||
2515 | default: | |
91447636 | 2516 | proc_fdunlock(p); |
1c79356b A |
2517 | return (error); |
2518 | } | |
2519 | /* NOTREACHED */ | |
2520 | } | |
2521 | ||
91447636 A |
2522 | void |
2523 | fg_ref(struct fileproc * fp) | |
1c79356b | 2524 | { |
91447636 A |
2525 | struct fileglob *fg; |
2526 | ||
2527 | fg = fp->f_fglob; | |
2528 | ||
2529 | lck_mtx_lock(&fg->fg_lock); | |
2530 | fg->fg_count++; | |
2531 | lck_mtx_unlock(&fg->fg_lock); | |
1c79356b A |
2532 | } |
2533 | ||
91447636 A |
2534 | void |
2535 | fg_drop(struct fileproc * fp) | |
1c79356b | 2536 | { |
91447636 A |
2537 | struct fileglob *fg; |
2538 | ||
2539 | fg = fp->f_fglob; | |
2540 | lck_mtx_lock(&fg->fg_lock); | |
2541 | fg->fg_count--; | |
2542 | lck_mtx_unlock(&fg->fg_lock); | |
1c79356b A |
2543 | } |
2544 | ||
9bccf70c | 2545 | |
91447636 A |
2546 | void |
2547 | fg_insertuipc(struct fileglob * fg) | |
9bccf70c | 2548 | { |
91447636 | 2549 | int insertque = 0; |
9bccf70c | 2550 | |
91447636 A |
2551 | lck_mtx_lock(&fg->fg_lock); |
2552 | ||
2553 | while (fg->fg_lflags & FG_RMMSGQ) { | |
2554 | fg->fg_lflags |= FG_WRMMSGQ; | |
2555 | msleep(&fg->fg_lflags, &fg->fg_lock, 0, "fg_insertuipc", 0); | |
2556 | } | |
9bccf70c | 2557 | |
91447636 A |
2558 | fg->fg_count++; |
2559 | fg->fg_msgcount++; | |
2560 | if (fg->fg_msgcount == 1) { | |
2561 | fg->fg_lflags |= FG_INSMSGQ; | |
2562 | insertque=1; | |
9bccf70c | 2563 | } |
91447636 A |
2564 | lck_mtx_unlock(&fg->fg_lock); |
2565 | ||
2566 | if (insertque) { | |
2567 | lck_mtx_lock(uipc_lock); | |
2568 | LIST_INSERT_HEAD(&fmsghead, fg, f_msglist); | |
2569 | lck_mtx_unlock(uipc_lock); | |
2570 | lck_mtx_lock(&fg->fg_lock); | |
2571 | fg->fg_lflags &= ~FG_INSMSGQ; | |
2572 | if (fg->fg_lflags & FG_WINSMSGQ) { | |
2573 | fg->fg_lflags &= ~FG_WINSMSGQ; | |
2574 | wakeup(&fg->fg_lflags); | |
2575 | } | |
2576 | lck_mtx_unlock(&fg->fg_lock); | |
2577 | } | |
2578 | ||
2579 | } | |
9bccf70c | 2580 | |
91447636 A |
2581 | void |
2582 | fg_removeuipc(struct fileglob * fg) | |
2583 | { | |
2584 | int removeque = 0; | |
2585 | ||
2586 | lck_mtx_lock(&fg->fg_lock); | |
2587 | while (fg->fg_lflags & FG_INSMSGQ) { | |
2588 | fg->fg_lflags |= FG_WINSMSGQ; | |
2589 | msleep(&fg->fg_lflags, &fg->fg_lock, 0, "fg_removeuipc", 0); | |
2590 | } | |
2591 | fg->fg_msgcount--; | |
2592 | if (fg->fg_msgcount == 0) { | |
2593 | fg->fg_lflags |= FG_RMMSGQ; | |
2594 | removeque=1; | |
9bccf70c | 2595 | } |
91447636 A |
2596 | lck_mtx_unlock(&fg->fg_lock); |
2597 | ||
2598 | if (removeque) { | |
2599 | lck_mtx_lock(uipc_lock); | |
2600 | LIST_REMOVE(fg, f_msglist); | |
2601 | lck_mtx_unlock(uipc_lock); | |
2602 | lck_mtx_lock(&fg->fg_lock); | |
2603 | fg->fg_lflags &= ~FG_RMMSGQ; | |
2604 | if (fg->fg_lflags & FG_WRMMSGQ) { | |
2605 | fg->fg_lflags &= ~FG_WRMMSGQ; | |
2606 | wakeup(&fg->fg_lflags); | |
2607 | } | |
2608 | lck_mtx_unlock(&fg->fg_lock); | |
2609 | } | |
2610 | } | |
2611 | ||
2612 | ||
2613 | int | |
2614 | fo_read(struct fileproc *fp, struct uio *uio, kauth_cred_t cred, int flags, struct proc *p) | |
2615 | { | |
2616 | return ((*fp->f_ops->fo_read)(fp, uio, cred, flags, p)); | |
2617 | } | |
2618 | ||
2619 | int | |
2620 | fo_write(struct fileproc *fp, struct uio *uio, kauth_cred_t cred, int flags, struct proc *p) | |
2621 | { | |
2622 | return((*fp->f_ops->fo_write)(fp, uio, cred, flags, p)); | |
2623 | } | |
2624 | ||
2625 | int | |
2626 | fo_ioctl(struct fileproc *fp, u_long com, caddr_t data, struct proc *p) | |
2627 | { | |
2628 | int error; | |
2629 | ||
2630 | proc_fdunlock(p); | |
2631 | error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); | |
2632 | proc_fdlock(p); | |
2633 | return(error); | |
2634 | } | |
2635 | ||
2636 | int | |
2637 | fo_select(struct fileproc *fp, int which, void *wql, struct proc *p) | |
2638 | { | |
2639 | return((*fp->f_ops->fo_select)(fp, which, wql, p)); | |
2640 | } | |
2641 | ||
2642 | int | |
2643 | fo_close(struct fileglob *fg, struct proc *p) | |
2644 | { | |
2645 | return((*fg->fg_ops->fo_close)(fg, p)); | |
9bccf70c A |
2646 | } |
2647 | ||
1c79356b | 2648 | int |
91447636 | 2649 | fo_kqfilter(struct fileproc *fp, struct knote *kn, struct proc *p) |
1c79356b | 2650 | { |
91447636 | 2651 | return ((*fp->f_ops->fo_kqfilter)(fp, kn, p)); |
1c79356b A |
2652 | } |
2653 |