]>
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 | * | |
37839358 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 | * |
37839358 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, | |
37839358 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 | |
3a60a9f5 A |
704 | case F_GLOBAL_NOCACHE: |
705 | if (fp->f_type != DTYPE_VNODE) { | |
706 | error = EBADF; | |
707 | goto out; | |
708 | } | |
709 | vp = (struct vnode *)fp->f_data; | |
710 | proc_fdunlock(p); | |
711 | ||
712 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
713 | ||
714 | *retval = vnode_isnocache(vp); | |
715 | ||
716 | if (uap->arg) | |
717 | vnode_setnocache(vp); | |
718 | else | |
719 | vnode_clearnocache(vp); | |
720 | ||
721 | (void)vnode_put(vp); | |
722 | } | |
723 | goto outdrop; | |
724 | ||
91447636 A |
725 | case F_RDADVISE: { |
726 | struct radvisory ra_struct; | |
9bccf70c | 727 | |
91447636 A |
728 | if (fp->f_type != DTYPE_VNODE) { |
729 | error = EBADF; | |
730 | goto out; | |
731 | } | |
55e303ae | 732 | vp = (struct vnode *)fp->f_data; |
91447636 | 733 | proc_fdunlock(p); |
55e303ae | 734 | |
91447636 A |
735 | if ( (error = copyin(argp, (caddr_t)&ra_struct, sizeof (ra_struct))) ) |
736 | goto outdrop; | |
737 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
738 | error = VNOP_IOCTL(vp, F_RDADVISE, (caddr_t)&ra_struct, 0, &context); | |
739 | ||
740 | (void)vnode_put(vp); | |
741 | } | |
742 | goto outdrop; | |
743 | } | |
55e303ae | 744 | |
1c79356b | 745 | case F_READBOOTSTRAP: |
91447636 A |
746 | case F_WRITEBOOTSTRAP: { |
747 | fbootstraptransfer_t fbt_struct; | |
748 | user_fbootstraptransfer_t user_fbt_struct; | |
749 | int sizeof_struct; | |
750 | caddr_t boot_structp; | |
751 | ||
752 | if (fp->f_type != DTYPE_VNODE) { | |
753 | error = EBADF; | |
754 | goto out; | |
755 | } | |
ccc36f2f | 756 | vp = (struct vnode *)fp->f_data; |
91447636 | 757 | proc_fdunlock(p); |
1c79356b | 758 | |
91447636 A |
759 | if (IS_64BIT_PROCESS(p)) { |
760 | sizeof_struct = sizeof(user_fbt_struct); | |
761 | boot_structp = (caddr_t) &user_fbt_struct; | |
762 | } | |
763 | else { | |
764 | sizeof_struct = sizeof(fbt_struct); | |
765 | boot_structp = (caddr_t) &fbt_struct; | |
766 | } | |
767 | error = copyin(argp, boot_structp, sizeof_struct); | |
1c79356b | 768 | if (error) |
91447636 A |
769 | goto outdrop; |
770 | if ( (error = vnode_getwithref(vp)) ) { | |
771 | goto outdrop; | |
772 | } | |
1c79356b | 773 | if (uap->cmd == F_WRITEBOOTSTRAP) { |
91447636 A |
774 | /* |
775 | * Make sure that we are root. Updating the | |
776 | * bootstrap on a disk could be a security hole | |
777 | */ | |
ccc36f2f | 778 | if (!is_suser()) { |
91447636 | 779 | (void)vnode_put(vp); |
ccc36f2f | 780 | error = EACCES; |
91447636 | 781 | goto outdrop; |
ccc36f2f | 782 | } |
9bccf70c | 783 | } |
91447636 | 784 | if (strcmp(vnode_mount(vp)->mnt_vfsstat.f_fstypename, "hfs") != 0) { |
9bccf70c | 785 | error = EINVAL; |
91447636 A |
786 | } else { |
787 | /* | |
788 | * call vnop_ioctl to handle the I/O | |
789 | */ | |
790 | error = VNOP_IOCTL(vp, uap->cmd, boot_structp, 0, &context); | |
9bccf70c | 791 | } |
91447636 A |
792 | (void)vnode_put(vp); |
793 | goto outdrop; | |
794 | } | |
795 | case F_LOG2PHYS: { | |
796 | struct log2phys l2p_struct; /* structure for allocate command */ | |
9bccf70c | 797 | |
91447636 A |
798 | if (fp->f_type != DTYPE_VNODE) { |
799 | error = EBADF; | |
800 | goto out; | |
801 | } | |
1c79356b | 802 | vp = (struct vnode *)fp->f_data; |
91447636 A |
803 | proc_fdunlock(p); |
804 | if ( (error = vnode_getwithref(vp)) ) { | |
805 | goto outdrop; | |
806 | } | |
807 | error = VNOP_OFFTOBLK(vp, fp->f_offset, &lbn); | |
808 | if (error) { | |
809 | (void)vnode_put(vp); | |
810 | goto outdrop; | |
811 | } | |
812 | error = VNOP_BLKTOOFF(vp, lbn, &offset); | |
813 | if (error) { | |
814 | (void)vnode_put(vp); | |
815 | goto outdrop; | |
816 | } | |
817 | devBlockSize = vfs_devblocksize(vnode_mount(vp)); | |
818 | ||
819 | error = VNOP_BLOCKMAP(vp, offset, devBlockSize, &bn, NULL, NULL, 0, &context); | |
820 | ||
821 | (void)vnode_put(vp); | |
ccc36f2f | 822 | |
1c79356b A |
823 | if (!error) { |
824 | l2p_struct.l2p_flags = 0; /* for now */ | |
825 | l2p_struct.l2p_contigbytes = 0; /* for now */ | |
826 | l2p_struct.l2p_devoffset = bn * devBlockSize; | |
827 | l2p_struct.l2p_devoffset += fp->f_offset - offset; | |
91447636 A |
828 | error = copyout((caddr_t)&l2p_struct, argp, sizeof (l2p_struct)); |
829 | } | |
830 | goto outdrop; | |
1c79356b | 831 | } |
55e303ae | 832 | case F_GETPATH: { |
91447636 A |
833 | char *pathbufp; |
834 | int pathlen; | |
55e303ae | 835 | |
91447636 A |
836 | if (fp->f_type != DTYPE_VNODE) { |
837 | error = EBADF; | |
838 | goto out; | |
839 | } | |
55e303ae | 840 | vp = (struct vnode *)fp->f_data; |
91447636 | 841 | proc_fdunlock(p); |
55e303ae | 842 | |
91447636 A |
843 | pathlen = MAXPATHLEN; |
844 | MALLOC(pathbufp, char *, pathlen, M_TEMP, M_WAITOK); | |
845 | if (pathbufp == NULL) { | |
846 | error = ENOMEM; | |
847 | goto outdrop; | |
848 | } | |
849 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
850 | error = vn_getpath(vp, pathbufp, &pathlen); | |
851 | (void)vnode_put(vp); | |
4a249263 | 852 | |
91447636 A |
853 | if (error == 0) |
854 | error = copyout((caddr_t)pathbufp, argp, pathlen); | |
855 | } | |
856 | FREE(pathbufp, M_TEMP); | |
857 | goto outdrop; | |
55e303ae A |
858 | } |
859 | ||
91447636 A |
860 | case F_PATHPKG_CHECK: { |
861 | char *pathbufp; | |
862 | size_t pathlen; | |
863 | ||
864 | if (fp->f_type != DTYPE_VNODE) { | |
865 | error = EBADF; | |
866 | goto out; | |
867 | } | |
55e303ae | 868 | vp = (struct vnode *)fp->f_data; |
91447636 | 869 | proc_fdunlock(p); |
55e303ae | 870 | |
91447636 A |
871 | pathlen = MAXPATHLEN; |
872 | pathbufp = kalloc(MAXPATHLEN); | |
873 | ||
874 | if ( (error = copyinstr(argp, pathbufp, MAXPATHLEN, &pathlen)) == 0 ) { | |
875 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
876 | error = vn_path_package_check(vp, pathbufp, pathlen, retval); | |
877 | ||
878 | (void)vnode_put(vp); | |
879 | } | |
880 | } | |
881 | kfree(pathbufp, MAXPATHLEN); | |
882 | goto outdrop; | |
883 | } | |
884 | ||
885 | case F_CHKCLEAN: // used by regression tests to see if all dirty pages got cleaned by fsync() | |
886 | case F_FULLFSYNC: // fsync + flush the journal + DKIOCSYNCHRONIZECACHE | |
887 | case F_FREEZE_FS: // freeze all other fs operations for the fs of this fd | |
888 | case F_THAW_FS: { // thaw all frozen fs operations for the fs of this fd | |
889 | if (fp->f_type != DTYPE_VNODE) { | |
890 | error = EBADF; | |
891 | goto out; | |
892 | } | |
893 | vp = (struct vnode *)fp->f_data; | |
894 | proc_fdunlock(p); | |
ccc36f2f | 895 | |
91447636 A |
896 | if ( (error = vnode_getwithref(vp)) == 0 ) { |
897 | error = VNOP_IOCTL(vp, uap->cmd, (caddr_t)NULL, 0, &context); | |
898 | ||
899 | (void)vnode_put(vp); | |
900 | } | |
ccc36f2f | 901 | break; |
55e303ae A |
902 | } |
903 | ||
1c79356b | 904 | default: |
91447636 A |
905 | if (uap->cmd < FCNTL_FS_SPECIFIC_BASE) { |
906 | error = EINVAL; | |
907 | goto out; | |
908 | } | |
909 | ||
910 | // if it's a fs-specific fcntl() then just pass it through | |
911 | ||
912 | if (fp->f_type != DTYPE_VNODE) { | |
913 | error = EBADF; | |
914 | goto out; | |
915 | } | |
916 | vp = (struct vnode *)fp->f_data; | |
917 | proc_fdunlock(p); | |
918 | ||
919 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
920 | error = VNOP_IOCTL(vp, uap->cmd, CAST_DOWN(caddr_t, argp), 0, &context); | |
921 | ||
922 | (void)vnode_put(vp); | |
923 | } | |
924 | break; | |
925 | ||
1c79356b | 926 | } |
ccc36f2f | 927 | |
91447636 A |
928 | outdrop: |
929 | AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1); | |
930 | fp_drop(p, fd, fp, 0); | |
931 | return(error); | |
932 | out: | |
933 | fp_drop(p, fd, fp, 1); | |
934 | proc_fdunlock(p); | |
935 | return(error); | |
1c79356b A |
936 | } |
937 | ||
938 | /* | |
939 | * Common code for dup, dup2, and fcntl(F_DUPFD). | |
940 | */ | |
941 | int | |
91447636 | 942 | finishdup(struct proc * p, struct filedesc *fdp, int old, int new, register_t *retval) |
1c79356b | 943 | { |
91447636 A |
944 | struct fileproc *nfp; |
945 | struct fileproc *ofp; | |
1c79356b | 946 | |
91447636 | 947 | if ((ofp = fdp->fd_ofiles[old]) == NULL || |
1c79356b A |
948 | (fdp->fd_ofileflags[old] & UF_RESERVED)) { |
949 | _fdrelse(fdp, new); | |
950 | return (EBADF); | |
951 | } | |
91447636 A |
952 | fg_ref(ofp); |
953 | proc_fdunlock(p); | |
954 | ||
955 | MALLOC_ZONE(nfp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK); | |
956 | bzero(nfp, sizeof(struct fileproc)); | |
957 | ||
958 | proc_fdlock(p); | |
959 | nfp->f_flags = ofp->f_flags; | |
960 | nfp->f_fglob = ofp->f_fglob; | |
961 | nfp->f_iocount = 0; | |
962 | ||
963 | fdp->fd_ofiles[new] = nfp; | |
1c79356b | 964 | fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; |
1c79356b A |
965 | if (new > fdp->fd_lastfile) |
966 | fdp->fd_lastfile = new; | |
967 | *retval = new; | |
968 | return (0); | |
969 | } | |
970 | ||
91447636 | 971 | |
1c79356b | 972 | int |
91447636 | 973 | close(struct proc *p, struct close_args *uap, __unused register_t *retval) |
1c79356b | 974 | { |
91447636 | 975 | struct fileproc *fp; |
1c79356b | 976 | int fd = uap->fd; |
91447636 | 977 | int error =0; |
1c79356b | 978 | |
e5568f75 | 979 | AUDIT_SYSCLOSE(p, fd); |
91447636 A |
980 | |
981 | proc_fdlock(p); | |
982 | ||
983 | if ( (error = fp_lookup(p,fd,&fp, 1)) ) { | |
984 | proc_fdunlock(p); | |
985 | return(error); | |
986 | } | |
987 | ||
988 | error = close_internal(p, fd, fp, CLOSEINT_LOCKED | CLOSEINT_WAITONCLOSE); | |
989 | ||
990 | proc_fdunlock(p); | |
991 | ||
992 | return(error); | |
993 | } | |
994 | ||
995 | ||
996 | /* | |
997 | * Close a file descriptor. | |
998 | */ | |
999 | int | |
1000 | close_internal(struct proc *p, int fd, struct fileproc *fp, int flags) | |
1001 | { | |
1002 | struct filedesc *fdp = p->p_fd; | |
1003 | int error =0; | |
1004 | int locked = flags & CLOSEINT_LOCKED; | |
1005 | int waitonclose = flags & CLOSEINT_WAITONCLOSE; | |
1006 | int norelse = flags & CLOSEINT_NOFDRELSE; | |
1007 | int nofdref = flags & CLOSEINT_NOFDNOREF; | |
1008 | int slpstate = PRIBIO; | |
1009 | ||
1010 | if (!locked) | |
1011 | proc_fdlock(p); | |
55e303ae A |
1012 | |
1013 | /* Keep people from using the filedesc while we are closing it */ | |
1014 | fdp->fd_ofileflags[fd] |= UF_RESERVED; | |
55e303ae | 1015 | |
91447636 A |
1016 | fdp->fd_ofileflags[fd] |= UF_CLOSING; |
1017 | ||
1018 | ||
1019 | if ((waitonclose && ((fp->f_flags & FP_CLOSING) == FP_CLOSING))) { | |
1020 | if (nofdref == 0) | |
1021 | fp_drop(p, fd, fp, 1); | |
1022 | fp->f_flags |= FP_WAITCLOSE; | |
1023 | if (!locked) | |
1024 | slpstate |= PDROP; | |
1025 | msleep(&fp->f_flags, &p->p_fdmlock, slpstate, "close wait",0) ; | |
1026 | return(EBADF); | |
1027 | } | |
1028 | ||
1029 | fp->f_flags |= FP_CLOSING; | |
1030 | if (nofdref) | |
1031 | fp->f_iocount++; | |
1032 | ||
1033 | if ( (fp->f_flags & FP_AIOISSUED) || kauth_authorize_fileop_has_listeners() ) { | |
1034 | ||
1035 | proc_fdunlock(p); | |
1036 | ||
1037 | if ( (fp->f_type == DTYPE_VNODE) && kauth_authorize_fileop_has_listeners() ) { | |
1038 | /* | |
1039 | * call out to allow 3rd party notification of close. | |
1040 | * Ignore result of kauth_authorize_fileop call. | |
1041 | */ | |
1042 | if (vnode_getwithref((vnode_t)fp->f_data) == 0) { | |
1043 | u_int fileop_flags = 0; | |
1044 | if ((fp->f_flags & FP_WRITTEN) != 0) | |
1045 | fileop_flags |= KAUTH_FILEOP_CLOSE_MODIFIED; | |
1046 | kauth_authorize_fileop(fp->f_fglob->fg_cred, KAUTH_FILEOP_CLOSE, | |
1047 | (uintptr_t)fp->f_data, (uintptr_t)fileop_flags); | |
1048 | vnode_put((vnode_t)fp->f_data); | |
1049 | } | |
1050 | } | |
1051 | if (fp->f_flags & FP_AIOISSUED) | |
1052 | /* | |
1053 | * cancel all async IO requests that can be cancelled. | |
1054 | */ | |
1055 | _aio_close( p, fd ); | |
1056 | ||
1057 | proc_fdlock(p); | |
1058 | } | |
1059 | ||
1060 | if (fd < fdp->fd_knlistsize) | |
55e303ae A |
1061 | knote_fdclose(p, fd); |
1062 | ||
91447636 A |
1063 | if (fp->f_flags & FP_WAITEVENT) |
1064 | (void)waitevent_close(p, fp); | |
1065 | ||
1066 | if ((fp->f_flags & FP_INCHRREAD) == 0) | |
1067 | fileproc_drain(p, fp); | |
1068 | if (norelse == 0) | |
1069 | _fdrelse(fdp, fd); | |
1070 | error = closef_locked(fp, fp->f_fglob, p); | |
1071 | if ((fp->f_flags & FP_WAITCLOSE) == FP_WAITCLOSE) | |
1072 | wakeup(&fp->f_flags); | |
1073 | fp->f_flags &= ~(FP_WAITCLOSE | FP_CLOSING); | |
1074 | ||
1075 | if (!locked) | |
1076 | proc_fdunlock(p); | |
1077 | ||
1078 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1079 | return(error); | |
1c79356b A |
1080 | } |
1081 | ||
1082 | /* | |
1083 | * Return status information about a file descriptor. | |
91447636 A |
1084 | * |
1085 | * XXX switch on node type is bogus; need a stat in struct fileops instead. | |
1c79356b | 1086 | */ |
91447636 A |
1087 | static int |
1088 | fstat1(struct proc *p, int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size) | |
1c79356b | 1089 | { |
91447636 A |
1090 | struct fileproc *fp; |
1091 | struct stat sb; | |
1092 | struct user_stat user_sb; | |
1093 | int error, my_size; | |
1094 | int funnel_state; | |
1095 | short type; | |
1096 | caddr_t data; | |
1097 | kauth_filesec_t fsec; | |
1098 | ssize_t xsecurity_bufsize; | |
1099 | int entrycount; | |
1100 | struct vfs_context context; | |
1c79356b | 1101 | |
91447636 A |
1102 | |
1103 | AUDIT_ARG(fd, fd); | |
1104 | ||
1105 | if ((error = fp_lookup(p, fd, &fp, 0)) != 0) | |
1106 | return(error); | |
1107 | type = fp->f_type; | |
1108 | data = fp->f_data; | |
1109 | fsec = KAUTH_FILESEC_NONE; | |
1110 | ||
1111 | switch (type) { | |
1c79356b A |
1112 | |
1113 | case DTYPE_VNODE: | |
91447636 A |
1114 | context.vc_proc = current_proc(); |
1115 | context.vc_ucred = kauth_cred_get(); | |
1116 | if ((error = vnode_getwithref((vnode_t)data)) == 0) { | |
1117 | /* | |
1118 | * If the caller has the file open, and is not requesting extended security, | |
1119 | * we are going to let them get the basic stat information. | |
1120 | */ | |
1121 | if (xsecurity == USER_ADDR_NULL) { | |
1122 | error = vn_stat_noauth((vnode_t)data, &sb, NULL, &context); | |
1123 | } else { | |
1124 | error = vn_stat((vnode_t)data, &sb, &fsec, &context); | |
1125 | } | |
1126 | ||
1127 | AUDIT_ARG(vnpath, (struct vnode *)data, ARG_VNODE1); | |
1128 | (void)vnode_put((vnode_t)data); | |
55e303ae | 1129 | } |
1c79356b A |
1130 | break; |
1131 | ||
1132 | case DTYPE_SOCKET: | |
91447636 A |
1133 | error = soo_stat((struct socket *)data, &sb); |
1134 | break; | |
1135 | ||
1136 | case DTYPE_PIPE: | |
1137 | error = pipe_stat((void *)data, &sb); | |
1c79356b A |
1138 | break; |
1139 | ||
1140 | case DTYPE_PSXSHM: | |
91447636 | 1141 | error = pshm_stat((void *)data, &sb); |
1c79356b | 1142 | break; |
55e303ae A |
1143 | |
1144 | case DTYPE_KQUEUE: | |
91447636 A |
1145 | funnel_state = thread_funnel_set(kernel_flock, TRUE); |
1146 | error = kqueue_stat(fp, &sb, p); | |
1147 | thread_funnel_set(kernel_flock, funnel_state); | |
1148 | break; | |
55e303ae | 1149 | |
1c79356b | 1150 | default: |
91447636 A |
1151 | error = EBADF; |
1152 | goto out; | |
1153 | } | |
1154 | /* Zap spare fields */ | |
1155 | sb.st_lspare = 0; | |
1156 | sb.st_qspare[0] = 0LL; | |
1157 | sb.st_qspare[1] = 0LL; | |
1158 | if (error == 0) { | |
1159 | caddr_t sbp; | |
1160 | if (IS_64BIT_PROCESS(current_proc())) { | |
1161 | munge_stat(&sb, &user_sb); | |
1162 | my_size = sizeof(user_sb); | |
1163 | sbp = (caddr_t)&user_sb; | |
1164 | } | |
1165 | else { | |
1166 | my_size = sizeof(sb); | |
1167 | sbp = (caddr_t)&sb; | |
1168 | } | |
1169 | error = copyout(sbp, ub, my_size); | |
1c79356b | 1170 | } |
1c79356b | 1171 | |
91447636 A |
1172 | /* caller wants extended security information? */ |
1173 | if (xsecurity != USER_ADDR_NULL) { | |
1c79356b | 1174 | |
91447636 A |
1175 | /* did we get any? */ |
1176 | if (fsec == KAUTH_FILESEC_NONE) { | |
1177 | if (susize(xsecurity_size, 0) != 0) { | |
1178 | error = EFAULT; | |
1179 | goto out; | |
1180 | } | |
1181 | } else { | |
1182 | /* find the user buffer size */ | |
1183 | xsecurity_bufsize = fusize(xsecurity_size); | |
1c79356b | 1184 | |
91447636 A |
1185 | /* copy out the actual data size */ |
1186 | if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) { | |
1187 | error = EFAULT; | |
1188 | goto out; | |
1189 | } | |
1c79356b | 1190 | |
91447636 A |
1191 | /* if the caller supplied enough room, copy out to it */ |
1192 | if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec)) | |
1193 | error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec)); | |
1194 | } | |
1c79356b | 1195 | } |
91447636 A |
1196 | out: |
1197 | fp_drop(p, fd, fp, 0); | |
1198 | if (fsec != NULL) | |
1199 | kauth_filesec_free(fsec); | |
1c79356b A |
1200 | return (error); |
1201 | } | |
91447636 A |
1202 | |
1203 | int | |
1204 | fstat_extended(struct proc *p, struct fstat_extended_args *uap, __unused register_t *retval) | |
1205 | { | |
1206 | return(fstat1(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size)); | |
1207 | } | |
1208 | ||
1209 | int | |
1210 | fstat(struct proc *p, register struct fstat_args *uap, __unused register_t *retval) | |
1211 | { | |
1212 | return(fstat1(p, uap->fd, uap->ub, 0, 0)); | |
1213 | } | |
1c79356b A |
1214 | |
1215 | /* | |
1216 | * Return pathconf information about a file descriptor. | |
1217 | */ | |
91447636 | 1218 | int |
1c79356b A |
1219 | fpathconf(p, uap, retval) |
1220 | struct proc *p; | |
1221 | register struct fpathconf_args *uap; | |
1222 | register_t *retval; | |
1223 | { | |
1224 | int fd = uap->fd; | |
91447636 | 1225 | struct fileproc *fp; |
1c79356b | 1226 | struct vnode *vp; |
91447636 A |
1227 | struct vfs_context context; |
1228 | int error = 0; | |
1229 | short type; | |
1230 | caddr_t data; | |
1231 | ||
1c79356b | 1232 | |
55e303ae | 1233 | AUDIT_ARG(fd, uap->fd); |
91447636 A |
1234 | if ( (error = fp_lookup(p, fd, &fp, 0)) ) |
1235 | return(error); | |
1236 | type = fp->f_type; | |
1237 | data = fp->f_data; | |
1238 | ||
1239 | switch (type) { | |
1c79356b A |
1240 | |
1241 | case DTYPE_SOCKET: | |
91447636 A |
1242 | if (uap->name != _PC_PIPE_BUF) { |
1243 | error = EINVAL; | |
1244 | goto out; | |
1245 | } | |
1c79356b | 1246 | *retval = PIPE_BUF; |
91447636 A |
1247 | error = 0; |
1248 | goto out; | |
1249 | ||
1250 | case DTYPE_PIPE: | |
1251 | *retval = PIPE_BUF; | |
1252 | error = 0; | |
1253 | goto out; | |
1c79356b A |
1254 | |
1255 | case DTYPE_VNODE: | |
91447636 A |
1256 | vp = (struct vnode *)data; |
1257 | ||
1258 | if ( (error = vnode_getwithref(vp)) == 0) { | |
1259 | AUDIT_ARG(vnpath, vp, ARG_VNODE1); | |
1260 | ||
1261 | context.vc_proc = p; | |
1262 | context.vc_ucred = kauth_cred_get(); | |
1263 | ||
1264 | error = vn_pathconf(vp, uap->name, retval, &context); | |
1265 | ||
1266 | (void)vnode_put(vp); | |
1267 | } | |
1268 | goto out; | |
55e303ae | 1269 | |
91447636 A |
1270 | case DTYPE_PSXSHM: |
1271 | case DTYPE_KQUEUE: | |
1272 | error = EINVAL; | |
1273 | goto out; | |
1c79356b A |
1274 | |
1275 | default: | |
91447636 | 1276 | panic("fpathconf (unrecognized - %d)", type); |
1c79356b A |
1277 | } |
1278 | /*NOTREACHED*/ | |
91447636 A |
1279 | out: |
1280 | fp_drop(p, fd, fp, 0); | |
1281 | return(error); | |
1c79356b A |
1282 | } |
1283 | ||
1284 | /* | |
1285 | * Allocate a file descriptor for the process. | |
1286 | */ | |
1287 | int fdexpand; | |
1288 | ||
1289 | int | |
1290 | fdalloc(p, want, result) | |
1291 | struct proc *p; | |
1292 | int want; | |
1293 | int *result; | |
1294 | { | |
1295 | register struct filedesc *fdp = p->p_fd; | |
1296 | register int i; | |
91447636 A |
1297 | int lim, last, numfiles, oldnfiles; |
1298 | struct fileproc **newofiles, **ofiles; | |
1c79356b A |
1299 | char *newofileflags, *ofileflags; |
1300 | ||
1301 | /* | |
1302 | * Search for a free descriptor starting at the higher | |
1303 | * of want or fd_freefile. If that fails, consider | |
1304 | * expanding the ofile array. | |
1305 | */ | |
1306 | lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); | |
1307 | for (;;) { | |
1308 | last = min(fdp->fd_nfiles, lim); | |
1309 | if ((i = want) < fdp->fd_freefile) | |
1310 | i = fdp->fd_freefile; | |
1311 | ofiles = &fdp->fd_ofiles[i]; | |
1312 | ofileflags = &fdp->fd_ofileflags[i]; | |
1313 | for (; i < last; i++) { | |
1314 | if (*ofiles == NULL && !(*ofileflags & UF_RESERVED)) { | |
1315 | *ofileflags = UF_RESERVED; | |
1316 | if (i > fdp->fd_lastfile) | |
1317 | fdp->fd_lastfile = i; | |
1318 | if (want <= fdp->fd_freefile) | |
1319 | fdp->fd_freefile = i; | |
1320 | *result = i; | |
1321 | return (0); | |
1322 | } | |
1323 | ofiles++; ofileflags++; | |
1324 | } | |
1325 | ||
1326 | /* | |
1327 | * No space in current array. Expand? | |
1328 | */ | |
1329 | if (fdp->fd_nfiles >= lim) | |
1330 | return (EMFILE); | |
1331 | if (fdp->fd_nfiles < NDEXTENT) | |
91447636 | 1332 | numfiles = NDEXTENT; |
1c79356b | 1333 | else |
91447636 | 1334 | numfiles = 2 * fdp->fd_nfiles; |
1c79356b | 1335 | /* Enforce lim */ |
91447636 A |
1336 | if (numfiles > lim) |
1337 | numfiles = lim; | |
1338 | proc_fdunlock(p); | |
1339 | MALLOC_ZONE(newofiles, struct fileproc **, | |
1340 | numfiles * OFILESIZE, M_OFILETABL, M_WAITOK); | |
1341 | proc_fdlock(p); | |
1342 | if (newofiles == NULL) { | |
1343 | return (ENOMEM); | |
1344 | } | |
1345 | if (fdp->fd_nfiles >= numfiles) { | |
1346 | FREE_ZONE(newofiles, numfiles * OFILESIZE, M_OFILETABL); | |
1c79356b A |
1347 | continue; |
1348 | } | |
91447636 | 1349 | newofileflags = (char *) &newofiles[numfiles]; |
1c79356b A |
1350 | /* |
1351 | * Copy the existing ofile and ofileflags arrays | |
1352 | * and zero the new portion of each array. | |
1353 | */ | |
1354 | oldnfiles = fdp->fd_nfiles; | |
1355 | (void) memcpy(newofiles, fdp->fd_ofiles, | |
1356 | oldnfiles * sizeof *fdp->fd_ofiles); | |
1357 | (void) memset(&newofiles[oldnfiles], 0, | |
91447636 | 1358 | (numfiles - oldnfiles) * sizeof *fdp->fd_ofiles); |
1c79356b A |
1359 | |
1360 | (void) memcpy(newofileflags, fdp->fd_ofileflags, | |
1361 | oldnfiles * sizeof *fdp->fd_ofileflags); | |
1362 | (void) memset(&newofileflags[oldnfiles], 0, | |
91447636 | 1363 | (numfiles - oldnfiles) * |
1c79356b A |
1364 | sizeof *fdp->fd_ofileflags); |
1365 | ofiles = fdp->fd_ofiles; | |
1366 | fdp->fd_ofiles = newofiles; | |
1367 | fdp->fd_ofileflags = newofileflags; | |
91447636 | 1368 | fdp->fd_nfiles = numfiles; |
1c79356b A |
1369 | FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL); |
1370 | fdexpand++; | |
1371 | } | |
1372 | } | |
1373 | ||
91447636 A |
1374 | /* |
1375 | * Check to see whether n user file descriptors | |
1376 | * are available to the process p. | |
1377 | */ | |
1378 | int | |
1379 | fdavail(p, n) | |
1380 | struct proc *p; | |
1381 | int n; | |
1382 | { | |
1383 | struct filedesc *fdp = p->p_fd; | |
1384 | struct fileproc **fpp; | |
1385 | char *flags; | |
1386 | int i, lim; | |
1387 | ||
1388 | lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); | |
1389 | if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) | |
1390 | return (1); | |
1391 | fpp = &fdp->fd_ofiles[fdp->fd_freefile]; | |
1392 | flags = &fdp->fd_ofileflags[fdp->fd_freefile]; | |
1393 | for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++) | |
1394 | if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0) | |
1395 | return (1); | |
1396 | return (0); | |
1397 | } | |
1398 | ||
1399 | void | |
1400 | fdrelse(p, fd) | |
1401 | struct proc *p; | |
1402 | int fd; | |
1403 | { | |
1404 | _fdrelse(p->p_fd, fd); | |
1405 | } | |
1406 | ||
1407 | void | |
1408 | fddrop(p, fd) | |
1409 | struct proc *p; | |
1410 | int fd; | |
1411 | { | |
1412 | struct filedesc *fdp = p->p_fd; | |
1413 | struct fileproc *fp; | |
1414 | ||
1415 | if (fd < fdp->fd_freefile) | |
1416 | fdp->fd_freefile = fd; | |
1417 | #if DIAGNOSTIC | |
1418 | if (fd > fdp->fd_lastfile) | |
1419 | panic("fdrelse: fd_lastfile inconsistent"); | |
1420 | #endif | |
1421 | fp = fdp->fd_ofiles[fd]; | |
1422 | fdp->fd_ofiles[fd] = NULL; | |
1423 | fdp->fd_ofileflags[fd] = 0; | |
1424 | ||
1425 | while ((fd = fdp->fd_lastfile) > 0 && | |
1426 | fdp->fd_ofiles[fd] == NULL && | |
1427 | !(fdp->fd_ofileflags[fd] & UF_RESERVED)) | |
1428 | fdp->fd_lastfile--; | |
1429 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1430 | } | |
1431 | ||
1432 | ||
1433 | int | |
1434 | fdgetf_noref(p, fd, resultfp) | |
1435 | struct proc *p; | |
1436 | int fd; | |
1437 | struct fileproc **resultfp; | |
1438 | { | |
1439 | struct filedesc *fdp = p->p_fd; | |
1440 | struct fileproc *fp; | |
1441 | ||
1442 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1443 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1444 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1445 | return (EBADF); | |
1446 | } | |
1447 | if (resultfp) | |
1448 | *resultfp = fp; | |
1449 | return (0); | |
1450 | } | |
1451 | ||
1452 | ||
1453 | /* should be called only when proc_fdlock is held */ | |
1454 | void | |
1455 | fp_setflags(proc_t p, struct fileproc * fp, int flags) | |
1456 | { | |
1457 | proc_fdlock(p); | |
1458 | fp->f_flags |= flags; | |
1459 | proc_fdunlock(p); | |
1460 | } | |
1461 | ||
1462 | void | |
1463 | fp_clearflags(proc_t p, struct fileproc * fp, int flags) | |
1464 | { | |
1465 | ||
1466 | proc_fdlock(p); | |
1467 | if (fp) | |
1468 | fp->f_flags &= ~flags; | |
1469 | proc_fdunlock(p); | |
1470 | } | |
1471 | ||
1472 | int | |
1473 | fp_getfvp(p, fd, resultfp, resultvp) | |
1474 | struct proc *p; | |
1475 | int fd; | |
1476 | struct fileproc **resultfp; | |
1477 | struct vnode **resultvp; | |
1478 | { | |
1479 | struct filedesc *fdp = p->p_fd; | |
1480 | struct fileproc *fp; | |
1481 | ||
1482 | proc_fdlock(p); | |
1483 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1484 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1485 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1486 | proc_fdunlock(p); | |
1487 | return (EBADF); | |
1488 | } | |
1489 | if (fp->f_type != DTYPE_VNODE) { | |
1490 | proc_fdunlock(p); | |
1491 | return(ENOTSUP); | |
1492 | } | |
1493 | fp->f_iocount++; | |
1494 | ||
1495 | if (resultfp) | |
1496 | *resultfp = fp; | |
1497 | if (resultvp) | |
1498 | *resultvp = (struct vnode *)fp->f_data; | |
1499 | proc_fdunlock(p); | |
1500 | ||
1501 | return (0); | |
1502 | } | |
1503 | ||
1504 | ||
1505 | /* | |
1506 | * Returns: EBADF The file descriptor is invalid | |
1507 | * EOPNOTSUPP The file descriptor is not a socket | |
1508 | * 0 Success | |
1509 | * | |
1510 | * Notes: EOPNOTSUPP should probably be ENOTSOCK; this function is only | |
1511 | * ever called from accept1(). | |
1512 | */ | |
1513 | int | |
1514 | fp_getfsock(p, fd, resultfp, results) | |
1515 | struct proc *p; | |
1516 | int fd; | |
1517 | struct fileproc **resultfp; | |
1518 | struct socket **results; | |
1519 | { | |
1520 | struct filedesc *fdp = p->p_fd; | |
1521 | struct fileproc *fp; | |
1522 | ||
1523 | proc_fdlock(p); | |
1524 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1525 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1526 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1527 | proc_fdunlock(p); | |
1528 | return (EBADF); | |
1529 | } | |
1530 | if (fp->f_type != DTYPE_SOCKET) { | |
1531 | proc_fdunlock(p); | |
1532 | return(EOPNOTSUPP); | |
1533 | } | |
1534 | fp->f_iocount++; | |
1535 | ||
1536 | if (resultfp) | |
1537 | *resultfp = fp; | |
1538 | if (results) | |
1539 | *results = (struct socket *)fp->f_data; | |
1540 | proc_fdunlock(p); | |
1541 | ||
1542 | return (0); | |
1543 | } | |
1544 | ||
1545 | ||
1546 | int | |
1547 | fp_getfkq(p, fd, resultfp, resultkq) | |
1548 | struct proc *p; | |
1549 | int fd; | |
1550 | struct fileproc **resultfp; | |
1551 | struct kqueue **resultkq; | |
1552 | { | |
1553 | struct filedesc *fdp = p->p_fd; | |
1554 | struct fileproc *fp; | |
1555 | ||
1556 | proc_fdlock(p); | |
1557 | if ( fd < 0 || fd >= fdp->fd_nfiles || | |
1558 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1559 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1560 | proc_fdunlock(p); | |
1561 | return (EBADF); | |
1562 | } | |
1563 | if (fp->f_type != DTYPE_KQUEUE) { | |
1564 | proc_fdunlock(p); | |
1565 | return(EBADF); | |
1566 | } | |
1567 | fp->f_iocount++; | |
1568 | ||
1569 | if (resultfp) | |
1570 | *resultfp = fp; | |
1571 | if (resultkq) | |
1572 | *resultkq = (struct kqueue *)fp->f_data; | |
1573 | proc_fdunlock(p); | |
1574 | ||
1575 | return (0); | |
1576 | } | |
1577 | ||
1578 | int | |
1579 | fp_getfpshm(p, fd, resultfp, resultpshm) | |
1580 | struct proc *p; | |
1581 | int fd; | |
1582 | struct fileproc **resultfp; | |
1583 | struct pshmnode **resultpshm; | |
1584 | { | |
1585 | struct filedesc *fdp = p->p_fd; | |
1586 | struct fileproc *fp; | |
1587 | ||
1588 | proc_fdlock(p); | |
1589 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1590 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1591 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1592 | proc_fdunlock(p); | |
1593 | return (EBADF); | |
1594 | } | |
1595 | if (fp->f_type != DTYPE_PSXSHM) { | |
1596 | ||
1597 | proc_fdunlock(p); | |
1598 | return(EBADF); | |
1599 | } | |
1600 | fp->f_iocount++; | |
1601 | ||
1602 | if (resultfp) | |
1603 | *resultfp = fp; | |
1604 | if (resultpshm) | |
1605 | *resultpshm = (struct pshmnode *)fp->f_data; | |
1606 | proc_fdunlock(p); | |
1607 | ||
1608 | return (0); | |
1609 | } | |
1610 | ||
1611 | ||
1612 | int | |
1613 | fp_getfpsem(p, fd, resultfp, resultpsem) | |
1614 | struct proc *p; | |
1615 | int fd; | |
1616 | struct fileproc **resultfp; | |
1617 | struct psemnode **resultpsem; | |
1618 | { | |
1619 | struct filedesc *fdp = p->p_fd; | |
1620 | struct fileproc *fp; | |
1621 | ||
1622 | proc_fdlock(p); | |
1623 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1624 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1625 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1626 | proc_fdunlock(p); | |
1627 | return (EBADF); | |
1628 | } | |
1629 | if (fp->f_type != DTYPE_PSXSEM) { | |
1630 | proc_fdunlock(p); | |
1631 | return(EBADF); | |
1632 | } | |
1633 | fp->f_iocount++; | |
1634 | ||
1635 | if (resultfp) | |
1636 | *resultfp = fp; | |
1637 | if (resultpsem) | |
1638 | *resultpsem = (struct psemnode *)fp->f_data; | |
1639 | proc_fdunlock(p); | |
1640 | ||
1641 | return (0); | |
1642 | } | |
1643 | int | |
1644 | fp_lookup(p, fd, resultfp, locked) | |
1645 | struct proc *p; | |
1646 | int fd; | |
1647 | struct fileproc **resultfp; | |
1648 | int locked; | |
1649 | { | |
1650 | struct filedesc *fdp = p->p_fd; | |
1651 | struct fileproc *fp; | |
1652 | ||
1653 | if (!locked) | |
1654 | proc_fdlock(p); | |
1655 | if (fd < 0 || fd >= fdp->fd_nfiles || | |
1656 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1657 | (fdp->fd_ofileflags[fd] & UF_RESERVED)) { | |
1658 | if (!locked) | |
1659 | proc_fdunlock(p); | |
1660 | return (EBADF); | |
1661 | } | |
1662 | fp->f_iocount++; | |
1663 | ||
1664 | if (resultfp) | |
1665 | *resultfp = fp; | |
1666 | if (!locked) | |
1667 | proc_fdunlock(p); | |
1668 | ||
1669 | return (0); | |
1670 | } | |
1671 | ||
1672 | int | |
1673 | fp_drop_written(proc_t p, int fd, struct fileproc *fp) | |
1674 | { | |
1675 | int error; | |
1676 | ||
1677 | proc_fdlock(p); | |
1678 | ||
1679 | fp->f_flags |= FP_WRITTEN; | |
1680 | ||
1681 | error = fp_drop(p, fd, fp, 1); | |
1682 | ||
1683 | proc_fdunlock(p); | |
1684 | ||
1685 | return (error); | |
1686 | } | |
1687 | ||
1688 | ||
1689 | int | |
1690 | fp_drop_event(proc_t p, int fd, struct fileproc *fp) | |
1691 | { | |
1692 | int error; | |
1693 | ||
1694 | proc_fdlock(p); | |
1695 | ||
1696 | fp->f_flags |= FP_WAITEVENT; | |
1697 | ||
1698 | error = fp_drop(p, fd, fp, 1); | |
1699 | ||
1700 | proc_fdunlock(p); | |
1701 | ||
1702 | return (error); | |
1703 | } | |
1704 | ||
1c79356b | 1705 | int |
91447636 | 1706 | fp_drop(p, fd, fp, locked) |
1c79356b | 1707 | struct proc *p; |
91447636 A |
1708 | int fd; |
1709 | struct fileproc *fp; | |
1710 | int locked; | |
1c79356b | 1711 | { |
91447636 | 1712 | struct filedesc *fdp = p->p_fd; |
1c79356b | 1713 | |
91447636 A |
1714 | if (!locked) |
1715 | proc_fdlock(p); | |
1716 | if ((fp == FILEPROC_NULL) && (fd < 0 || fd >= fdp->fd_nfiles || | |
1717 | (fp = fdp->fd_ofiles[fd]) == NULL || | |
1718 | ((fdp->fd_ofileflags[fd] & UF_RESERVED) && | |
1719 | !(fdp->fd_ofileflags[fd] & UF_CLOSING)))) { | |
1720 | if (!locked) | |
1721 | proc_fdunlock(p); | |
1722 | return (EBADF); | |
1723 | } | |
1724 | fp->f_iocount--; | |
1725 | ||
1726 | if (p->p_fpdrainwait && fp->f_iocount == 0) { | |
1727 | p->p_fpdrainwait = 0; | |
1728 | wakeup(&p->p_fpdrainwait); | |
1729 | } | |
1730 | if (!locked) | |
1731 | proc_fdunlock(p); | |
1732 | ||
1c79356b A |
1733 | return (0); |
1734 | } | |
1735 | ||
91447636 A |
1736 | int |
1737 | file_vnode(int fd, struct vnode **vpp) | |
1c79356b | 1738 | { |
91447636 A |
1739 | struct proc * p = current_proc(); |
1740 | struct fileproc *fp; | |
1741 | int error; | |
1742 | ||
1743 | proc_fdlock(p); | |
1744 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
1745 | proc_fdunlock(p); | |
1746 | return(error); | |
1747 | } | |
1748 | if (fp->f_type != DTYPE_VNODE) { | |
1749 | fp_drop(p, fd, fp,1); | |
1750 | proc_fdunlock(p); | |
1751 | return(EINVAL); | |
1752 | } | |
1753 | *vpp = (struct vnode *)fp->f_data; | |
1754 | proc_fdunlock(p); | |
1755 | ||
1756 | return(0); | |
1c79356b A |
1757 | } |
1758 | ||
91447636 | 1759 | |
1c79356b | 1760 | int |
91447636 | 1761 | file_socket(int fd, struct socket **sp) |
1c79356b | 1762 | { |
91447636 A |
1763 | struct proc * p = current_proc(); |
1764 | struct fileproc *fp; | |
1765 | int error; | |
1766 | ||
1767 | proc_fdlock(p); | |
1768 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
1769 | proc_fdunlock(p); | |
1770 | return(error); | |
1771 | } | |
1772 | if (fp->f_type != DTYPE_SOCKET) { | |
1773 | fp_drop(p, fd, fp,1); | |
1774 | proc_fdunlock(p); | |
1775 | return(ENOTSOCK); | |
1776 | } | |
1777 | *sp = (struct socket *)fp->f_data; | |
1778 | proc_fdunlock(p); | |
1c79356b | 1779 | |
91447636 A |
1780 | return(0); |
1781 | } | |
1782 | ||
1783 | int | |
1784 | file_flags(int fd, int * flags) | |
1785 | { | |
1786 | ||
1787 | struct proc * p = current_proc(); | |
1788 | struct fileproc *fp; | |
1789 | int error; | |
1790 | ||
1791 | proc_fdlock(p); | |
1792 | if ( (error = fp_lookup(p, fd, &fp, 1)) ) { | |
1793 | proc_fdunlock(p); | |
1794 | return(error); | |
1795 | } | |
1796 | *flags = (int)fp->f_flag; | |
1797 | fp_drop(p, fd, fp,1); | |
1798 | proc_fdunlock(p); | |
1799 | ||
1800 | return(0); | |
1801 | } | |
1802 | ||
1803 | ||
1804 | int | |
1805 | file_drop(int fd) | |
1806 | { | |
1807 | struct fileproc *fp; | |
1808 | struct proc *p = current_proc(); | |
1809 | ||
1810 | proc_fdlock(p); | |
1811 | if (fd < 0 || fd >= p->p_fd->fd_nfiles || | |
1812 | (fp = p->p_fd->fd_ofiles[fd]) == NULL || | |
1813 | ((p->p_fd->fd_ofileflags[fd] & UF_RESERVED) && | |
1814 | !(p->p_fd->fd_ofileflags[fd] & UF_CLOSING))) { | |
1815 | proc_fdunlock(p); | |
1c79356b | 1816 | return (EBADF); |
91447636 A |
1817 | } |
1818 | fp->f_iocount --; | |
1819 | ||
1820 | if (p->p_fpdrainwait && fp->f_iocount == 0) { | |
1821 | p->p_fpdrainwait = 0; | |
1822 | wakeup(&p->p_fpdrainwait); | |
1823 | } | |
1824 | proc_fdunlock(p); | |
1825 | return(0); | |
1826 | ||
1c79356b | 1827 | |
1c79356b A |
1828 | } |
1829 | ||
91447636 A |
1830 | int |
1831 | falloc(p, resultfp, resultfd ) | |
1832 | struct proc *p; | |
1833 | struct fileproc **resultfp; | |
1834 | int *resultfd; | |
1835 | { | |
1836 | int error; | |
1837 | ||
1838 | proc_fdlock(p); | |
1839 | error = falloc_locked(p, resultfp, resultfd, 1); | |
1840 | proc_fdunlock(p); | |
1841 | ||
1842 | return(error); | |
1843 | } | |
1c79356b A |
1844 | /* |
1845 | * Create a new open file structure and allocate | |
1846 | * a file decriptor for the process that refers to it. | |
1847 | */ | |
1848 | int | |
91447636 A |
1849 | falloc_locked(p, resultfp, resultfd, locked) |
1850 | struct proc *p; | |
1851 | struct fileproc **resultfp; | |
1c79356b | 1852 | int *resultfd; |
91447636 | 1853 | int locked; |
1c79356b | 1854 | { |
91447636 A |
1855 | struct fileproc *fp, *fq; |
1856 | struct fileglob *fg; | |
1857 | int error, nfd; | |
1858 | ||
1859 | if (!locked) | |
1860 | proc_fdlock(p); | |
1861 | if ( (error = fdalloc(p, 0, &nfd)) ) { | |
1862 | if (!locked) | |
1863 | proc_fdunlock(p); | |
1c79356b | 1864 | return (error); |
91447636 | 1865 | } |
1c79356b | 1866 | if (nfiles >= maxfiles) { |
91447636 A |
1867 | if (!locked) |
1868 | proc_fdunlock(p); | |
1c79356b A |
1869 | tablefull("file"); |
1870 | return (ENFILE); | |
1871 | } | |
1872 | /* | |
1873 | * Allocate a new file descriptor. | |
1874 | * If the process has file descriptor zero open, add to the list | |
1875 | * of open files at that point, otherwise put it at the front of | |
1876 | * the list of open files. | |
1877 | */ | |
91447636 A |
1878 | proc_fdunlock(p); |
1879 | ||
1880 | MALLOC_ZONE(fp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK); | |
1881 | MALLOC_ZONE(fg, struct fileglob *, sizeof(struct fileglob), M_FILEGLOB, M_WAITOK); | |
1882 | bzero(fp, sizeof(struct fileproc)); | |
1883 | bzero(fg, sizeof(struct fileglob)); | |
1884 | lck_mtx_init(&fg->fg_lock, file_lck_grp, file_lck_attr); | |
1885 | ||
1886 | fp->f_iocount = 1; | |
1887 | fg->fg_count = 1; | |
1888 | fp->f_fglob = fg; | |
1889 | ||
1890 | proc_fdlock(p); | |
1891 | ||
1892 | fp->f_cred = kauth_cred_proc_ref(p); | |
1893 | ||
1894 | lck_mtx_lock(file_flist_lock); | |
1895 | ||
1c79356b | 1896 | nfiles++; |
91447636 A |
1897 | |
1898 | if ( (fq = p->p_fd->fd_ofiles[0]) ) { | |
1899 | LIST_INSERT_AFTER(fq->f_fglob, fg, f_list); | |
1900 | } else { | |
1901 | LIST_INSERT_HEAD(&filehead, fg, f_list); | |
1902 | } | |
1903 | lck_mtx_unlock(file_flist_lock); | |
1904 | ||
1905 | p->p_fd->fd_ofiles[nfd] = fp; | |
1906 | ||
1907 | if (!locked) | |
1908 | proc_fdunlock(p); | |
1909 | ||
1c79356b A |
1910 | if (resultfp) |
1911 | *resultfp = fp; | |
1912 | if (resultfd) | |
91447636 A |
1913 | *resultfd = nfd; |
1914 | ||
1c79356b A |
1915 | return (0); |
1916 | } | |
1917 | ||
1918 | /* | |
1919 | * Free a file structure. | |
1920 | */ | |
1921 | void | |
91447636 A |
1922 | fg_free(fg) |
1923 | struct fileglob *fg; | |
1c79356b | 1924 | { |
91447636 A |
1925 | kauth_cred_t cred; |
1926 | ||
1927 | lck_mtx_lock(file_flist_lock); | |
1928 | LIST_REMOVE(fg, f_list); | |
1929 | nfiles--; | |
1930 | lck_mtx_unlock(file_flist_lock); | |
1c79356b | 1931 | |
91447636 | 1932 | cred = fg->fg_cred; |
1c79356b | 1933 | if (cred != NOCRED) { |
91447636 A |
1934 | fg->fg_cred = NOCRED; |
1935 | kauth_cred_rele(cred); | |
1c79356b | 1936 | } |
91447636 | 1937 | lck_mtx_destroy(&fg->fg_lock, file_lck_grp); |
fa4905b1 | 1938 | |
91447636 | 1939 | FREE_ZONE(fg, sizeof *fg, M_FILEGLOB); |
1c79356b A |
1940 | } |
1941 | ||
1942 | void | |
1943 | fdexec(p) | |
1944 | struct proc *p; | |
1945 | { | |
91447636 A |
1946 | struct filedesc *fdp = p->p_fd; |
1947 | int i = fdp->fd_lastfile; | |
1948 | struct fileproc **fpp = &fdp->fd_ofiles[i]; | |
1949 | char *flags = &fdp->fd_ofileflags[i]; | |
1950 | int funnel_state; | |
1951 | ||
1952 | funnel_state = thread_funnel_set(kernel_flock, FALSE); | |
1953 | proc_fdlock(p); | |
1c79356b A |
1954 | |
1955 | while (i >= 0) { | |
1956 | if ((*flags & (UF_RESERVED|UF_EXCLOSE)) == UF_EXCLOSE) { | |
91447636 | 1957 | struct fileproc *fp = *fpp; |
1c79356b | 1958 | |
55e303ae A |
1959 | if (i < fdp->fd_knlistsize) |
1960 | knote_fdclose(p, i); | |
1961 | ||
1c79356b A |
1962 | *fpp = NULL; *flags = 0; |
1963 | if (i == fdp->fd_lastfile && i > 0) | |
1964 | fdp->fd_lastfile--; | |
91447636 A |
1965 | closef_locked(fp, fp->f_fglob, p); |
1966 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1c79356b | 1967 | } |
1c79356b A |
1968 | |
1969 | i--; fpp--; flags--; | |
1970 | } | |
91447636 A |
1971 | proc_fdunlock(p); |
1972 | thread_funnel_set(kernel_flock, funnel_state); | |
1c79356b A |
1973 | } |
1974 | ||
1975 | /* | |
1976 | * Copy a filedesc structure. | |
1977 | */ | |
1978 | struct filedesc * | |
1979 | fdcopy(p) | |
1980 | struct proc *p; | |
1981 | { | |
91447636 A |
1982 | struct filedesc *newfdp, *fdp = p->p_fd; |
1983 | int i; | |
1984 | struct fileproc *ofp, *fp; | |
1985 | vnode_t v_dir; | |
1c79356b A |
1986 | |
1987 | MALLOC_ZONE(newfdp, struct filedesc *, | |
1988 | sizeof *newfdp, M_FILEDESC, M_WAITOK); | |
91447636 A |
1989 | if (newfdp == NULL) |
1990 | return(NULL); | |
1991 | ||
1992 | proc_fdlock(p); | |
1993 | ||
1994 | /* | |
1995 | * the FD_CHROOT flag will be inherited via this copy | |
1996 | */ | |
1c79356b | 1997 | (void) memcpy(newfdp, fdp, sizeof *newfdp); |
91447636 A |
1998 | |
1999 | /* | |
2000 | * for both fd_cdir and fd_rdir make sure we get | |
2001 | * a valid reference... if we can't, than set | |
2002 | * set the pointer(s) to NULL in the child... this | |
2003 | * will keep us from using a non-referenced vp | |
2004 | * and allows us to do the vnode_rele only on | |
2005 | * a properly referenced vp | |
2006 | */ | |
2007 | if ( (v_dir = newfdp->fd_cdir) ) { | |
2008 | if (vnode_getwithref(v_dir) == 0) { | |
2009 | if ( (vnode_ref(v_dir)) ) | |
2010 | newfdp->fd_cdir = NULL; | |
2011 | vnode_put(v_dir); | |
2012 | } else | |
2013 | newfdp->fd_cdir = NULL; | |
2014 | } | |
2015 | if (newfdp->fd_cdir == NULL && fdp->fd_cdir) { | |
2016 | /* | |
2017 | * we couldn't get a new reference on | |
2018 | * the current working directory being | |
2019 | * inherited... we might as well drop | |
2020 | * our reference from the parent also | |
2021 | * since the vnode has gone DEAD making | |
2022 | * it useless... by dropping it we'll | |
2023 | * be that much closer to recyling it | |
2024 | */ | |
2025 | vnode_rele(fdp->fd_cdir); | |
2026 | fdp->fd_cdir = NULL; | |
2027 | } | |
2028 | ||
2029 | if ( (v_dir = newfdp->fd_rdir) ) { | |
2030 | if (vnode_getwithref(v_dir) == 0) { | |
2031 | if ( (vnode_ref(v_dir)) ) | |
2032 | newfdp->fd_rdir = NULL; | |
2033 | vnode_put(v_dir); | |
2034 | } else | |
2035 | newfdp->fd_rdir = NULL; | |
2036 | } | |
2037 | if (newfdp->fd_rdir == NULL && fdp->fd_rdir) { | |
2038 | /* | |
2039 | * we couldn't get a new reference on | |
2040 | * the root directory being | |
2041 | * inherited... we might as well drop | |
2042 | * our reference from the parent also | |
2043 | * since the vnode has gone DEAD making | |
2044 | * it useless... by dropping it we'll | |
2045 | * be that much closer to recyling it | |
2046 | */ | |
2047 | vnode_rele(fdp->fd_rdir); | |
2048 | fdp->fd_rdir = NULL; | |
2049 | } | |
1c79356b A |
2050 | newfdp->fd_refcnt = 1; |
2051 | ||
2052 | /* | |
2053 | * If the number of open files fits in the internal arrays | |
2054 | * of the open file structure, use them, otherwise allocate | |
2055 | * additional memory for the number of descriptors currently | |
2056 | * in use. | |
2057 | */ | |
2058 | if (newfdp->fd_lastfile < NDFILE) | |
2059 | i = NDFILE; | |
2060 | else { | |
2061 | /* | |
2062 | * Compute the smallest multiple of NDEXTENT needed | |
2063 | * for the file descriptors currently in use, | |
2064 | * allowing the table to shrink. | |
2065 | */ | |
2066 | i = newfdp->fd_nfiles; | |
2067 | while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2) | |
2068 | i /= 2; | |
2069 | } | |
91447636 A |
2070 | proc_fdunlock(p); |
2071 | ||
2072 | MALLOC_ZONE(newfdp->fd_ofiles, struct fileproc **, | |
1c79356b | 2073 | i * OFILESIZE, M_OFILETABL, M_WAITOK); |
91447636 A |
2074 | if (newfdp->fd_ofiles == NULL) { |
2075 | if (newfdp->fd_cdir) | |
2076 | vnode_rele(newfdp->fd_cdir); | |
2077 | if (newfdp->fd_rdir) | |
2078 | vnode_rele(newfdp->fd_rdir); | |
2079 | ||
2080 | FREE_ZONE(newfdp, sizeof *newfdp, M_FILEDESC); | |
2081 | return(NULL); | |
2082 | } | |
2083 | proc_fdlock(p); | |
2084 | ||
1c79356b A |
2085 | newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; |
2086 | newfdp->fd_nfiles = i; | |
91447636 | 2087 | |
1c79356b | 2088 | if (fdp->fd_nfiles > 0) { |
91447636 A |
2089 | struct fileproc **fpp; |
2090 | char *flags; | |
1c79356b A |
2091 | |
2092 | (void) memcpy(newfdp->fd_ofiles, fdp->fd_ofiles, | |
2093 | i * sizeof *fdp->fd_ofiles); | |
2094 | (void) memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags, | |
2095 | i * sizeof *fdp->fd_ofileflags); | |
2096 | ||
55e303ae A |
2097 | /* |
2098 | * kq descriptors cannot be copied. | |
2099 | */ | |
2100 | if (newfdp->fd_knlistsize != -1) { | |
2101 | fpp = &newfdp->fd_ofiles[newfdp->fd_lastfile]; | |
2102 | for (i = newfdp->fd_lastfile; i >= 0; i--, fpp--) { | |
2103 | if (*fpp != NULL && (*fpp)->f_type == DTYPE_KQUEUE) { | |
2104 | *fpp = NULL; | |
2105 | if (i < newfdp->fd_freefile) | |
2106 | newfdp->fd_freefile = i; | |
2107 | } | |
2108 | if (*fpp == NULL && i == newfdp->fd_lastfile && i > 0) | |
2109 | newfdp->fd_lastfile--; | |
2110 | } | |
2111 | newfdp->fd_knlist = NULL; | |
2112 | newfdp->fd_knlistsize = -1; | |
2113 | newfdp->fd_knhash = NULL; | |
2114 | newfdp->fd_knhashmask = 0; | |
2115 | } | |
1c79356b A |
2116 | fpp = newfdp->fd_ofiles; |
2117 | flags = newfdp->fd_ofileflags; | |
91447636 | 2118 | |
1c79356b | 2119 | for (i = newfdp->fd_lastfile; i-- >= 0; fpp++, flags++) |
91447636 A |
2120 | if ((ofp = *fpp) != NULL && !(*flags & UF_RESERVED)) { |
2121 | MALLOC_ZONE(fp, struct fileproc *, sizeof(struct fileproc), M_FILEPROC, M_WAITOK); | |
2122 | bzero(fp, sizeof(struct fileproc)); | |
2123 | fp->f_flags = ofp->f_flags; | |
2124 | //fp->f_iocount = ofp->f_iocount; | |
2125 | fp->f_iocount = 0; | |
2126 | fp->f_fglob = ofp->f_fglob; | |
2127 | (void)fg_ref(fp); | |
2128 | *fpp = fp; | |
1c79356b A |
2129 | } else { |
2130 | *fpp = NULL; | |
2131 | *flags = 0; | |
2132 | } | |
fa4905b1 | 2133 | } else |
1c79356b A |
2134 | (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE); |
2135 | ||
91447636 | 2136 | proc_fdunlock(p); |
1c79356b A |
2137 | return (newfdp); |
2138 | } | |
2139 | ||
2140 | /* | |
2141 | * Release a filedesc structure. | |
2142 | */ | |
2143 | void | |
2144 | fdfree(p) | |
2145 | struct proc *p; | |
2146 | { | |
fa4905b1 | 2147 | struct filedesc *fdp; |
91447636 | 2148 | struct fileproc *fp; |
fa4905b1 | 2149 | int i; |
91447636 A |
2150 | |
2151 | proc_fdlock(p); | |
1c79356b | 2152 | |
55e303ae | 2153 | /* Certain daemons might not have file descriptors */ |
91447636 | 2154 | fdp = p->p_fd; |
55e303ae | 2155 | |
91447636 A |
2156 | if ((fdp == NULL) || (--fdp->fd_refcnt > 0)) { |
2157 | proc_fdunlock(p); | |
1c79356b | 2158 | return; |
91447636 A |
2159 | } |
2160 | if (fdp->fd_refcnt == 0xffff) | |
2161 | panic("fdfree: bad fd_refcnt"); | |
55e303ae A |
2162 | |
2163 | /* Last reference: the structure can't change out from under us */ | |
91447636 A |
2164 | |
2165 | if (fdp->fd_nfiles > 0 && fdp->fd_ofiles) { | |
2166 | for (i = fdp->fd_lastfile; i >= 0; i--) { | |
55e303ae | 2167 | if ((fp = fdp->fd_ofiles[i]) != NULL) { |
91447636 A |
2168 | |
2169 | if (fdp->fd_ofileflags[i] & UF_RESERVED) | |
2170 | panic("fdfree: found fp with UF_RESERVED\n"); | |
2171 | ||
2172 | /* closef drops the iocount ... */ | |
2173 | if ((fp->f_flags & FP_INCHRREAD) != 0) | |
2174 | fp->f_iocount++; | |
2175 | fdp->fd_ofiles[i] = NULL; | |
2176 | fdp->fd_ofileflags[i] |= UF_RESERVED; | |
2177 | ||
55e303ae A |
2178 | if (i < fdp->fd_knlistsize) |
2179 | knote_fdclose(p, i); | |
91447636 A |
2180 | if (fp->f_flags & FP_WAITEVENT) |
2181 | (void)waitevent_close(p, fp); | |
2182 | (void) closef_locked(fp, fp->f_fglob, p); | |
2183 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
55e303ae | 2184 | } |
91447636 A |
2185 | } |
2186 | FREE_ZONE(fdp->fd_ofiles, fdp->fd_nfiles * OFILESIZE, M_OFILETABL); | |
2187 | fdp->fd_ofiles = NULL; | |
2188 | fdp->fd_nfiles = 0; | |
2189 | } | |
55e303ae | 2190 | |
91447636 A |
2191 | proc_fdunlock(p); |
2192 | ||
2193 | if (fdp->fd_cdir) | |
2194 | vnode_rele(fdp->fd_cdir); | |
2195 | if (fdp->fd_rdir) | |
2196 | vnode_rele(fdp->fd_rdir); | |
55e303ae | 2197 | |
91447636 A |
2198 | proc_fdlock(p); |
2199 | p->p_fd = NULL; | |
2200 | proc_fdunlock(p); | |
55e303ae A |
2201 | |
2202 | if (fdp->fd_knlist) | |
2203 | FREE(fdp->fd_knlist, M_KQUEUE); | |
2204 | if (fdp->fd_knhash) | |
2205 | FREE(fdp->fd_knhash, M_KQUEUE); | |
2206 | ||
1c79356b A |
2207 | FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC); |
2208 | } | |
2209 | ||
9bccf70c | 2210 | static int |
91447636 A |
2211 | closef_finish(fp, fg, p) |
2212 | struct fileproc *fp; | |
2213 | struct fileglob *fg; | |
2214 | struct proc *p; | |
9bccf70c A |
2215 | { |
2216 | struct vnode *vp; | |
2217 | struct flock lf; | |
2218 | int error; | |
91447636 | 2219 | struct vfs_context context; |
9bccf70c | 2220 | |
91447636 | 2221 | if ((fg->fg_flag & FHASLOCK) && fg->fg_type == DTYPE_VNODE) { |
9bccf70c A |
2222 | lf.l_whence = SEEK_SET; |
2223 | lf.l_start = 0; | |
2224 | lf.l_len = 0; | |
2225 | lf.l_type = F_UNLCK; | |
91447636 A |
2226 | vp = (struct vnode *)fg->fg_data; |
2227 | context.vc_proc = p; | |
2228 | context.vc_ucred = fg->fg_cred; | |
2229 | ||
2230 | (void) VNOP_ADVLOCK(vp, (caddr_t)fg, F_UNLCK, &lf, F_FLOCK, &context); | |
9bccf70c | 2231 | } |
91447636 A |
2232 | if (fg->fg_ops) |
2233 | error = fo_close(fg, p); | |
9bccf70c A |
2234 | else |
2235 | error = 0; | |
91447636 A |
2236 | |
2237 | if (((fp != (struct fileproc *)0) && ((fp->f_flags & FP_INCHRREAD) != 0))) { | |
2238 | proc_fdlock(p); | |
2239 | if ( ((fp->f_flags & FP_INCHRREAD) != 0) ) { | |
2240 | fileproc_drain(p, fp); | |
2241 | } | |
2242 | proc_fdunlock(p); | |
2243 | } | |
2244 | fg_free(fg); | |
2245 | ||
9bccf70c A |
2246 | return (error); |
2247 | } | |
2248 | ||
91447636 A |
2249 | int |
2250 | closef(fg, p) | |
2251 | struct fileglob *fg; | |
2252 | struct proc *p; | |
2253 | { | |
2254 | int error; | |
2255 | ||
2256 | proc_fdlock(p); | |
2257 | error = closef_locked((struct fileproc *)0, fg, p); | |
2258 | proc_fdunlock(p); | |
2259 | ||
2260 | return(error); | |
2261 | } | |
1c79356b A |
2262 | /* |
2263 | * Internal form of close. | |
2264 | * Decrement reference count on file structure. | |
2265 | * Note: p may be NULL when closing a file | |
2266 | * that was being passed in a message. | |
2267 | */ | |
2268 | int | |
91447636 A |
2269 | closef_locked(fp, fg, p) |
2270 | struct fileproc *fp; | |
2271 | struct fileglob *fg; | |
2272 | struct proc *p; | |
1c79356b A |
2273 | { |
2274 | struct vnode *vp; | |
2275 | struct flock lf; | |
91447636 | 2276 | struct vfs_context context; |
1c79356b A |
2277 | int error; |
2278 | ||
91447636 | 2279 | if (fg == NULL) { |
1c79356b | 2280 | return (0); |
91447636 | 2281 | } |
1c79356b A |
2282 | /* |
2283 | * POSIX record locking dictates that any close releases ALL | |
2284 | * locks owned by this process. This is handled by setting | |
2285 | * a flag in the unlock to free ONLY locks obeying POSIX | |
2286 | * semantics, and not to free BSD-style file locks. | |
2287 | * If the descriptor was in a message, POSIX-style locks | |
2288 | * aren't passed with the descriptor. | |
2289 | */ | |
b36670ce | 2290 | if (p && (p->p_ladvflag & P_LADVLOCK) && fg->fg_type == DTYPE_VNODE) { |
91447636 A |
2291 | proc_fdunlock(p); |
2292 | ||
1c79356b A |
2293 | lf.l_whence = SEEK_SET; |
2294 | lf.l_start = 0; | |
2295 | lf.l_len = 0; | |
2296 | lf.l_type = F_UNLCK; | |
91447636 A |
2297 | vp = (struct vnode *)fg->fg_data; |
2298 | ||
2299 | if ( (error = vnode_getwithref(vp)) == 0 ) { | |
2300 | context.vc_proc = p; | |
2301 | context.vc_ucred = fg->fg_cred; | |
2302 | (void) VNOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX, &context); | |
2303 | ||
2304 | (void)vnode_put(vp); | |
2305 | } | |
2306 | proc_fdlock(p); | |
1c79356b | 2307 | } |
91447636 A |
2308 | lck_mtx_lock(&fg->fg_lock); |
2309 | fg->fg_count--; | |
2310 | ||
2311 | if (fg->fg_count > 0) { | |
2312 | lck_mtx_unlock(&fg->fg_lock); | |
1c79356b | 2313 | return (0); |
91447636 A |
2314 | } |
2315 | if (fg->fg_count != 0) | |
2316 | panic("fg: being freed with bad fg_count (%d)", fg, fg->fg_count); | |
2317 | ||
2318 | if (fp && (fp->f_flags & FP_WRITTEN)) | |
2319 | fg->fg_flag |= FWASWRITTEN; | |
2320 | ||
2321 | fg->fg_lflags |= FG_TERM; | |
2322 | lck_mtx_unlock(&fg->fg_lock); | |
2323 | ||
2324 | proc_fdunlock(p); | |
2325 | error = closef_finish(fp, fg, p); | |
2326 | proc_fdlock(p); | |
2327 | ||
2328 | return(error); | |
2329 | } | |
2330 | ||
2331 | ||
2332 | extern int selwait; | |
2333 | void | |
2334 | fileproc_drain(struct proc *p, struct fileproc * fp) | |
2335 | { | |
2336 | fp->f_iocount-- ; /* (the one the close holds) */ | |
2337 | ||
2338 | while (fp->f_iocount) { | |
2339 | if (((fp->f_flags & FP_INSELECT)== FP_INSELECT)) { | |
2340 | wait_queue_wakeup_all((wait_queue_t)fp->f_waddr, &selwait, THREAD_INTERRUPTED); | |
2341 | } else { | |
2342 | if (fp->f_fglob->fg_ops->fo_drain) { | |
2343 | (*fp->f_fglob->fg_ops->fo_drain)(fp, p); | |
2344 | } | |
2345 | } | |
2346 | p->p_fpdrainwait = 1; | |
2347 | ||
2348 | msleep(&p->p_fpdrainwait, &p->p_fdmlock, PRIBIO, "fpdrain",0); | |
2349 | ||
2350 | //panic("successful wait after drain\n"); | |
2351 | } | |
2352 | } | |
2353 | ||
2354 | int | |
2355 | fp_free(struct proc * p, int fd, struct fileproc * fp) | |
2356 | { | |
2357 | proc_fdlock(p); | |
2358 | fdrelse(p, fd); | |
2359 | proc_fdunlock(p); | |
2360 | ||
2361 | fg_free(fp->f_fglob); | |
2362 | FREE_ZONE(fp, sizeof *fp, M_FILEPROC); | |
1c79356b A |
2363 | } |
2364 | ||
91447636 | 2365 | |
1c79356b A |
2366 | /* |
2367 | * Apply an advisory lock on a file descriptor. | |
2368 | * | |
2369 | * Just attempt to get a record lock of the requested type on | |
2370 | * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). | |
2371 | */ | |
1c79356b | 2372 | int |
91447636 | 2373 | flock(struct proc *p, register struct flock_args *uap, __unused register_t *retval) |
1c79356b A |
2374 | { |
2375 | int fd = uap->fd; | |
2376 | int how = uap->how; | |
91447636 | 2377 | struct fileproc *fp; |
1c79356b A |
2378 | struct vnode *vp; |
2379 | struct flock lf; | |
91447636 A |
2380 | struct vfs_context context; |
2381 | int error=0; | |
1c79356b | 2382 | |
55e303ae | 2383 | AUDIT_ARG(fd, uap->fd); |
91447636 A |
2384 | if ( (error = fp_getfvp(p, fd, &fp, &vp)) ) { |
2385 | return(error); | |
2386 | } | |
2387 | if ( (error = vnode_getwithref(vp)) ) { | |
2388 | goto out1; | |
2389 | } | |
55e303ae | 2390 | AUDIT_ARG(vnpath, vp, ARG_VNODE1); |
91447636 A |
2391 | |
2392 | context.vc_proc = p; | |
2393 | context.vc_ucred = fp->f_cred; | |
2394 | ||
1c79356b A |
2395 | lf.l_whence = SEEK_SET; |
2396 | lf.l_start = 0; | |
2397 | lf.l_len = 0; | |
2398 | if (how & LOCK_UN) { | |
2399 | lf.l_type = F_UNLCK; | |
2400 | fp->f_flag &= ~FHASLOCK; | |
91447636 A |
2401 | error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_UNLCK, &lf, F_FLOCK, &context); |
2402 | goto out; | |
1c79356b A |
2403 | } |
2404 | if (how & LOCK_EX) | |
2405 | lf.l_type = F_WRLCK; | |
2406 | else if (how & LOCK_SH) | |
2407 | lf.l_type = F_RDLCK; | |
91447636 A |
2408 | else { |
2409 | error = EBADF; | |
2410 | goto out; | |
2411 | } | |
1c79356b | 2412 | fp->f_flag |= FHASLOCK; |
91447636 A |
2413 | if (how & LOCK_NB) { |
2414 | error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, F_FLOCK, &context); | |
2415 | goto out; | |
2416 | } | |
2417 | error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, F_FLOCK|F_WAIT, &context); | |
2418 | out: | |
2419 | (void)vnode_put(vp); | |
2420 | out1: | |
2421 | fp_drop(p, fd, fp, 0); | |
2422 | return(error); | |
2423 | ||
1c79356b A |
2424 | } |
2425 | ||
2426 | /* | |
2427 | * File Descriptor pseudo-device driver (/dev/fd/). | |
2428 | * | |
2429 | * Opening minor device N dup()s the file (if any) connected to file | |
2430 | * descriptor N belonging to the calling process. Note that this driver | |
2431 | * consists of only the ``open()'' routine, because all subsequent | |
2432 | * references to this file will be direct to the other driver. | |
2433 | */ | |
1c79356b | 2434 | int |
91447636 | 2435 | fdopen(dev_t dev, __unused int mode, __unused int type, struct proc *p) |
1c79356b A |
2436 | { |
2437 | ||
2438 | /* | |
2439 | * XXX Kludge: set curproc->p_dupfd to contain the value of the | |
2440 | * the file descriptor being sought for duplication. The error | |
2441 | * return ensures that the vnode for this device will be released | |
2442 | * by vn_open. Open will detect this special error and take the | |
91447636 | 2443 | * actions in dupfdopen below. Other callers of vn_open or vnop_open |
1c79356b A |
2444 | * will simply report the error. |
2445 | */ | |
2446 | p->p_dupfd = minor(dev); | |
2447 | return (ENODEV); | |
2448 | } | |
2449 | ||
2450 | /* | |
2451 | * Duplicate the specified descriptor to a free descriptor. | |
2452 | */ | |
2453 | int | |
2454 | dupfdopen(fdp, indx, dfd, mode, error) | |
2455 | register struct filedesc *fdp; | |
2456 | register int indx, dfd; | |
2457 | int mode; | |
2458 | int error; | |
2459 | { | |
91447636 A |
2460 | struct fileproc *wfp; |
2461 | struct fileproc *fp; | |
2462 | struct proc * p = current_proc(); | |
1c79356b A |
2463 | |
2464 | /* | |
2465 | * If the to-be-dup'd fd number is greater than the allowed number | |
2466 | * of file descriptors, or the fd to be dup'd has already been | |
2467 | * closed, reject. Note, check for new == old is necessary as | |
2468 | * falloc could allocate an already closed to-be-dup'd descriptor | |
2469 | * as the new descriptor. | |
2470 | */ | |
91447636 A |
2471 | proc_fdlock(p); |
2472 | ||
1c79356b | 2473 | fp = fdp->fd_ofiles[indx]; |
91447636 | 2474 | if (dfd < 0 || dfd >= fdp->fd_nfiles || |
1c79356b | 2475 | (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp || |
91447636 | 2476 | (fdp->fd_ofileflags[dfd] & UF_RESERVED)) { |
1c79356b | 2477 | |
91447636 A |
2478 | proc_fdunlock(p); |
2479 | return (EBADF); | |
2480 | } | |
1c79356b A |
2481 | /* |
2482 | * There are two cases of interest here. | |
2483 | * | |
2484 | * For ENODEV simply dup (dfd) to file descriptor | |
2485 | * (indx) and return. | |
2486 | * | |
2487 | * For ENXIO steal away the file structure from (dfd) and | |
2488 | * store it in (indx). (dfd) is effectively closed by | |
2489 | * this operation. | |
2490 | * | |
2491 | * Any other error code is just returned. | |
2492 | */ | |
2493 | switch (error) { | |
2494 | case ENODEV: | |
2495 | /* | |
2496 | * Check that the mode the file is being opened for is a | |
2497 | * subset of the mode of the existing descriptor. | |
2498 | */ | |
91447636 A |
2499 | if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) { |
2500 | proc_fdunlock(p); | |
1c79356b | 2501 | return (EACCES); |
91447636 | 2502 | } |
1c79356b | 2503 | if (indx > fdp->fd_lastfile) |
91447636 A |
2504 | fdp->fd_lastfile = indx; |
2505 | (void)fg_ref(wfp); | |
2506 | ||
2507 | if (fp->f_fglob) | |
2508 | fg_free(fp->f_fglob); | |
2509 | fp->f_fglob = wfp->f_fglob; | |
2510 | ||
1c79356b | 2511 | fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; |
91447636 A |
2512 | |
2513 | proc_fdunlock(p); | |
1c79356b A |
2514 | return (0); |
2515 | ||
2516 | case ENXIO: | |
2517 | /* | |
2518 | * Steal away the file pointer from dfd, and stuff it into indx. | |
2519 | */ | |
2520 | if (indx > fdp->fd_lastfile) | |
91447636 A |
2521 | fdp->fd_lastfile = indx; |
2522 | ||
2523 | if (fp->f_fglob) | |
2524 | fg_free(fp->f_fglob); | |
2525 | fp->f_fglob = wfp->f_fglob; | |
2526 | ||
1c79356b A |
2527 | fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; |
2528 | _fdrelse(fdp, dfd); | |
91447636 A |
2529 | |
2530 | proc_fdunlock(p); | |
2531 | ||
2532 | FREE_ZONE(wfp, sizeof *fp, M_FILEPROC); | |
2533 | ||
1c79356b A |
2534 | return (0); |
2535 | ||
2536 | default: | |
91447636 | 2537 | proc_fdunlock(p); |
1c79356b A |
2538 | return (error); |
2539 | } | |
2540 | /* NOTREACHED */ | |
2541 | } | |
2542 | ||
91447636 A |
2543 | void |
2544 | fg_ref(struct fileproc * fp) | |
1c79356b | 2545 | { |
91447636 A |
2546 | struct fileglob *fg; |
2547 | ||
2548 | fg = fp->f_fglob; | |
2549 | ||
2550 | lck_mtx_lock(&fg->fg_lock); | |
2551 | fg->fg_count++; | |
2552 | lck_mtx_unlock(&fg->fg_lock); | |
1c79356b A |
2553 | } |
2554 | ||
91447636 A |
2555 | void |
2556 | fg_drop(struct fileproc * fp) | |
1c79356b | 2557 | { |
91447636 A |
2558 | struct fileglob *fg; |
2559 | ||
2560 | fg = fp->f_fglob; | |
2561 | lck_mtx_lock(&fg->fg_lock); | |
2562 | fg->fg_count--; | |
2563 | lck_mtx_unlock(&fg->fg_lock); | |
1c79356b A |
2564 | } |
2565 | ||
9bccf70c | 2566 | |
91447636 A |
2567 | void |
2568 | fg_insertuipc(struct fileglob * fg) | |
9bccf70c | 2569 | { |
91447636 | 2570 | int insertque = 0; |
9bccf70c | 2571 | |
91447636 A |
2572 | lck_mtx_lock(&fg->fg_lock); |
2573 | ||
2574 | while (fg->fg_lflags & FG_RMMSGQ) { | |
2575 | fg->fg_lflags |= FG_WRMMSGQ; | |
2576 | msleep(&fg->fg_lflags, &fg->fg_lock, 0, "fg_insertuipc", 0); | |
2577 | } | |
9bccf70c | 2578 | |
91447636 A |
2579 | fg->fg_count++; |
2580 | fg->fg_msgcount++; | |
2581 | if (fg->fg_msgcount == 1) { | |
2582 | fg->fg_lflags |= FG_INSMSGQ; | |
2583 | insertque=1; | |
9bccf70c | 2584 | } |
91447636 A |
2585 | lck_mtx_unlock(&fg->fg_lock); |
2586 | ||
2587 | if (insertque) { | |
2588 | lck_mtx_lock(uipc_lock); | |
2589 | LIST_INSERT_HEAD(&fmsghead, fg, f_msglist); | |
2590 | lck_mtx_unlock(uipc_lock); | |
2591 | lck_mtx_lock(&fg->fg_lock); | |
2592 | fg->fg_lflags &= ~FG_INSMSGQ; | |
2593 | if (fg->fg_lflags & FG_WINSMSGQ) { | |
2594 | fg->fg_lflags &= ~FG_WINSMSGQ; | |
2595 | wakeup(&fg->fg_lflags); | |
2596 | } | |
2597 | lck_mtx_unlock(&fg->fg_lock); | |
2598 | } | |
2599 | ||
2600 | } | |
9bccf70c | 2601 | |
91447636 A |
2602 | void |
2603 | fg_removeuipc(struct fileglob * fg) | |
2604 | { | |
2605 | int removeque = 0; | |
2606 | ||
2607 | lck_mtx_lock(&fg->fg_lock); | |
2608 | while (fg->fg_lflags & FG_INSMSGQ) { | |
2609 | fg->fg_lflags |= FG_WINSMSGQ; | |
2610 | msleep(&fg->fg_lflags, &fg->fg_lock, 0, "fg_removeuipc", 0); | |
2611 | } | |
2612 | fg->fg_msgcount--; | |
2613 | if (fg->fg_msgcount == 0) { | |
2614 | fg->fg_lflags |= FG_RMMSGQ; | |
2615 | removeque=1; | |
9bccf70c | 2616 | } |
91447636 A |
2617 | lck_mtx_unlock(&fg->fg_lock); |
2618 | ||
2619 | if (removeque) { | |
2620 | lck_mtx_lock(uipc_lock); | |
2621 | LIST_REMOVE(fg, f_msglist); | |
2622 | lck_mtx_unlock(uipc_lock); | |
2623 | lck_mtx_lock(&fg->fg_lock); | |
2624 | fg->fg_lflags &= ~FG_RMMSGQ; | |
2625 | if (fg->fg_lflags & FG_WRMMSGQ) { | |
2626 | fg->fg_lflags &= ~FG_WRMMSGQ; | |
2627 | wakeup(&fg->fg_lflags); | |
2628 | } | |
2629 | lck_mtx_unlock(&fg->fg_lock); | |
2630 | } | |
2631 | } | |
2632 | ||
2633 | ||
2634 | int | |
2635 | fo_read(struct fileproc *fp, struct uio *uio, kauth_cred_t cred, int flags, struct proc *p) | |
2636 | { | |
2637 | return ((*fp->f_ops->fo_read)(fp, uio, cred, flags, p)); | |
2638 | } | |
2639 | ||
2640 | int | |
2641 | fo_write(struct fileproc *fp, struct uio *uio, kauth_cred_t cred, int flags, struct proc *p) | |
2642 | { | |
2643 | return((*fp->f_ops->fo_write)(fp, uio, cred, flags, p)); | |
2644 | } | |
2645 | ||
2646 | int | |
2647 | fo_ioctl(struct fileproc *fp, u_long com, caddr_t data, struct proc *p) | |
2648 | { | |
2649 | int error; | |
2650 | ||
2651 | proc_fdunlock(p); | |
2652 | error = (*fp->f_ops->fo_ioctl)(fp, com, data, p); | |
2653 | proc_fdlock(p); | |
2654 | return(error); | |
2655 | } | |
2656 | ||
2657 | int | |
2658 | fo_select(struct fileproc *fp, int which, void *wql, struct proc *p) | |
2659 | { | |
2660 | return((*fp->f_ops->fo_select)(fp, which, wql, p)); | |
2661 | } | |
2662 | ||
2663 | int | |
2664 | fo_close(struct fileglob *fg, struct proc *p) | |
2665 | { | |
2666 | return((*fg->fg_ops->fo_close)(fg, p)); | |
9bccf70c A |
2667 | } |
2668 | ||
1c79356b | 2669 | int |
91447636 | 2670 | fo_kqfilter(struct fileproc *fp, struct knote *kn, struct proc *p) |
1c79356b | 2671 | { |
91447636 | 2672 | return ((*fp->f_ops->fo_kqfilter)(fp, kn, p)); |
1c79356b A |
2673 | } |
2674 |