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