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