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