1 /* $NetBSD: fdesc_vnops.c,v 1.83 2005/02/26 22:59:00 perry Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software donated to Berkeley by
8 * Jan-Simon Pendry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)fdesc_vnops.c 8.17 (Berkeley) 5/22/95
35 *
36 * #Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp #
37 */
38
39 /*
40 * /dev/fd Filesystem
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: fdesc_vnops.c,v 1.83 2005/02/26 22:59:00 perry Exp $");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/time.h>
49 #include <sys/proc.h>
50 #include <sys/kernel.h> /* boottime */
51 #include <sys/resourcevar.h>
52 #include <sys/socketvar.h>
53 #include <sys/filedesc.h>
54 #include <sys/vnode.h>
55 #include <sys/malloc.h>
56 #include <sys/conf.h>
57 #include <sys/file.h>
58 #include <sys/stat.h>
59 #include <sys/mount.h>
60 #include <sys/namei.h>
61 #include <sys/buf.h>
62 #include <sys/dirent.h>
63 #include <sys/tty.h>
64
65 #include <miscfs/fdesc/fdesc.h>
66 #include <miscfs/genfs/genfs.h>
67
68 #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
69
70 #define FDL_WANT 0x01
71 #define FDL_LOCKED 0x02
72 static int fdcache_lock;
73
74 dev_t devctty;
75
76 #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
77 FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
78 #endif
79
80 #define NFDCACHE 4
81
82 #define FD_NHASH(ix) \
83 (&fdhashtbl[(ix) & fdhash])
84 LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
85 u_long fdhash;
86
87 int fdesc_lookup __P((void *));
88 #define fdesc_create genfs_eopnotsupp
89 #define fdesc_mknod genfs_eopnotsupp
90 int fdesc_open __P((void *));
91 #define fdesc_close genfs_nullop
92 #define fdesc_access genfs_nullop
93 int fdesc_getattr __P((void *));
94 int fdesc_setattr __P((void *));
95 int fdesc_read __P((void *));
96 int fdesc_write __P((void *));
97 int fdesc_ioctl __P((void *));
98 int fdesc_poll __P((void *));
99 int fdesc_kqfilter __P((void *));
100 #define fdesc_mmap genfs_eopnotsupp
101 #define fdesc_fcntl genfs_fcntl
102 #define fdesc_fsync genfs_nullop
103 #define fdesc_seek genfs_seek
104 #define fdesc_remove genfs_eopnotsupp
105 int fdesc_link __P((void *));
106 #define fdesc_rename genfs_eopnotsupp
107 #define fdesc_mkdir genfs_eopnotsupp
108 #define fdesc_rmdir genfs_eopnotsupp
109 int fdesc_symlink __P((void *));
110 int fdesc_readdir __P((void *));
111 int fdesc_readlink __P((void *));
112 #define fdesc_abortop genfs_abortop
113 int fdesc_inactive __P((void *));
114 int fdesc_reclaim __P((void *));
115 #define fdesc_lock genfs_lock
116 #define fdesc_unlock genfs_unlock
117 #define fdesc_bmap genfs_badop
118 #define fdesc_strategy genfs_badop
119 int fdesc_print __P((void *));
120 int fdesc_pathconf __P((void *));
121 #define fdesc_islocked genfs_islocked
122 #define fdesc_advlock genfs_einval
123 #define fdesc_blkatoff genfs_eopnotsupp
124 #define fdesc_valloc genfs_eopnotsupp
125 #define fdesc_vfree genfs_nullop
126 #define fdesc_truncate genfs_eopnotsupp
127 #define fdesc_update genfs_nullop
128 #define fdesc_bwrite genfs_eopnotsupp
129 #define fdesc_revoke genfs_revoke
130 #define fdesc_putpages genfs_null_putpages
131
132 static int fdesc_attr __P((int, struct vattr *, struct ucred *, struct proc *));
133
134 int (**fdesc_vnodeop_p) __P((void *));
135 const struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
136 { &vop_default_desc, vn_default_error },
137 { &vop_lookup_desc, fdesc_lookup }, /* lookup */
138 { &vop_create_desc, fdesc_create }, /* create */
139 { &vop_mknod_desc, fdesc_mknod }, /* mknod */
140 { &vop_open_desc, fdesc_open }, /* open */
141 { &vop_close_desc, fdesc_close }, /* close */
142 { &vop_access_desc, fdesc_access }, /* access */
143 { &vop_getattr_desc, fdesc_getattr }, /* getattr */
144 { &vop_setattr_desc, fdesc_setattr }, /* setattr */
145 { &vop_read_desc, fdesc_read }, /* read */
146 { &vop_write_desc, fdesc_write }, /* write */
147 { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */
148 { &vop_fcntl_desc, fdesc_fcntl }, /* fcntl */
149 { &vop_poll_desc, fdesc_poll }, /* poll */
150 { &vop_kqfilter_desc, fdesc_kqfilter }, /* kqfilter */
151 { &vop_revoke_desc, fdesc_revoke }, /* revoke */
152 { &vop_mmap_desc, fdesc_mmap }, /* mmap */
153 { &vop_fsync_desc, fdesc_fsync }, /* fsync */
154 { &vop_seek_desc, fdesc_seek }, /* seek */
155 { &vop_remove_desc, fdesc_remove }, /* remove */
156 { &vop_link_desc, fdesc_link }, /* link */
157 { &vop_rename_desc, fdesc_rename }, /* rename */
158 { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */
159 { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */
160 { &vop_symlink_desc, fdesc_symlink }, /* symlink */
161 { &vop_readdir_desc, fdesc_readdir }, /* readdir */
162 { &vop_readlink_desc, fdesc_readlink }, /* readlink */
163 { &vop_abortop_desc, fdesc_abortop }, /* abortop */
164 { &vop_inactive_desc, fdesc_inactive }, /* inactive */
165 { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */
166 { &vop_lock_desc, fdesc_lock }, /* lock */
167 { &vop_unlock_desc, fdesc_unlock }, /* unlock */
168 { &vop_bmap_desc, fdesc_bmap }, /* bmap */
169 { &vop_strategy_desc, fdesc_strategy }, /* strategy */
170 { &vop_print_desc, fdesc_print }, /* print */
171 { &vop_islocked_desc, fdesc_islocked }, /* islocked */
172 { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */
173 { &vop_advlock_desc, fdesc_advlock }, /* advlock */
174 { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */
175 { &vop_valloc_desc, fdesc_valloc }, /* valloc */
176 { &vop_vfree_desc, fdesc_vfree }, /* vfree */
177 { &vop_truncate_desc, fdesc_truncate }, /* truncate */
178 { &vop_update_desc, fdesc_update }, /* update */
179 { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */
180 { &vop_putpages_desc, fdesc_putpages }, /* putpages */
181 { NULL, NULL }
182 };
183
184 const struct vnodeopv_desc fdesc_vnodeop_opv_desc =
185 { &fdesc_vnodeop_p, fdesc_vnodeop_entries };
186
187 extern const struct cdevsw ctty_cdevsw;
188
189 /*
190 * Initialise cache headers
191 */
192 void
193 fdesc_init()
194 {
195 int cttymajor;
196
197 /* locate the major number */
198 cttymajor = cdevsw_lookup_major(&ctty_cdevsw);
199 devctty = makedev(cttymajor, 0);
200 fdhashtbl = hashinit(NFDCACHE, HASH_LIST, M_CACHE, M_NOWAIT, &fdhash);
201 }
202
203 /*
204 * Free hash table.
205 */
206 void
207 fdesc_done()
208 {
209 hashdone(fdhashtbl, M_CACHE);
210 }
211
212 /*
213 * Return a locked vnode of the correct type.
214 */
215 int
216 fdesc_allocvp(ftype, ix, mp, vpp)
217 fdntype ftype;
218 int ix;
219 struct mount *mp;
220 struct vnode **vpp;
221 {
222 struct fdhashhead *fc;
223 struct fdescnode *fd;
224 int error = 0;
225
226 fc = FD_NHASH(ix);
227 loop:
228 for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
229 if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
230 if (vget(fd->fd_vnode, LK_EXCLUSIVE))
231 goto loop;
232 *vpp = fd->fd_vnode;
233 return (error);
234 }
235 }
236
237 /*
238 * otherwise lock the array while we call getnewvnode
239 * since that can block.
240 */
241 if (fdcache_lock & FDL_LOCKED) {
242 fdcache_lock |= FDL_WANT;
243 (void) tsleep(&fdcache_lock, PINOD, "fdcache", 0);
244 goto loop;
245 }
246 fdcache_lock |= FDL_LOCKED;
247
248 error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
249 if (error)
250 goto out;
251 MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
252 (*vpp)->v_data = fd;
253 fd->fd_vnode = *vpp;
254 fd->fd_type = ftype;
255 fd->fd_fd = -1;
256 fd->fd_link = 0;
257 fd->fd_ix = ix;
258 VOP_LOCK(*vpp, LK_EXCLUSIVE);
259 LIST_INSERT_HEAD(fc, fd, fd_hash);
260
261 out:;
262 fdcache_lock &= ~FDL_LOCKED;
263
264 if (fdcache_lock & FDL_WANT) {
265 fdcache_lock &= ~FDL_WANT;
266 wakeup(&fdcache_lock);
267 }
268
269 return (error);
270 }
271
272 /*
273 * vp is the current namei directory
274 * ndp is the name to locate in that directory...
275 */
276 int
277 fdesc_lookup(v)
278 void *v;
279 {
280 struct vop_lookup_args /* {
281 struct vnode * a_dvp;
282 struct vnode ** a_vpp;
283 struct componentname * a_cnp;
284 } */ *ap = v;
285 struct vnode **vpp = ap->a_vpp;
286 struct vnode *dvp = ap->a_dvp;
287 struct componentname *cnp = ap->a_cnp;
288 struct proc *p = cnp->cn_proc;
289 const char *pname = cnp->cn_nameptr;
290 int nfiles = p->p_fd->fd_nfiles;
291 unsigned fd = 0;
292 int error;
293 struct vnode *fvp;
294 char *ln;
295
296 if (cnp->cn_namelen == 1 && *pname == '.') {
297 *vpp = dvp;
298 VREF(dvp);
299 return (0);
300 }
301
302 switch (VTOFDESC(dvp)->fd_type) {
303 default:
304 case Flink:
305 case Fdesc:
306 case Fctty:
307 error = ENOTDIR;
308 goto bad;
309
310 case Froot:
311 if (cnp->cn_namelen == 2 && memcmp(pname, "fd", 2) == 0) {
312 error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
313 if (error)
314 goto bad;
315 *vpp = fvp;
316 fvp->v_type = VDIR;
317 goto good;
318 }
319
320 if (cnp->cn_namelen == 3 && memcmp(pname, "tty", 3) == 0) {
321 struct vnode *ttyvp = cttyvp(p);
322 if (ttyvp == NULL) {
323 error = ENXIO;
324 goto bad;
325 }
326 error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);
327 if (error)
328 goto bad;
329 *vpp = fvp;
330 fvp->v_type = VCHR;
331 goto good;
332 }
333
334 ln = 0;
335 switch (cnp->cn_namelen) {
336 case 5:
337 if (memcmp(pname, "stdin", 5) == 0) {
338 ln = "fd/0";
339 fd = FD_STDIN;
340 }
341 break;
342 case 6:
343 if (memcmp(pname, "stdout", 6) == 0) {
344 ln = "fd/1";
345 fd = FD_STDOUT;
346 } else
347 if (memcmp(pname, "stderr", 6) == 0) {
348 ln = "fd/2";
349 fd = FD_STDERR;
350 }
351 break;
352 }
353
354 if (ln) {
355 error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);
356 if (error)
357 goto bad;
358 VTOFDESC(fvp)->fd_link = ln;
359 *vpp = fvp;
360 fvp->v_type = VLNK;
361 goto good;
362 } else {
363 error = ENOENT;
364 goto bad;
365 }
366
367 /* FALL THROUGH */
368
369 case Fdevfd:
370 if (cnp->cn_namelen == 2 && memcmp(pname, "..", 2) == 0) {
371 VOP_UNLOCK(dvp, 0);
372 cnp->cn_flags |= PDIRUNLOCK;
373 error = fdesc_root(dvp->v_mount, vpp);
374 if (error)
375 goto bad;
376 /*
377 * If we're at the last component and need the
378 * parent locked, undo the unlock above.
379 */
380 if (((~cnp->cn_flags & (ISLASTCN | LOCKPARENT)) == 0) &&
381 ((error = vn_lock(dvp, LK_EXCLUSIVE)) == 0))
382 cnp->cn_flags &= ~PDIRUNLOCK;
383 return (error);
384 }
385
386 fd = 0;
387 while (*pname >= '' && *pname <= '9') {
388 fd = 10 * fd + *pname++ - '';
389 if (fd >= nfiles)
390 break;
391 }
392
393 if (*pname != '\0') {
394 error = ENOENT;
395 goto bad;
396 }
397
398 if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL ||
399 FILE_IS_USABLE(p->p_fd->fd_ofiles[fd]) == 0) {
400 error = EBADF;
401 goto bad;
402 }
403
404 error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);
405 if (error)
406 goto bad;
407 VTOFDESC(fvp)->fd_fd = fd;
408 *vpp = fvp;
409 goto good;
410 }
411
412 bad:;
413 *vpp = NULL;
414 return (error);
415
416 good:;
417 /*
418 * As "." was special cased above, we now unlock the parent if we're
419 * suppoed to. We're only supposed to not unlock if this is the
420 * last component, and the caller requested LOCKPARENT. So if either
421 * condition is false, unlock.
422 */
423 if (((~cnp->cn_flags) & (ISLASTCN | LOCKPARENT)) != 0) {
424 VOP_UNLOCK(dvp, 0);
425 cnp->cn_flags |= PDIRUNLOCK;
426 }
427 return (0);
428 }
429
430 int
431 fdesc_open(v)
432 void *v;
433 {
434 struct vop_open_args /* {
435 struct vnode *a_vp;
436 int a_mode;
437 struct ucred *a_cred;
438 struct proc *a_p;
439 } */ *ap = v;
440 struct vnode *vp = ap->a_vp;
441
442 switch (VTOFDESC(vp)->fd_type) {
443 case Fdesc:
444 /*
445 * XXX Kludge: set dupfd to contain the value of the
446 * the file descriptor being sought for duplication. The error
447 * return ensures that the vnode for this device will be
448 * released by vn_open. Open will detect this special error and
449 * take the actions in dupfdopen. Other callers of vn_open or
450 * VOP_OPEN will simply report the error.
451 */
452 curlwp->l_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */
453 return EDUPFD;
454
455 case Fctty:
456 return ((*ctty_cdevsw.d_open)(devctty, ap->a_mode, 0, ap->a_p));
457 case Froot:
458 case Fdevfd:
459 case Flink:
460 break;
461 }
462
463 return (0);
464 }
465
466 static int
467 fdesc_attr(fd, vap, cred, p)
468 int fd;
469 struct vattr *vap;
470 struct ucred *cred;
471 struct proc *p;
472 {
473 struct filedesc *fdp = p->p_fd;
474 struct file *fp;
475 struct stat stb;
476 int error;
477
478 if ((fp = fd_getfile(fdp, fd)) == NULL)
479 return (EBADF);
480
481 switch (fp->f_type) {
482 case DTYPE_VNODE:
483 simple_unlock(&fp->f_slock);
484 error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
485 if (error == 0 && vap->va_type == VDIR) {
486 /*
487 * directories can cause loops in the namespace,
488 * so turn off the 'x' bits to avoid trouble.
489 */
490 vap->va_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
491 }
492 break;
493
494 default:
495 FILE_USE(fp);
496 memset(&stb, 0, sizeof(stb));
497 error = (*fp->f_ops->fo_stat)(fp, &stb, p);
498 FILE_UNUSE(fp, p);
499 if (error)
500 break;
501
502 vattr_null(vap);
503 switch(fp->f_type) {
504 case DTYPE_SOCKET:
505 vap->va_type = VSOCK;
506 break;
507 case DTYPE_PIPE:
508 vap->va_type = VFIFO;
509 break;
510 default:
511 /* use VNON perhaps? */
512 vap->va_type = VBAD;
513 break;
514 }
515 vap->va_mode = stb.st_mode;
516 vap->va_nlink = stb.st_nlink;
517 vap->va_uid = stb.st_uid;
518 vap->va_gid = stb.st_gid;
519 vap->va_fsid = stb.st_dev;
520 vap->va_fileid = stb.st_ino;
521 vap->va_size = stb.st_size;
522 vap->va_blocksize = stb.st_blksize;
523 vap->va_atime = stb.st_atimespec;
524 vap->va_mtime = stb.st_mtimespec;
525 vap->va_ctime = stb.st_ctimespec;
526 vap->va_gen = stb.st_gen;
527 vap->va_flags = stb.st_flags;
528 vap->va_rdev = stb.st_rdev;
529 vap->va_bytes = stb.st_blocks * stb.st_blksize;
530 break;
531 }
532
533 return (error);
534 }
535
536 int
537 fdesc_getattr(v)
538 void *v;
539 {
540 struct vop_getattr_args /* {
541 struct vnode *a_vp;
542 struct vattr *a_vap;
543 struct ucred *a_cred;
544 struct proc *a_p;
545 } */ *ap = v;
546 struct vnode *vp = ap->a_vp;
547 struct vattr *vap = ap->a_vap;
548 unsigned fd;
549 int error = 0;
550
551 switch (VTOFDESC(vp)->fd_type) {
552 case Froot:
553 case Fdevfd:
554 case Flink:
555 case Fctty:
556 VATTR_NULL(vap);
557 vap->va_fileid = VTOFDESC(vp)->fd_ix;
558
559 #define R_ALL (S_IRUSR|S_IRGRP|S_IROTH)
560 #define W_ALL (S_IWUSR|S_IWGRP|S_IWOTH)
561 #define X_ALL (S_IXUSR|S_IXGRP|S_IXOTH)
562
563 switch (VTOFDESC(vp)->fd_type) {
564 case Flink:
565 vap->va_mode = R_ALL|X_ALL;
566 vap->va_type = VLNK;
567 vap->va_rdev = 0;
568 vap->va_nlink = 1;
569 vap->va_size = strlen(VTOFDESC(vp)->fd_link);
570 break;
571
572 case Fctty:
573 vap->va_mode = R_ALL|W_ALL;
574 vap->va_type = VCHR;
575 vap->va_rdev = devctty;
576 vap->va_nlink = 1;
577 vap->va_size = 0;
578 break;
579
580 default:
581 vap->va_mode = R_ALL|X_ALL;
582 vap->va_type = VDIR;
583 vap->va_rdev = 0;
584 vap->va_nlink = 2;
585 vap->va_size = DEV_BSIZE;
586 break;
587 }
588 vap->va_uid = 0;
589 vap->va_gid = 0;
590 vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
591 vap->va_blocksize = DEV_BSIZE;
592 vap->va_atime.tv_sec = boottime.tv_sec;
593 vap->va_atime.tv_nsec = 0;
594 vap->va_mtime = vap->va_atime;
595 vap->va_ctime = vap->va_mtime;
596 vap->va_gen = 0;
597 vap->va_flags = 0;
598 vap->va_bytes = 0;
599 break;
600
601 case Fdesc:
602 fd = VTOFDESC(vp)->fd_fd;
603 error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
604 break;
605
606 default:
607 panic("fdesc_getattr");
608 break;
609 }
610
611 if (error == 0)
612 vp->v_type = vap->va_type;
613
614 return (error);
615 }
616
617 int
618 fdesc_setattr(v)
619 void *v;
620 {
621 struct vop_setattr_args /* {
622 struct vnode *a_vp;
623 struct vattr *a_vap;
624 struct ucred *a_cred;
625 struct proc *a_p;
626 } */ *ap = v;
627 struct filedesc *fdp = ap->a_p->p_fd;
628 struct file *fp;
629 unsigned fd;
630
631 /*
632 * Can't mess with the root vnode
633 */
634 switch (VTOFDESC(ap->a_vp)->fd_type) {
635 case Fdesc:
636 break;
637
638 case Fctty:
639 return (0);
640
641 default:
642 return (EACCES);
643 }
644
645 fd = VTOFDESC(ap->a_vp)->fd_fd;
646 if ((fp = fd_getfile(fdp, fd)) == NULL)
647 return (EBADF);
648
649 /*
650 * XXX: Can't reasonably set the attr's on any types currently.
651 * On vnode's this will cause truncation and socket/pipes make
652 * no sense.
653 */
654 simple_unlock(&fp->f_slock);
655 return (0);
656 }
657
658 #define UIO_MX 32
659
660 struct fdesc_target {
661 ino_t ft_fileno;
662 u_char ft_type;
663 u_char ft_namlen;
664 char *ft_name;
665 } fdesc_targets[] = {
666 /* NOTE: The name must be less than UIO_MX-16 chars in length */
667 #define N(s) sizeof(s)-1, s
668 { FD_DEVFD, DT_DIR, N("fd") },
669 { FD_STDIN, DT_LNK, N("stdin") },
670 { FD_STDOUT, DT_LNK, N("stdout") },
671 { FD_STDERR, DT_LNK, N("stderr") },
672 { FD_CTTY, DT_UNKNOWN, N("tty") },
673 #undef N
674 };
675 static int nfdesc_targets = sizeof(fdesc_targets) / sizeof(fdesc_targets[0]);
676
677 int
678 fdesc_readdir(v)
679 void *v;
680 {
681 struct vop_readdir_args /* {
682 struct vnode *a_vp;
683 struct uio *a_uio;
684 struct ucred *a_cred;
685 int *a_eofflag;
686 off_t **a_cookies;
687 int *a_ncookies;
688 } */ *ap = v;
689 struct uio *uio = ap->a_uio;
690 struct dirent d;
691 struct filedesc *fdp;
692 off_t i;
693 int error;
694 off_t *cookies = NULL;
695 int ncookies = 0;
696
697 switch (VTOFDESC(ap->a_vp)->fd_type) {
698 case Fctty:
699 return (0);
700
701 case Fdesc:
702 return (ENOTDIR);
703
704 default:
705 break;
706 }
707
708 fdp = uio->uio_procp->p_fd;
709
710 if (uio->uio_resid < UIO_MX)
711 return (EINVAL);
712 if (uio->uio_offset < 0)
713 return (EINVAL);
714
715 error = 0;
716 i = uio->uio_offset;
717 memset(&d, 0, UIO_MX);
718 d.d_reclen = UIO_MX;
719 if (ap->a_ncookies)
720 ncookies = (uio->uio_resid / UIO_MX);
721
722 if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
723 struct fdesc_target *ft;
724
725 if (i >= nfdesc_targets)
726 return 0;
727
728 if (ap->a_ncookies) {
729 ncookies = min(ncookies, (nfdesc_targets - i));
730 cookies = malloc(ncookies * sizeof(off_t),
731 M_TEMP, M_WAITOK);
732 *ap->a_cookies = cookies;
733 *ap->a_ncookies = ncookies;
734 }
735
736 for (ft = &fdesc_targets[i];
737 uio->uio_resid >= UIO_MX && i < nfdesc_targets; ft++, i++) {
738 switch (ft->ft_fileno) {
739 case FD_CTTY:
740 if (cttyvp(uio->uio_procp) == NULL)
741 continue;
742 break;
743
744 case FD_STDIN:
745 case FD_STDOUT:
746 case FD_STDERR:
747 if ((ft->ft_fileno - FD_STDIN) >= fdp->fd_nfiles)
748 continue;
749 if (fdp->fd_ofiles[ft->ft_fileno - FD_STDIN] == NULL
750 || FILE_IS_USABLE(fdp->fd_ofiles[ft->ft_fileno - FD_STDIN]) == 0)
751 continue;
752 break;
753 }
754
755 d.d_fileno = ft->ft_fileno;
756 d.d_namlen = ft->ft_namlen;
757 memcpy(d.d_name, ft->ft_name, ft->ft_namlen + 1);
758 d.d_type = ft->ft_type;
759
760 if ((error = uiomove(&d, UIO_MX, uio)) != 0)
761 break;
762 if (cookies)
763 *cookies++ = i + 1;
764 }
765 } else {
766 if (ap->a_ncookies) {
767 ncookies = min(ncookies, (fdp->fd_nfiles + 2));
768 cookies = malloc(ncookies * sizeof(off_t),
769 M_TEMP, M_WAITOK);
770 *ap->a_cookies = cookies;
771 *ap->a_ncookies = ncookies;
772 }
773 for (; i - 2 < fdp->fd_nfiles && uio->uio_resid >= UIO_MX;
774 i++) {
775 switch (i) {
776 case 0:
777 case 1:
778 d.d_fileno = FD_ROOT; /* XXX */
779 d.d_namlen = i + 1;
780 memcpy(d.d_name, "..", d.d_namlen);
781 d.d_name[i + 1] = '\0';
782 d.d_type = DT_DIR;
783 break;
784
785 default:
786 if (fdp->fd_ofiles[i - 2] == NULL ||
787 FILE_IS_USABLE(fdp->fd_ofiles[i - 2]) == 0)
788 continue;
789 d.d_fileno = i - 2 + FD_STDIN;
790 d.d_namlen = sprintf(d.d_name, "%d", (int) i - 2);
791 d.d_type = DT_UNKNOWN;
792 break;
793 }
794
795 if ((error = uiomove(&d, UIO_MX, uio)) != 0)
796 break;
797 if (cookies)
798 *cookies++ = i + 1;
799 }
800 }
801
802 if (ap->a_ncookies && error) {
803 free(*ap->a_cookies, M_TEMP);
804 *ap->a_ncookies = 0;
805 *ap->a_cookies = NULL;
806 }
807
808 uio->uio_offset = i;
809 return (error);
810 }
811
812 int
813 fdesc_readlink(v)
814 void *v;
815 {
816 struct vop_readlink_args /* {
817 struct vnode *a_vp;
818 struct uio *a_uio;
819 struct ucred *a_cred;
820 } */ *ap = v;
821 struct vnode *vp = ap->a_vp;
822 int error;
823
824 if (vp->v_type != VLNK)
825 return (EPERM);
826
827 if (VTOFDESC(vp)->fd_type == Flink) {
828 char *ln = VTOFDESC(vp)->fd_link;
829 error = uiomove(ln, strlen(ln), ap->a_uio);
830 } else {
831 error = EOPNOTSUPP;
832 }
833
834 return (error);
835 }
836
837 int
838 fdesc_read(v)
839 void *v;
840 {
841 struct vop_read_args /* {
842 struct vnode *a_vp;
843 struct uio *a_uio;
844 int a_ioflag;
845 struct ucred *a_cred;
846 } */ *ap = v;
847 int error = EOPNOTSUPP;
848 struct vnode *vp = ap->a_vp;
849
850 switch (VTOFDESC(vp)->fd_type) {
851 case Fctty:
852 VOP_UNLOCK(vp, 0);
853 error = (*ctty_cdevsw.d_read)(devctty, ap->a_uio, ap->a_ioflag);
854 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
855 break;
856
857 default:
858 error = EOPNOTSUPP;
859 break;
860 }
861
862 return (error);
863 }
864
865 int
866 fdesc_write(v)
867 void *v;
868 {
869 struct vop_write_args /* {
870 struct vnode *a_vp;
871 struct uio *a_uio;
872 int a_ioflag;
873 struct ucred *a_cred;
874 } */ *ap = v;
875 int error = EOPNOTSUPP;
876 struct vnode *vp = ap->a_vp;
877
878 switch (VTOFDESC(vp)->fd_type) {
879 case Fctty:
880 VOP_UNLOCK(vp, 0);
881 error = (*ctty_cdevsw.d_write)(devctty, ap->a_uio,
882 ap->a_ioflag);
883 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
884 break;
885
886 default:
887 error = EOPNOTSUPP;
888 break;
889 }
890
891 return (error);
892 }
893
894 int
895 fdesc_ioctl(v)
896 void *v;
897 {
898 struct vop_ioctl_args /* {
899 struct vnode *a_vp;
900 u_long a_command;
901 void *a_data;
902 int a_fflag;
903 struct ucred *a_cred;
904 struct proc *a_p;
905 } */ *ap = v;
906 int error = EOPNOTSUPP;
907
908 switch (VTOFDESC(ap->a_vp)->fd_type) {
909 case Fctty:
910 error = (*ctty_cdevsw.d_ioctl)(devctty, ap->a_command,
911 ap->a_data, ap->a_fflag,
912 ap->a_p);
913 break;
914
915 default:
916 error = EOPNOTSUPP;
917 break;
918 }
919
920 return (error);
921 }
922
923 int
924 fdesc_poll(v)
925 void *v;
926 {
927 struct vop_poll_args /* {
928 struct vnode *a_vp;
929 int a_events;
930 struct proc *a_p;
931 } */ *ap = v;
932 int revents;
933
934 switch (VTOFDESC(ap->a_vp)->fd_type) {
935 case Fctty:
936 revents = (*ctty_cdevsw.d_poll)(devctty, ap->a_events, ap->a_p);
937 break;
938
939 default:
940 revents = genfs_poll(v);
941 break;
942 }
943
944 return (revents);
945 }
946
947 int
948 fdesc_kqfilter(v)
949 void *v;
950 {
951 struct vop_kqfilter_args /* {
952 struct vnode *a_vp;
953 struct knote *a_kn;
954 } */ *ap = v;
955 int error;
956 struct proc *p;
957 struct file *fp;
958
959 switch (VTOFDESC(ap->a_vp)->fd_type) {
960 case Fctty:
961 error = (*ctty_cdevsw.d_kqfilter)(devctty, ap->a_kn);
962 break;
963
964 case Fdesc:
965 /* just invoke kqfilter for the underlying descriptor */
966 p = curproc; /* XXX hopefully ok to use curproc here */
967 if ((fp = fd_getfile(p->p_fd, VTOFDESC(ap->a_vp)->fd_fd)) == NULL)
968 return (1);
969
970 FILE_USE(fp);
971 error = (*fp->f_ops->fo_kqfilter)(fp, ap->a_kn);
972 FILE_UNUSE(fp, p);
973 break;
974
975 default:
976 return (genfs_kqfilter(v));
977 }
978
979 return (error);
980 }
981
982 int
983 fdesc_inactive(v)
984 void *v;
985 {
986 struct vop_inactive_args /* {
987 struct vnode *a_vp;
988 struct proc *a_p;
989 } */ *ap = v;
990 struct vnode *vp = ap->a_vp;
991
992 /*
993 * Clear out the v_type field to avoid
994 * nasty things happening in vgone().
995 */
996 VOP_UNLOCK(vp, 0);
997 vp->v_type = VNON;
998 return (0);
999 }
1000
1001 int
1002 fdesc_reclaim(v)
1003 void *v;
1004 {
1005 struct vop_reclaim_args /* {
1006 struct vnode *a_vp;
1007 } */ *ap = v;
1008 struct vnode *vp = ap->a_vp;
1009 struct fdescnode *fd = VTOFDESC(vp);
1010
1011 LIST_REMOVE(fd, fd_hash);
1012 FREE(vp->v_data, M_TEMP);
1013 vp->v_data = 0;
1014
1015 return (0);
1016 }
1017
1018 /*
1019 * Return POSIX pathconf information applicable to special devices.
1020 */
1021 int
1022 fdesc_pathconf(v)
1023 void *v;
1024 {
1025 struct vop_pathconf_args /* {
1026 struct vnode *a_vp;
1027 int a_name;
1028 register_t *a_retval;
1029 } */ *ap = v;
1030
1031 switch (ap->a_name) {
1032 case _PC_LINK_MAX:
1033 *ap->a_retval = LINK_MAX;
1034 return (0);
1035 case _PC_MAX_CANON:
1036 *ap->a_retval = MAX_CANON;
1037 return (0);
1038 case _PC_MAX_INPUT:
1039 *ap->a_retval = MAX_INPUT;
1040 return (0);
1041 case _PC_PIPE_BUF:
1042 *ap->a_retval = PIPE_BUF;
1043 return (0);
1044 case _PC_CHOWN_RESTRICTED:
1045 *ap->a_retval = 1;
1046 return (0);
1047 case _PC_VDISABLE:
1048 *ap->a_retval = _POSIX_VDISABLE;
1049 return (0);
1050 case _PC_SYNC_IO:
1051 *ap->a_retval = 1;
1052 return (0);
1053 default:
1054 return (EINVAL);
1055 }
1056 /* NOTREACHED */
1057 }
1058
1059 /*
1060 * Print out the contents of a /dev/fd vnode.
1061 */
1062 /* ARGSUSED */
1063 int
1064 fdesc_print(v)
1065 void *v;
1066 {
1067 printf("tag VT_NON, fdesc vnode\n");
1068 return (0);
1069 }
1070
1071 int
1072 fdesc_link(v)
1073 void *v;
1074 {
1075 struct vop_link_args /* {
1076 struct vnode *a_dvp;
1077 struct vnode *a_vp;
1078 struct componentname *a_cnp;
1079 } */ *ap = v;
1080
1081 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
1082 vput(ap->a_dvp);
1083 return (EROFS);
1084 }
1085
1086 int
1087 fdesc_symlink(v)
1088 void *v;
1089 {
1090 struct vop_symlink_args /* {
1091 struct vnode *a_dvp;
1092 struct vnode **a_vpp;
1093 struct componentname *a_cnp;
1094 struct vattr *a_vap;
1095 char *a_target;
1096 } */ *ap = v;
1097
1098 VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
1099 vput(ap->a_dvp);
1100 return (EROFS);
1101 }
Cache object: 8257b9578c4116a62fa4e0ad477102be
|