]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5d5c5d0d A |
2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
3 | * | |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
1c79356b | 5 | * |
8ad349bb 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. The rights granted to you under the | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
1c79356b A |
29 | */ |
30 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
31 | /* | |
32 | * Copyright (c) 1992, 1993 | |
33 | * The Regents of the University of California. All rights reserved. | |
34 | * | |
35 | * This code is derived from software donated to Berkeley by | |
36 | * Jan-Simon Pendry. | |
37 | * | |
38 | * Redistribution and use in source and binary forms, with or without | |
39 | * modification, are permitted provided that the following conditions | |
40 | * are met: | |
41 | * 1. Redistributions of source code must retain the above copyright | |
42 | * notice, this list of conditions and the following disclaimer. | |
43 | * 2. Redistributions in binary form must reproduce the above copyright | |
44 | * notice, this list of conditions and the following disclaimer in the | |
45 | * documentation and/or other materials provided with the distribution. | |
46 | * 3. All advertising materials mentioning features or use of this software | |
47 | * must display the following acknowledgement: | |
48 | * This product includes software developed by the University of | |
49 | * California, Berkeley and its contributors. | |
50 | * 4. Neither the name of the University nor the names of its contributors | |
51 | * may be used to endorse or promote products derived from this software | |
52 | * without specific prior written permission. | |
53 | * | |
54 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
55 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
56 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
57 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
58 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
59 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
60 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
61 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
62 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
63 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
64 | * SUCH DAMAGE. | |
65 | * | |
66 | * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95 | |
67 | * | |
68 | */ | |
69 | ||
70 | /* | |
71 | * /dev/fd Filesystem | |
72 | */ | |
73 | ||
74 | #include <sys/param.h> | |
75 | #include <sys/systm.h> | |
76 | #include <sys/types.h> | |
77 | #include <sys/time.h> | |
91447636 | 78 | #include <sys/proc_internal.h> |
1c79356b A |
79 | #include <sys/kernel.h> /* boottime */ |
80 | #include <sys/resourcevar.h> | |
81 | #include <sys/filedesc.h> | |
91447636 A |
82 | #include <sys/kauth.h> |
83 | #include <sys/vnode_internal.h> | |
1c79356b | 84 | #include <sys/malloc.h> |
91447636 | 85 | #include <sys/file_internal.h> |
1c79356b | 86 | #include <sys/stat.h> |
91447636 | 87 | #include <sys/mount_internal.h> |
1c79356b | 88 | #include <sys/namei.h> |
1c79356b A |
89 | #include <sys/dirent.h> |
90 | #include <sys/ubc.h> | |
91447636 A |
91 | #include <sys/socketvar.h> |
92 | #include <sys/pipe.h> | |
93 | #include <sys/uio_internal.h> | |
1c79356b A |
94 | #include <miscfs/fdesc/fdesc.h> |
95 | #include <vfs/vfs_support.h> | |
91447636 | 96 | #include <pexpert/pexpert.h> |
1c79356b | 97 | |
1c79356b A |
98 | #define FDL_WANT 0x01 |
99 | #define FDL_LOCKED 0x02 | |
100 | static int fdcache_lock; | |
101 | ||
1c79356b A |
102 | |
103 | #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) | |
104 | FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 | |
105 | #endif | |
106 | ||
9bccf70c | 107 | #define NFDCACHE 3 |
1c79356b A |
108 | |
109 | #define FD_NHASH(ix) \ | |
110 | (&fdhashtbl[(ix) & fdhash]) | |
111 | LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; | |
112 | u_long fdhash; | |
113 | ||
91447636 A |
114 | static int fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context); |
115 | ||
116 | ||
1c79356b A |
117 | /* |
118 | * Initialise cache headers | |
119 | */ | |
91447636 A |
120 | int |
121 | fdesc_init(__unused struct vfsconf *vfsp) | |
1c79356b A |
122 | { |
123 | ||
1c79356b | 124 | fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); |
91447636 A |
125 | |
126 | return( 0 ); | |
1c79356b A |
127 | } |
128 | ||
129 | int | |
91447636 | 130 | fdesc_allocvp(ftype, ix, mp, vpp, vtype) |
1c79356b A |
131 | fdntype ftype; |
132 | int ix; | |
133 | struct mount *mp; | |
134 | struct vnode **vpp; | |
91447636 | 135 | enum vtype vtype; |
1c79356b | 136 | { |
1c79356b A |
137 | struct fdhashhead *fc; |
138 | struct fdescnode *fd; | |
139 | int error = 0; | |
91447636 A |
140 | int vid = 0; |
141 | struct vnode_fsparam vfsp; | |
1c79356b A |
142 | |
143 | fc = FD_NHASH(ix); | |
144 | loop: | |
145 | for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { | |
91447636 A |
146 | if (fd->fd_ix == ix && vnode_mount(fd->fd_vnode) == mp) { |
147 | /* | |
148 | * doing a vnode_getwithvid isn't technically | |
149 | * necessary since fdesc is an unsafe filesystem | |
150 | * and we're running behind a funnel at this point | |
151 | * however, vnode_get always succeeds, which isn't | |
152 | * what we want if this vnode is in the process of | |
153 | * being terminated | |
154 | */ | |
155 | vid = vnode_vid(fd->fd_vnode); | |
156 | ||
157 | if (vnode_getwithvid(fd->fd_vnode, vid)) | |
1c79356b A |
158 | goto loop; |
159 | *vpp = fd->fd_vnode; | |
91447636 A |
160 | (*vpp)->v_type = vtype; |
161 | ||
1c79356b A |
162 | return (error); |
163 | } | |
164 | } | |
165 | ||
166 | /* | |
167 | * otherwise lock the array while we call getnewvnode | |
168 | * since that can block. | |
169 | */ | |
170 | if (fdcache_lock & FDL_LOCKED) { | |
171 | fdcache_lock |= FDL_WANT; | |
172 | sleep((caddr_t) &fdcache_lock, PINOD); | |
173 | goto loop; | |
174 | } | |
175 | fdcache_lock |= FDL_LOCKED; | |
176 | ||
177 | MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); | |
91447636 A |
178 | |
179 | vfsp.vnfs_mp = mp; | |
180 | vfsp.vnfs_vtype = vtype; | |
181 | vfsp.vnfs_str = "fdesc"; | |
182 | vfsp.vnfs_dvp = 0; | |
183 | vfsp.vnfs_fsnode = fd; | |
184 | vfsp.vnfs_cnp = 0; | |
185 | vfsp.vnfs_vops = fdesc_vnodeop_p; | |
186 | vfsp.vnfs_rdev = 0; | |
187 | vfsp.vnfs_filesize = 0; | |
188 | vfsp.vnfs_flags = VNFS_NOCACHE | VNFS_CANTCACHE; | |
189 | vfsp.vnfs_marksystem = 0; | |
190 | if (ftype == Froot) | |
191 | vfsp.vnfs_markroot = 1; | |
192 | else | |
193 | vfsp.vnfs_markroot = 0; | |
194 | ||
195 | error = vnode_create(VNCREATE_FLAVOR, VCREATESIZE, &vfsp, vpp); | |
1c79356b A |
196 | if (error) { |
197 | FREE(fd, M_TEMP); | |
198 | goto out; | |
199 | } | |
91447636 | 200 | (*vpp)->v_tag = VT_FDESC; |
1c79356b A |
201 | fd->fd_vnode = *vpp; |
202 | fd->fd_type = ftype; | |
203 | fd->fd_fd = -1; | |
204 | fd->fd_link = 0; | |
205 | fd->fd_ix = ix; | |
206 | LIST_INSERT_HEAD(fc, fd, fd_hash); | |
207 | ||
208 | out: | |
209 | fdcache_lock &= ~FDL_LOCKED; | |
210 | ||
211 | if (fdcache_lock & FDL_WANT) { | |
212 | fdcache_lock &= ~FDL_WANT; | |
213 | wakeup((caddr_t) &fdcache_lock); | |
214 | } | |
215 | ||
216 | return (error); | |
217 | } | |
218 | ||
219 | /* | |
220 | * vp is the current namei directory | |
221 | * ndp is the name to locate in that directory... | |
222 | */ | |
223 | int | |
224 | fdesc_lookup(ap) | |
91447636 | 225 | struct vnop_lookup_args /* { |
1c79356b A |
226 | struct vnode * a_dvp; |
227 | struct vnode ** a_vpp; | |
228 | struct componentname * a_cnp; | |
91447636 | 229 | vfs_context_t a_context; |
1c79356b A |
230 | } */ *ap; |
231 | { | |
232 | struct vnode **vpp = ap->a_vpp; | |
233 | struct vnode *dvp = ap->a_dvp; | |
234 | struct componentname *cnp = ap->a_cnp; | |
235 | char *pname = cnp->cn_nameptr; | |
91447636 A |
236 | struct proc *p = vfs_context_proc(ap->a_context); |
237 | int numfiles = p->p_fd->fd_nfiles; | |
238 | int fd; | |
1c79356b A |
239 | int error; |
240 | struct vnode *fvp; | |
241 | char *ln; | |
242 | ||
1c79356b A |
243 | if (cnp->cn_namelen == 1 && *pname == '.') { |
244 | *vpp = dvp; | |
91447636 A |
245 | |
246 | if ( (error = vnode_get(dvp)) ) { | |
247 | return(error); | |
248 | } | |
1c79356b A |
249 | return (0); |
250 | } | |
251 | ||
252 | switch (VTOFDESC(dvp)->fd_type) { | |
253 | default: | |
254 | case Flink: | |
255 | case Fdesc: | |
91447636 | 256 | /* should never happen */ |
1c79356b A |
257 | error = ENOTDIR; |
258 | goto bad; | |
259 | ||
260 | case Froot: | |
261 | if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { | |
91447636 | 262 | error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp, VDIR); |
1c79356b A |
263 | if (error) |
264 | goto bad; | |
265 | *vpp = fvp; | |
1c79356b A |
266 | return (0); |
267 | } | |
268 | ||
91447636 | 269 | ln = NULL; |
1c79356b A |
270 | switch (cnp->cn_namelen) { |
271 | case 5: | |
272 | if (bcmp(pname, "stdin", 5) == 0) { | |
273 | ln = "fd/0"; | |
274 | fd = FD_STDIN; | |
275 | } | |
276 | break; | |
277 | case 6: | |
278 | if (bcmp(pname, "stdout", 6) == 0) { | |
279 | ln = "fd/1"; | |
280 | fd = FD_STDOUT; | |
281 | } else | |
282 | if (bcmp(pname, "stderr", 6) == 0) { | |
283 | ln = "fd/2"; | |
284 | fd = FD_STDERR; | |
285 | } | |
286 | break; | |
287 | } | |
288 | ||
289 | if (ln) { | |
91447636 | 290 | error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp, VLNK); |
1c79356b A |
291 | if (error) |
292 | goto bad; | |
293 | VTOFDESC(fvp)->fd_link = ln; | |
294 | *vpp = fvp; | |
1c79356b A |
295 | return (0); |
296 | } else { | |
297 | error = ENOENT; | |
298 | goto bad; | |
299 | } | |
300 | ||
301 | /* FALL THROUGH */ | |
302 | ||
303 | case Fdevfd: | |
304 | if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { | |
91447636 | 305 | if ((error = fdesc_root(dvp->v_mount, vpp, ap->a_context))) |
1c79356b A |
306 | goto bad; |
307 | return (0); | |
308 | } | |
309 | ||
310 | fd = 0; | |
311 | while (*pname >= '0' && *pname <= '9') { | |
312 | fd = 10 * fd + *pname++ - '0'; | |
91447636 | 313 | if (fd >= numfiles) |
1c79356b A |
314 | break; |
315 | } | |
316 | ||
317 | if (*pname != '\0') { | |
318 | error = ENOENT; | |
319 | goto bad; | |
320 | } | |
321 | ||
91447636 | 322 | if (fd < 0 || fd >= numfiles || |
1c79356b A |
323 | *fdfile(p, fd) == NULL || |
324 | (*fdflags(p, fd) & UF_RESERVED)) { | |
325 | error = EBADF; | |
326 | goto bad; | |
327 | } | |
328 | ||
91447636 | 329 | error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp, VNON); |
1c79356b A |
330 | if (error) |
331 | goto bad; | |
332 | VTOFDESC(fvp)->fd_fd = fd; | |
1c79356b A |
333 | *vpp = fvp; |
334 | return (0); | |
335 | } | |
336 | ||
337 | bad:; | |
1c79356b A |
338 | *vpp = NULL; |
339 | return (error); | |
340 | } | |
341 | ||
342 | int | |
343 | fdesc_open(ap) | |
91447636 | 344 | struct vnop_open_args /* { |
1c79356b A |
345 | struct vnode *a_vp; |
346 | int a_mode; | |
91447636 | 347 | vfs_context_t a_context; |
1c79356b A |
348 | } */ *ap; |
349 | { | |
350 | struct vnode *vp = ap->a_vp; | |
91447636 | 351 | struct proc *p = vfs_context_proc(ap->a_context); |
1c79356b A |
352 | int error = 0; |
353 | ||
354 | switch (VTOFDESC(vp)->fd_type) { | |
355 | case Fdesc: | |
356 | /* | |
357 | * XXX Kludge: set p->p_dupfd to contain the value of the | |
358 | * the file descriptor being sought for duplication. The error | |
359 | * return ensures that the vnode for this device will be | |
360 | * released by vn_open. Open will detect this special error and | |
361 | * take the actions in dupfdopen. Other callers of vn_open or | |
91447636 | 362 | * vnop_open will simply report the error. |
1c79356b | 363 | */ |
91447636 | 364 | p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ |
1c79356b A |
365 | error = ENODEV; |
366 | break; | |
367 | ||
1c79356b A |
368 | } |
369 | ||
370 | return (error); | |
371 | } | |
372 | ||
373 | static int | |
91447636 | 374 | fdesc_attr(int fd, struct vnode_attr *vap, vfs_context_t a_context) |
1c79356b | 375 | { |
91447636 A |
376 | struct fileproc *fp; |
377 | struct proc *p = vfs_context_proc(a_context); | |
1c79356b A |
378 | struct stat stb; |
379 | int error; | |
380 | ||
91447636 | 381 | if ((error = fp_lookup(p, fd, &fp, 0))) |
1c79356b | 382 | return (error); |
91447636 | 383 | switch (fp->f_fglob->fg_type) { |
1c79356b | 384 | case DTYPE_VNODE: |
91447636 A |
385 | if(error = vnode_getwithref((struct vnode *) fp->f_fglob->fg_data)) { |
386 | break; | |
387 | } | |
388 | if ((error = vnode_authorize((struct vnode *)fp->f_fglob->fg_data, | |
389 | NULL, | |
390 | KAUTH_VNODE_READ_ATTRIBUTES | KAUTH_VNODE_READ_SECURITY, | |
391 | a_context)) == 0) | |
392 | error = vnode_getattr((struct vnode *)fp->f_fglob->fg_data, vap, a_context); | |
1c79356b A |
393 | if (error == 0 && vap->va_type == VDIR) { |
394 | /* | |
395 | * directories can cause loops in the namespace, | |
396 | * so turn off the 'x' bits to avoid trouble. | |
91447636 A |
397 | * |
398 | * XXX ACLs break this, of course | |
1c79356b A |
399 | */ |
400 | vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6)); | |
401 | } | |
91447636 | 402 | (void)vnode_put((struct vnode *) fp->f_fglob->fg_data); |
1c79356b A |
403 | break; |
404 | ||
405 | case DTYPE_SOCKET: | |
91447636 A |
406 | case DTYPE_PIPE: |
407 | if (fp->f_fglob->fg_type == DTYPE_SOCKET) | |
408 | error = soo_stat((struct socket *)fp->f_fglob->fg_data, &stb); | |
409 | else | |
410 | error = pipe_stat((struct socket *)fp->f_fglob->fg_data, &stb); | |
411 | ||
1c79356b | 412 | if (error == 0) { |
91447636 A |
413 | if (fp->f_fglob->fg_type == DTYPE_SOCKET) |
414 | VATTR_RETURN(vap, va_type, VSOCK); | |
415 | else | |
416 | VATTR_RETURN(vap, va_type, VFIFO); | |
417 | ||
418 | VATTR_RETURN(vap, va_mode, stb.st_mode); | |
419 | VATTR_RETURN(vap, va_nlink, stb.st_nlink); | |
420 | VATTR_RETURN(vap, va_uid, stb.st_uid); | |
421 | VATTR_RETURN(vap, va_gid, stb.st_gid); | |
422 | VATTR_RETURN(vap, va_fsid, stb.st_dev); | |
423 | VATTR_RETURN(vap, va_fileid, stb.st_ino); | |
424 | VATTR_RETURN(vap, va_data_size, stb.st_size); | |
425 | VATTR_RETURN(vap, va_access_time, stb.st_atimespec); | |
426 | VATTR_RETURN(vap, va_modify_time, stb.st_mtimespec); | |
427 | VATTR_RETURN(vap, va_change_time, stb.st_ctimespec); | |
428 | VATTR_RETURN(vap, va_gen, stb.st_gen); | |
429 | VATTR_RETURN(vap, va_flags, stb.st_flags); | |
430 | VATTR_RETURN(vap, va_rdev, stb.st_rdev); | |
431 | VATTR_RETURN(vap, va_total_alloc, stb.st_blocks * stb.st_blksize); | |
432 | VATTR_RETURN(vap, va_acl, NULL); | |
1c79356b A |
433 | } |
434 | break; | |
435 | ||
436 | default: | |
91447636 | 437 | error = EBADF; |
1c79356b A |
438 | } |
439 | ||
91447636 | 440 | fp_drop(p, fd, fp, 0); |
1c79356b A |
441 | return (error); |
442 | } | |
443 | ||
444 | int | |
445 | fdesc_getattr(ap) | |
91447636 | 446 | struct vnop_getattr_args /* { |
1c79356b | 447 | struct vnode *a_vp; |
91447636 A |
448 | struct vnode_attr *a_vap; |
449 | vfs_context_t a_context; | |
1c79356b A |
450 | } */ *ap; |
451 | { | |
452 | struct vnode *vp = ap->a_vp; | |
91447636 | 453 | struct vnode_attr *vap = ap->a_vap; |
1c79356b A |
454 | unsigned fd; |
455 | int error = 0; | |
91447636 | 456 | struct timespec ts; |
1c79356b A |
457 | |
458 | switch (VTOFDESC(vp)->fd_type) { | |
459 | case Froot: | |
460 | case Fdevfd: | |
461 | case Flink: | |
91447636 A |
462 | VATTR_RETURN(vap, va_fileid, VTOFDESC(vp)->fd_ix); |
463 | VATTR_RETURN(vap, va_uid, 0); | |
464 | VATTR_RETURN(vap, va_gid, 0); | |
465 | VATTR_RETURN(vap, va_fsid, vp->v_mount->mnt_vfsstat.f_fsid.val[0]); | |
466 | VATTR_RETURN(vap, va_iosize, DEV_BSIZE); | |
467 | ts.tv_sec = boottime_sec(); | |
468 | ts.tv_nsec = 0; | |
469 | VATTR_RETURN(vap, va_access_time, ts); | |
470 | VATTR_RETURN(vap, va_modify_time, ts); | |
471 | VATTR_RETURN(vap, va_change_time, ts); | |
472 | VATTR_RETURN(vap, va_gen, 0); | |
473 | VATTR_RETURN(vap, va_flags, 0); | |
474 | VATTR_RETURN(vap, va_rdev, 0); | |
475 | VATTR_RETURN(vap, va_acl, NULL); | |
1c79356b A |
476 | |
477 | switch (VTOFDESC(vp)->fd_type) { | |
478 | case Flink: | |
91447636 A |
479 | VATTR_RETURN(vap, va_mode, S_IRUSR|S_IRGRP|S_IROTH); |
480 | VATTR_RETURN(vap, va_type, VLNK); /* not strictly required */ | |
481 | VATTR_RETURN(vap, va_nlink, 1); | |
482 | VATTR_RETURN(vap, va_data_size, strlen(VTOFDESC(vp)->fd_link)); | |
1c79356b A |
483 | break; |
484 | ||
1c79356b | 485 | default: |
91447636 A |
486 | VATTR_RETURN(vap, va_mode, S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); |
487 | VATTR_RETURN(vap, va_type, VDIR); | |
488 | VATTR_RETURN(vap, va_nlink, 2); | |
489 | VATTR_RETURN(vap, va_data_size, DEV_BSIZE); | |
1c79356b A |
490 | break; |
491 | } | |
492 | break; | |
493 | ||
494 | case Fdesc: | |
495 | fd = VTOFDESC(vp)->fd_fd; | |
91447636 | 496 | error = fdesc_attr(fd, vap, ap->a_context); |
1c79356b A |
497 | break; |
498 | ||
499 | default: | |
9bccf70c | 500 | return (EBADF); |
1c79356b A |
501 | break; |
502 | } | |
91447636 | 503 | |
1c79356b A |
504 | if (error == 0) { |
505 | vp->v_type = vap->va_type; | |
506 | } | |
507 | ||
508 | return (error); | |
509 | } | |
510 | ||
511 | int | |
512 | fdesc_setattr(ap) | |
91447636 | 513 | struct vnop_setattr_args /* { |
1c79356b | 514 | struct vnode *a_vp; |
91447636 A |
515 | struct vnode_attr *a_vap; |
516 | vfs_context_t a_context; | |
1c79356b A |
517 | } */ *ap; |
518 | { | |
91447636 | 519 | struct fileproc *fp; |
1c79356b A |
520 | unsigned fd; |
521 | int error; | |
91447636 | 522 | struct proc * p = vfs_context_proc(ap->a_context); |
1c79356b A |
523 | |
524 | /* | |
525 | * Can't mess with the root vnode | |
526 | */ | |
527 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
528 | case Fdesc: | |
529 | break; | |
530 | ||
1c79356b A |
531 | default: |
532 | return (EACCES); | |
533 | } | |
534 | ||
535 | fd = VTOFDESC(ap->a_vp)->fd_fd; | |
91447636 | 536 | if ((error = fp_lookup(vfs_context_proc(ap->a_context), fd, &fp, 0))) |
1c79356b A |
537 | return (error); |
538 | ||
539 | /* | |
540 | * Can setattr the underlying vnode, but not sockets! | |
541 | */ | |
91447636 | 542 | switch (fp->f_fglob->fg_type) { |
1c79356b | 543 | case DTYPE_VNODE: |
91447636 A |
544 | { |
545 | if ((error = vnode_getwithref((struct vnode *) fp->f_fglob->fg_data)) != 0) | |
546 | break; | |
547 | error = vnode_setattr((struct vnode *) fp->f_fglob->fg_data, ap->a_vap, ap->a_context); | |
548 | (void)vnode_put((struct vnode *) fp->f_fglob->fg_data); | |
1c79356b | 549 | break; |
91447636 | 550 | } |
1c79356b A |
551 | |
552 | case DTYPE_SOCKET: | |
91447636 | 553 | case DTYPE_PIPE: |
1c79356b A |
554 | error = 0; |
555 | break; | |
556 | ||
557 | default: | |
91447636 | 558 | kprintf("fp->f_fglob->fg_type = %d\n", fp->f_fglob->fg_type); |
1c79356b A |
559 | error = EBADF; |
560 | break; | |
561 | } | |
562 | ||
91447636 | 563 | fp_drop(p, fd, fp, 0); |
1c79356b A |
564 | return (error); |
565 | } | |
566 | ||
567 | #define UIO_MX 16 | |
568 | ||
569 | static struct dirtmp { | |
570 | u_long d_fileno; | |
571 | u_short d_reclen; | |
572 | u_short d_namlen; | |
573 | char d_name[8]; | |
574 | } rootent[] = { | |
575 | { FD_DEVFD, UIO_MX, 2, "fd" }, | |
576 | { FD_STDIN, UIO_MX, 5, "stdin" }, | |
577 | { FD_STDOUT, UIO_MX, 6, "stdout" }, | |
578 | { FD_STDERR, UIO_MX, 6, "stderr" }, | |
91447636 | 579 | { 0, 0, 0, "" } |
1c79356b A |
580 | }; |
581 | ||
582 | int | |
583 | fdesc_readdir(ap) | |
91447636 | 584 | struct vnop_readdir_args /* { |
1c79356b A |
585 | struct vnode *a_vp; |
586 | struct uio *a_uio; | |
91447636 | 587 | int a_flags; |
1c79356b | 588 | int *a_eofflag; |
91447636 A |
589 | int *a_numdirent; |
590 | vfs_context_t a_context; | |
1c79356b A |
591 | } */ *ap; |
592 | { | |
593 | struct uio *uio = ap->a_uio; | |
91447636 | 594 | struct proc *p = current_proc(); |
1c79356b A |
595 | int i, error; |
596 | ||
597 | /* | |
598 | * We don't allow exporting fdesc mounts, and currently local | |
599 | * requests do not need cookies. | |
600 | */ | |
91447636 | 601 | if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) |
9bccf70c | 602 | return (EINVAL); |
1c79356b A |
603 | |
604 | switch (VTOFDESC(ap->a_vp)->fd_type) { | |
1c79356b A |
605 | case Fdesc: |
606 | return (ENOTDIR); | |
607 | ||
608 | default: | |
609 | break; | |
610 | } | |
611 | ||
612 | if (VTOFDESC(ap->a_vp)->fd_type == Froot) { | |
613 | struct dirent d; | |
614 | struct dirent *dp = &d; | |
615 | struct dirtmp *dt; | |
616 | int fd; | |
617 | ||
618 | i = uio->uio_offset / UIO_MX; | |
619 | error = 0; | |
620 | ||
91447636 | 621 | while (uio_resid(uio) > 0) { |
1c79356b A |
622 | dt = &rootent[i]; |
623 | if (dt->d_fileno == 0) { | |
624 | /**eofflagp = 1;*/ | |
625 | break; | |
626 | } | |
627 | i++; | |
628 | ||
629 | switch (dt->d_fileno) { | |
1c79356b A |
630 | case FD_STDIN: |
631 | case FD_STDOUT: | |
632 | case FD_STDERR: | |
633 | fd = dt->d_fileno - FD_STDIN; | |
634 | if (fd >= p->p_fd->fd_nfiles) | |
635 | continue; | |
636 | if (*fdfile(p, fd) == NULL && | |
637 | !(*fdflags(p, fd) & | |
638 | UF_RESERVED)) | |
639 | continue; | |
640 | break; | |
641 | } | |
642 | bzero((caddr_t) dp, UIO_MX); | |
643 | dp->d_fileno = dt->d_fileno; | |
644 | dp->d_namlen = dt->d_namlen; | |
645 | dp->d_type = DT_UNKNOWN; | |
646 | dp->d_reclen = dt->d_reclen; | |
647 | bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); | |
648 | error = uiomove((caddr_t) dp, UIO_MX, uio); | |
649 | if (error) | |
650 | break; | |
651 | } | |
652 | uio->uio_offset = i * UIO_MX; | |
653 | return (error); | |
654 | } | |
655 | ||
656 | i = uio->uio_offset / UIO_MX; | |
657 | error = 0; | |
91447636 | 658 | while (uio_resid(uio) > 0) { |
1c79356b A |
659 | if (i >= p->p_fd->fd_nfiles) |
660 | break; | |
661 | ||
662 | if (*fdfile(p, i) != NULL && !(*fdflags(p, i) & UF_RESERVED)) { | |
663 | struct dirent d; | |
664 | struct dirent *dp = &d; | |
665 | ||
666 | bzero((caddr_t) dp, UIO_MX); | |
667 | ||
668 | dp->d_namlen = sprintf(dp->d_name, "%d", i); | |
669 | dp->d_reclen = UIO_MX; | |
670 | dp->d_type = DT_UNKNOWN; | |
671 | dp->d_fileno = i + FD_STDIN; | |
672 | /* | |
673 | * And ship to userland | |
674 | */ | |
675 | error = uiomove((caddr_t) dp, UIO_MX, uio); | |
676 | if (error) | |
677 | break; | |
678 | } | |
679 | i++; | |
680 | } | |
681 | ||
682 | uio->uio_offset = i * UIO_MX; | |
683 | return (error); | |
684 | } | |
685 | ||
686 | int | |
687 | fdesc_readlink(ap) | |
91447636 | 688 | struct vnop_readlink_args /* { |
1c79356b A |
689 | struct vnode *a_vp; |
690 | struct uio *a_uio; | |
91447636 | 691 | vfs_context_t a_context; |
1c79356b A |
692 | } */ *ap; |
693 | { | |
694 | struct vnode *vp = ap->a_vp; | |
695 | int error; | |
696 | ||
697 | if (vp->v_type != VLNK) | |
698 | return (EPERM); | |
699 | ||
700 | if (VTOFDESC(vp)->fd_type == Flink) { | |
701 | char *ln = VTOFDESC(vp)->fd_link; | |
702 | error = uiomove(ln, strlen(ln), ap->a_uio); | |
703 | } else { | |
91447636 | 704 | error = ENOTSUP; |
1c79356b A |
705 | } |
706 | ||
707 | return (error); | |
708 | } | |
709 | ||
710 | int | |
91447636 | 711 | fdesc_read(__unused struct vnop_read_args *ap) |
1c79356b | 712 | { |
1c79356b | 713 | |
91447636 | 714 | return (ENOTSUP); |
1c79356b A |
715 | } |
716 | ||
717 | int | |
91447636 | 718 | fdesc_write(__unused struct vnop_write_args *ap) |
1c79356b | 719 | { |
91447636 | 720 | return (ENOTSUP); |
1c79356b A |
721 | } |
722 | ||
723 | int | |
91447636 | 724 | fdesc_ioctl(__unused struct vnop_ioctl_args *ap) |
1c79356b | 725 | { |
91447636 | 726 | return (ENOTSUP); |
1c79356b A |
727 | } |
728 | ||
729 | int | |
91447636 | 730 | fdesc_select(__unused struct vnop_select_args *ap) |
1c79356b | 731 | { |
91447636 | 732 | return (ENOTSUP); |
1c79356b A |
733 | } |
734 | ||
735 | int | |
736 | fdesc_inactive(ap) | |
91447636 | 737 | struct vnop_inactive_args /* { |
1c79356b | 738 | struct vnode *a_vp; |
91447636 | 739 | vfs_context_t a_context; |
1c79356b A |
740 | } */ *ap; |
741 | { | |
742 | struct vnode *vp = ap->a_vp; | |
743 | ||
744 | /* | |
745 | * Clear out the v_type field to avoid | |
746 | * nasty things happening in vgone(). | |
747 | */ | |
1c79356b A |
748 | vp->v_type = VNON; |
749 | return (0); | |
750 | } | |
751 | ||
752 | int | |
753 | fdesc_reclaim(ap) | |
91447636 | 754 | struct vnop_reclaim_args /* { |
1c79356b | 755 | struct vnode *a_vp; |
91447636 | 756 | vfs_context_t a_context; |
1c79356b A |
757 | } */ *ap; |
758 | { | |
759 | struct vnode *vp = ap->a_vp; | |
760 | struct fdescnode *fd = VTOFDESC(vp); | |
761 | ||
762 | LIST_REMOVE(fd, fd_hash); | |
763 | FREE(vp->v_data, M_TEMP); | |
764 | vp->v_data = 0; | |
765 | ||
766 | return (0); | |
767 | } | |
768 | ||
769 | /* | |
770 | * Return POSIX pathconf information applicable to special devices. | |
771 | */ | |
91447636 | 772 | int |
1c79356b | 773 | fdesc_pathconf(ap) |
91447636 | 774 | struct vnop_pathconf_args /* { |
1c79356b A |
775 | struct vnode *a_vp; |
776 | int a_name; | |
777 | int *a_retval; | |
91447636 | 778 | vfs_context_t a_context; |
1c79356b A |
779 | } */ *ap; |
780 | { | |
781 | ||
782 | switch (ap->a_name) { | |
783 | case _PC_LINK_MAX: | |
784 | *ap->a_retval = LINK_MAX; | |
785 | return (0); | |
786 | case _PC_MAX_CANON: | |
787 | *ap->a_retval = MAX_CANON; | |
788 | return (0); | |
789 | case _PC_MAX_INPUT: | |
790 | *ap->a_retval = MAX_INPUT; | |
791 | return (0); | |
792 | case _PC_PIPE_BUF: | |
793 | *ap->a_retval = PIPE_BUF; | |
794 | return (0); | |
795 | case _PC_CHOWN_RESTRICTED: | |
796 | *ap->a_retval = 1; | |
797 | return (0); | |
798 | case _PC_VDISABLE: | |
799 | *ap->a_retval = _POSIX_VDISABLE; | |
800 | return (0); | |
801 | default: | |
802 | return (EINVAL); | |
803 | } | |
804 | /* NOTREACHED */ | |
805 | } | |
806 | ||
1c79356b A |
807 | |
808 | /*void*/ | |
809 | int | |
91447636 | 810 | fdesc_vfree(__unused struct vnop_vfree_args *ap) |
1c79356b A |
811 | { |
812 | ||
813 | return (0); | |
814 | } | |
815 | ||
816 | /* | |
817 | * /dev/fd "should never get here" operation | |
818 | */ | |
819 | int | |
91447636 | 820 | fdesc_badop(void) |
1c79356b A |
821 | { |
822 | ||
9bccf70c | 823 | return (ENOTSUP); |
1c79356b A |
824 | /* NOTREACHED */ |
825 | } | |
826 | ||
827 | #define VOPFUNC int (*)(void *) | |
828 | ||
91447636 A |
829 | #define fdesc_create (int (*) (struct vnop_create_args *))eopnotsupp |
830 | #define fdesc_mknod (int (*) (struct vnop_mknod_args *))eopnotsupp | |
831 | #define fdesc_close (int (*) (struct vnop_close_args *))nullop | |
832 | #define fdesc_access (int (*) (struct vnop_access_args *))nullop | |
833 | #define fdesc_mmap (int (*) (struct vnop_mmap_args *))eopnotsupp | |
834 | #define fdesc_revoke nop_revoke | |
835 | #define fdesc_fsync (int (*) (struct vnop_fsync_args *))nullop | |
836 | #define fdesc_remove (int (*) (struct vnop_remove_args *))eopnotsupp | |
837 | #define fdesc_link (int (*) (struct vnop_link_args *))eopnotsupp | |
838 | #define fdesc_rename (int (*) (struct vnop_rename_args *))eopnotsupp | |
839 | #define fdesc_mkdir (int (*) (struct vnop_mkdir_args *))eopnotsupp | |
840 | #define fdesc_rmdir (int (*) (struct vnop_rmdir_args *))eopnotsupp | |
841 | #define fdesc_symlink (int (*) (struct vnop_symlink_args *))eopnotsupp | |
842 | #define fdesc_strategy (int (*) (struct vnop_strategy_args *))fdesc_badop | |
843 | #define fdesc_advlock (int (*) (struct vnop_advlock_args *))eopnotsupp | |
844 | #define fdesc_bwrite (int (*) (struct vnop_bwrite_args *))eopnotsupp | |
845 | #define fdesc_blktooff (int (*) (struct vnop_blktooff_args *))eopnotsupp | |
846 | #define fdesc_offtoblk (int (*) (struct vnop_offtoblk_args *))eopnotsupp | |
847 | #define fdesc_blockmap (int (*) (struct vnop_blockmap_args *))eopnotsupp | |
1c79356b A |
848 | |
849 | int (**fdesc_vnodeop_p)(void *); | |
850 | struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { | |
91447636 A |
851 | { &vnop_default_desc, (VOPFUNC)vn_default_error }, |
852 | { &vnop_lookup_desc, (VOPFUNC)fdesc_lookup }, /* lookup */ | |
853 | { &vnop_create_desc, (VOPFUNC)fdesc_create }, /* create */ | |
854 | { &vnop_mknod_desc, (VOPFUNC)fdesc_mknod }, /* mknod */ | |
855 | { &vnop_open_desc, (VOPFUNC)fdesc_open }, /* open */ | |
856 | { &vnop_close_desc, (VOPFUNC)fdesc_close }, /* close */ | |
857 | { &vnop_access_desc, (VOPFUNC)fdesc_access }, /* access */ | |
858 | { &vnop_getattr_desc, (VOPFUNC)fdesc_getattr }, /* getattr */ | |
859 | { &vnop_setattr_desc, (VOPFUNC)fdesc_setattr }, /* setattr */ | |
860 | { &vnop_read_desc, (VOPFUNC)fdesc_read }, /* read */ | |
861 | { &vnop_write_desc, (VOPFUNC)fdesc_write }, /* write */ | |
862 | { &vnop_ioctl_desc, (VOPFUNC)fdesc_ioctl }, /* ioctl */ | |
863 | { &vnop_select_desc, (VOPFUNC)fdesc_select }, /* select */ | |
864 | { &vnop_revoke_desc, (VOPFUNC)fdesc_revoke }, /* revoke */ | |
865 | { &vnop_mmap_desc, (VOPFUNC)fdesc_mmap }, /* mmap */ | |
866 | { &vnop_fsync_desc, (VOPFUNC)fdesc_fsync }, /* fsync */ | |
867 | { &vnop_remove_desc, (VOPFUNC)fdesc_remove }, /* remove */ | |
868 | { &vnop_link_desc, (VOPFUNC)fdesc_link }, /* link */ | |
869 | { &vnop_rename_desc, (VOPFUNC)fdesc_rename }, /* rename */ | |
870 | { &vnop_mkdir_desc, (VOPFUNC)fdesc_mkdir }, /* mkdir */ | |
871 | { &vnop_rmdir_desc, (VOPFUNC)fdesc_rmdir }, /* rmdir */ | |
872 | { &vnop_symlink_desc, (VOPFUNC)fdesc_symlink }, /* symlink */ | |
873 | { &vnop_readdir_desc, (VOPFUNC)fdesc_readdir }, /* readdir */ | |
874 | { &vnop_readlink_desc, (VOPFUNC)fdesc_readlink },/* readlink */ | |
875 | { &vnop_inactive_desc, (VOPFUNC)fdesc_inactive },/* inactive */ | |
876 | { &vnop_reclaim_desc, (VOPFUNC)fdesc_reclaim }, /* reclaim */ | |
877 | { &vnop_strategy_desc, (VOPFUNC)fdesc_strategy }, /* strategy */ | |
878 | { &vnop_pathconf_desc, (VOPFUNC)fdesc_pathconf }, /* pathconf */ | |
879 | { &vnop_advlock_desc, (VOPFUNC)fdesc_advlock }, /* advlock */ | |
880 | { &vnop_bwrite_desc, (VOPFUNC)fdesc_bwrite }, /* bwrite */ | |
881 | { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* pagein */ | |
882 | { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* pageout */ | |
883 | { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */ | |
884 | { &vnop_blktooff_desc, (VOPFUNC)fdesc_blktooff }, /* blktooff */ | |
885 | { &vnop_blktooff_desc, (VOPFUNC)fdesc_offtoblk }, /* offtoblk */ | |
886 | { &vnop_blockmap_desc, (VOPFUNC)fdesc_blockmap }, /* blockmap */ | |
1c79356b A |
887 | { (struct vnodeop_desc*)NULL, (VOPFUNC)NULL } |
888 | }; | |
889 | struct vnodeopv_desc fdesc_vnodeop_opv_desc = | |
890 | { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; |