summaryrefslogtreecommitdiffstats
path: root/sys/fs/fdescfs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/fdescfs')
-rw-r--r--sys/fs/fdescfs/fdesc.h79
-rw-r--r--sys/fs/fdescfs/fdesc_vfsops.c264
-rw-r--r--sys/fs/fdescfs/fdesc_vnops.c872
3 files changed, 1215 insertions, 0 deletions
diff --git a/sys/fs/fdescfs/fdesc.h b/sys/fs/fdescfs/fdesc.h
new file mode 100644
index 0000000..bbba54d
--- /dev/null
+++ b/sys/fs/fdescfs/fdesc.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdesc.h 8.5 (Berkeley) 1/21/94
+ *
+ * $Id: fdesc.h,v 1.5 1997/02/22 09:40:14 peter Exp $
+ */
+
+#ifdef KERNEL
+struct fdescmount {
+ struct vnode *f_root; /* Root node */
+};
+
+#define FD_ROOT 2
+#define FD_DEVFD 3
+#define FD_STDIN 4
+#define FD_STDOUT 5
+#define FD_STDERR 6
+#define FD_CTTY 7
+#define FD_DESC 8
+#define FD_MAX 12
+
+typedef enum {
+ Froot,
+ Fdevfd,
+ Fdesc,
+ Flink,
+ Fctty
+} fdntype;
+
+struct fdescnode {
+ LIST_ENTRY(fdescnode) fd_hash; /* Hash list */
+ struct vnode *fd_vnode; /* Back ptr to vnode */
+ fdntype fd_type; /* Type of this node */
+ unsigned fd_fd; /* Fd to be dup'ed */
+ char *fd_link; /* Link to fd/n */
+ int fd_ix; /* filesystem index */
+};
+
+#define VFSTOFDESC(mp) ((struct fdescmount *)((mp)->mnt_data))
+#define VTOFDESC(vp) ((struct fdescnode *)(vp)->v_data)
+
+extern dev_t devctty;
+extern int fdesc_init __P((struct vfsconf *));
+extern int fdesc_root __P((struct mount *, struct vnode **));
+extern int fdesc_allocvp __P((fdntype, int, struct mount *, struct vnode **));
+#endif /* KERNEL */
diff --git a/sys/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c
new file mode 100644
index 0000000..758f3b5
--- /dev/null
+++ b/sys/fs/fdescfs/fdesc_vfsops.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 1992, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdesc_vfsops.c 8.4 (Berkeley) 1/21/94
+ *
+ * $Id: fdesc_vfsops.c,v 1.17 1999/01/12 11:49:30 eivind Exp $
+ */
+
+/*
+ * /dev/fd Filesystem
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/resourcevar.h>
+#include <sys/filedesc.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+#include <miscfs/fdesc/fdesc.h>
+
+static MALLOC_DEFINE(M_FDESCMNT, "FDESC mount", "FDESC mount structure");
+
+static int fdesc_mount __P((struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct proc *p));
+static int fdesc_start __P((struct mount *mp, int flags, struct proc *p));
+static int fdesc_unmount __P((struct mount *mp, int mntflags,
+ struct proc *p));
+static int fdesc_statfs __P((struct mount *mp, struct statfs *sbp,
+ struct proc *p));
+static int fdesc_sync __P((struct mount *mp, int waitfor,
+ struct ucred *cred, struct proc *p));
+
+/*
+ * Mount the per-process file descriptors (/dev/fd)
+ */
+static int
+fdesc_mount(mp, path, data, ndp, p)
+ struct mount *mp;
+ char *path;
+ caddr_t data;
+ struct nameidata *ndp;
+ struct proc *p;
+{
+ int error = 0;
+ u_int size;
+ struct fdescmount *fmp;
+ struct vnode *rvp;
+
+ /*
+ * Update is a no-op
+ */
+ if (mp->mnt_flag & MNT_UPDATE)
+ return (EOPNOTSUPP);
+
+ error = fdesc_allocvp(Froot, FD_ROOT, mp, &rvp);
+ if (error)
+ return (error);
+
+ MALLOC(fmp, struct fdescmount *, sizeof(struct fdescmount),
+ M_FDESCMNT, M_WAITOK); /* XXX */
+ rvp->v_type = VDIR;
+ rvp->v_flag |= VROOT;
+ fmp->f_root = rvp;
+ /* XXX -- don't mark as local to work around fts() problems */
+ /*mp->mnt_flag |= MNT_LOCAL;*/
+ mp->mnt_data = (qaddr_t) fmp;
+ vfs_getnewfsid(mp);
+
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
+ bcopy("fdesc", mp->mnt_stat.f_mntfromname, sizeof("fdesc"));
+ (void)fdesc_statfs(mp, &mp->mnt_stat, p);
+ return (0);
+}
+
+static int
+fdesc_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+ return (0);
+}
+
+static int
+fdesc_unmount(mp, mntflags, p)
+ struct mount *mp;
+ int mntflags;
+ struct proc *p;
+{
+ int error;
+ int flags = 0;
+ struct vnode *rootvp = VFSTOFDESC(mp)->f_root;
+
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+
+ /*
+ * Clear out buffer cache. I don't think we
+ * ever get anything cached at this level at the
+ * moment, but who knows...
+ */
+ if (rootvp->v_usecount > 1)
+ return (EBUSY);
+ if ((error = vflush(mp, rootvp, flags)) != 0)
+ return (error);
+
+ /*
+ * Release reference on underlying root vnode
+ */
+ vrele(rootvp);
+ /*
+ * And blow it away for future re-use
+ */
+ vgone(rootvp);
+ /*
+ * Finally, throw away the fdescmount structure
+ */
+ free(mp->mnt_data, M_FDESCMNT); /* XXX */
+ mp->mnt_data = 0;
+
+ return (0);
+}
+
+int
+fdesc_root(mp, vpp)
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ struct proc *p = curproc; /* XXX */
+ struct vnode *vp;
+
+ /*
+ * Return locked reference to root.
+ */
+ vp = VFSTOFDESC(mp)->f_root;
+ VREF(vp);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ *vpp = vp;
+ return (0);
+}
+
+static int
+fdesc_statfs(mp, sbp, p)
+ struct mount *mp;
+ struct statfs *sbp;
+ struct proc *p;
+{
+ struct filedesc *fdp;
+ int lim;
+ int i;
+ int last;
+ int freefd;
+
+ /*
+ * Compute number of free file descriptors.
+ * [ Strange results will ensue if the open file
+ * limit is ever reduced below the current number
+ * of open files... ]
+ */
+ lim = p->p_rlimit[RLIMIT_NOFILE].rlim_cur;
+ fdp = p->p_fd;
+ last = min(fdp->fd_nfiles, lim);
+ freefd = 0;
+ for (i = fdp->fd_freefile; i < last; i++)
+ if (fdp->fd_ofiles[i] == NULL)
+ freefd++;
+
+ /*
+ * Adjust for the fact that the fdesc array may not
+ * have been fully allocated yet.
+ */
+ if (fdp->fd_nfiles < lim)
+ freefd += (lim - fdp->fd_nfiles);
+
+ sbp->f_flags = 0;
+ sbp->f_bsize = DEV_BSIZE;
+ sbp->f_iosize = DEV_BSIZE;
+ sbp->f_blocks = 2; /* 1K to keep df happy */
+ sbp->f_bfree = 0;
+ sbp->f_bavail = 0;
+ sbp->f_files = lim + 1; /* Allow for "." */
+ sbp->f_ffree = freefd; /* See comments above */
+ if (sbp != &mp->mnt_stat) {
+ sbp->f_type = mp->mnt_vfc->vfc_typenum;
+ bcopy(&mp->mnt_stat.f_fsid, &sbp->f_fsid, sizeof(sbp->f_fsid));
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ return (0);
+}
+
+static int
+fdesc_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
+{
+
+ return (0);
+}
+
+#define fdesc_fhtovp ((int (*) __P((struct mount *, struct fid *, \
+ struct sockaddr *, struct vnode **, int *, struct ucred **)))eopnotsupp)
+#define fdesc_quotactl ((int (*) __P((struct mount *, int, uid_t, caddr_t, \
+ struct proc *)))eopnotsupp)
+#define fdesc_sysctl ((int (*) __P((int *, u_int, void *, size_t *, void *, \
+ size_t, struct proc *)))eopnotsupp)
+#define fdesc_vget ((int (*) __P((struct mount *, ino_t, struct vnode **))) \
+ eopnotsupp)
+#define fdesc_vptofh ((int (*) __P((struct vnode *, struct fid *)))eopnotsupp)
+
+static struct vfsops fdesc_vfsops = {
+ fdesc_mount,
+ fdesc_start,
+ fdesc_unmount,
+ fdesc_root,
+ fdesc_quotactl,
+ fdesc_statfs,
+ fdesc_sync,
+ fdesc_vget,
+ fdesc_fhtovp,
+ fdesc_vptofh,
+ fdesc_init,
+};
+
+VFS_SET(fdesc_vfsops, fdesc, VFCF_SYNTHETIC);
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
new file mode 100644
index 0000000..6bdea5f
--- /dev/null
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdesc_vnops.c 8.9 (Berkeley) 1/21/94
+ *
+ * $Id: fdesc_vnops.c,v 1.40 1998/12/14 05:00:57 dillon Exp $
+ */
+
+/*
+ * /dev/fd Filesystem
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kernel.h> /* boottime */
+#include <sys/filedesc.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/dirent.h>
+#include <sys/socketvar.h>
+#include <sys/conf.h>
+#include <miscfs/fdesc/fdesc.h>
+
+extern struct cdevsw ctty_cdevsw;
+
+#define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL)
+
+#define FDL_WANT 0x01
+#define FDL_LOCKED 0x02
+static int fdcache_lock;
+
+static vop_t **fdesc_vnodeop_p;
+
+dev_t devctty;
+
+#if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1)
+FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2
+#endif
+
+#define NFDCACHE 4
+#define FD_NHASH(ix) \
+ (&fdhashtbl[(ix) & fdhash])
+static LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl;
+static u_long fdhash;
+
+static int fdesc_attr __P((int fd, struct vattr *vap, struct ucred *cred,
+ struct proc *p));
+static int fdesc_badop __P((void));
+static int fdesc_getattr __P((struct vop_getattr_args *ap));
+static int fdesc_inactive __P((struct vop_inactive_args *ap));
+static int fdesc_ioctl __P((struct vop_ioctl_args *ap));
+static int fdesc_lookup __P((struct vop_lookup_args *ap));
+static int fdesc_open __P((struct vop_open_args *ap));
+static int fdesc_print __P((struct vop_print_args *ap));
+static int fdesc_read __P((struct vop_read_args *ap));
+static int fdesc_readdir __P((struct vop_readdir_args *ap));
+static int fdesc_readlink __P((struct vop_readlink_args *ap));
+static int fdesc_reclaim __P((struct vop_reclaim_args *ap));
+static int fdesc_poll __P((struct vop_poll_args *ap));
+static int fdesc_setattr __P((struct vop_setattr_args *ap));
+static int fdesc_write __P((struct vop_write_args *ap));
+
+/*
+ * Initialise cache headers
+ */
+int
+fdesc_init(vfsp)
+ struct vfsconf *vfsp;
+{
+
+ devctty = makedev(nchrdev, 0);
+ fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash);
+ return (0);
+}
+
+int
+fdesc_allocvp(ftype, ix, mp, vpp)
+ fdntype ftype;
+ int ix;
+ struct mount *mp;
+ struct vnode **vpp;
+{
+ struct proc *p = curproc; /* XXX */
+ struct fdhashhead *fc;
+ struct fdescnode *fd;
+ int error = 0;
+
+ fc = FD_NHASH(ix);
+loop:
+ for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) {
+ if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) {
+ if (vget(fd->fd_vnode, 0, p))
+ goto loop;
+ *vpp = fd->fd_vnode;
+ return (error);
+ }
+ }
+
+ /*
+ * otherwise lock the array while we call getnewvnode
+ * since that can block.
+ */
+ if (fdcache_lock & FDL_LOCKED) {
+ fdcache_lock |= FDL_WANT;
+ (void) tsleep((caddr_t) &fdcache_lock, PINOD, "fdalvp", 0);
+ goto loop;
+ }
+ fdcache_lock |= FDL_LOCKED;
+
+ /*
+ * Do the MALLOC before the getnewvnode since doing so afterward
+ * might cause a bogus v_data pointer to get dereferenced
+ * elsewhere if MALLOC should block.
+ */
+ MALLOC(fd, struct fdescnode *, sizeof(struct fdescnode), M_TEMP, M_WAITOK);
+
+ error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp);
+ if (error) {
+ FREE(fd, M_TEMP);
+ goto out;
+ }
+ (*vpp)->v_data = fd;
+ fd->fd_vnode = *vpp;
+ fd->fd_type = ftype;
+ fd->fd_fd = -1;
+ fd->fd_link = 0;
+ fd->fd_ix = ix;
+ LIST_INSERT_HEAD(fc, fd, fd_hash);
+
+out:;
+ fdcache_lock &= ~FDL_LOCKED;
+
+ if (fdcache_lock & FDL_WANT) {
+ fdcache_lock &= ~FDL_WANT;
+ wakeup((caddr_t) &fdcache_lock);
+ }
+
+ return (error);
+}
+
+/*
+ * vp is the current namei directory
+ * ndp is the name to locate in that directory...
+ */
+static int
+fdesc_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnode * a_dvp;
+ struct vnode ** a_vpp;
+ struct componentname * a_cnp;
+ } */ *ap;
+{
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+ char *pname = cnp->cn_nameptr;
+ struct proc *p = cnp->cn_proc;
+ int nfiles = p->p_fd->fd_nfiles;
+ unsigned fd = -1;
+ int error;
+ struct vnode *fvp;
+ char *ln;
+
+ if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
+ error = EROFS;
+ goto bad;
+ }
+
+ VOP_UNLOCK(dvp, 0, p);
+ if (cnp->cn_namelen == 1 && *pname == '.') {
+ *vpp = dvp;
+ VREF(dvp);
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ return (0);
+ }
+
+ switch (VTOFDESC(dvp)->fd_type) {
+ default:
+ case Flink:
+ case Fdesc:
+ case Fctty:
+ error = ENOTDIR;
+ goto bad;
+
+ case Froot:
+ if (cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) {
+ error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp);
+ if (error)
+ goto bad;
+ *vpp = fvp;
+ fvp->v_type = VDIR;
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
+ return (0);
+ }
+
+ if (cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) {
+ struct vnode *ttyvp = cttyvp(p);
+ if (ttyvp == NULL) {
+ error = ENXIO;
+ goto bad;
+ }
+ error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp);
+ if (error)
+ goto bad;
+ *vpp = fvp;
+ fvp->v_type = VFIFO;
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
+ return (0);
+ }
+
+ ln = 0;
+ switch (cnp->cn_namelen) {
+ case 5:
+ if (bcmp(pname, "stdin", 5) == 0) {
+ ln = "fd/0";
+ fd = FD_STDIN;
+ }
+ break;
+ case 6:
+ if (bcmp(pname, "stdout", 6) == 0) {
+ ln = "fd/1";
+ fd = FD_STDOUT;
+ } else
+ if (bcmp(pname, "stderr", 6) == 0) {
+ ln = "fd/2";
+ fd = FD_STDERR;
+ }
+ break;
+ }
+
+ if (ln) {
+ error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp);
+ if (error)
+ goto bad;
+ VTOFDESC(fvp)->fd_link = ln;
+ *vpp = fvp;
+ fvp->v_type = VLNK;
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
+ return (0);
+ } else {
+ error = ENOENT;
+ goto bad;
+ }
+
+ /* FALL THROUGH */
+
+ case Fdevfd:
+ if (cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) {
+ if ((error = fdesc_root(dvp->v_mount, vpp)) != 0)
+ goto bad;
+ return (0);
+ }
+
+ fd = 0;
+ while (*pname >= '0' && *pname <= '9') {
+ fd = 10 * fd + *pname++ - '0';
+ if (fd >= nfiles)
+ break;
+ }
+
+ if (*pname != '\0') {
+ error = ENOENT;
+ goto bad;
+ }
+
+ if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) {
+ error = EBADF;
+ goto bad;
+ }
+
+ error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp);
+ if (error)
+ goto bad;
+ VTOFDESC(fvp)->fd_fd = fd;
+ vn_lock(fvp, LK_SHARED | LK_RETRY, p);
+ *vpp = fvp;
+ return (0);
+ }
+
+bad:;
+ vn_lock(dvp, LK_SHARED | LK_RETRY, p);
+ *vpp = NULL;
+ return (error);
+}
+
+static int
+fdesc_open(ap)
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ int error = 0;
+
+ switch (VTOFDESC(vp)->fd_type) {
+ case Fdesc:
+ /*
+ * XXX Kludge: set p->p_dupfd to contain the value of the
+ * the file descriptor being sought for duplication. The error
+ * return ensures that the vnode for this device will be
+ * released by vn_open. Open will detect this special error and
+ * take the actions in dupfdopen. Other callers of vn_open or
+ * VOP_OPEN will simply report the error.
+ */
+ ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */
+ error = ENODEV;
+ break;
+
+ case Fctty:
+ error = (*ctty_cdevsw.d_open)(devctty, ap->a_mode, 0, ap->a_p);
+ break;
+ }
+
+ return (error);
+}
+
+static int
+fdesc_attr(fd, vap, cred, p)
+ int fd;
+ struct vattr *vap;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct file *fp;
+ struct stat stb;
+ int error;
+
+ if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL)
+ return (EBADF);
+
+ switch (fp->f_type) {
+ case DTYPE_FIFO:
+ case DTYPE_VNODE:
+ error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p);
+ if (error == 0 && vap->va_type == VDIR) {
+ /*
+ * directories can cause loops in the namespace,
+ * so turn off the 'x' bits to avoid trouble.
+ */
+ vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6));
+ }
+ break;
+
+ case DTYPE_SOCKET:
+ error = soo_stat((struct socket *)fp->f_data, &stb);
+ if (error == 0) {
+ vattr_null(vap);
+ vap->va_type = VSOCK;
+ vap->va_mode = stb.st_mode;
+ vap->va_nlink = stb.st_nlink;
+ vap->va_uid = stb.st_uid;
+ vap->va_gid = stb.st_gid;
+ vap->va_fsid = stb.st_dev;
+ vap->va_fileid = stb.st_ino;
+ vap->va_size = stb.st_size;
+ vap->va_blocksize = stb.st_blksize;
+ vap->va_atime = stb.st_atimespec;
+ vap->va_mtime = stb.st_mtimespec;
+ vap->va_ctime = stb.st_ctimespec;
+ vap->va_gen = stb.st_gen;
+ vap->va_flags = stb.st_flags;
+ vap->va_rdev = stb.st_rdev;
+ vap->va_bytes = stb.st_blocks * stb.st_blksize;
+ }
+ break;
+
+ default:
+ panic("fdesc attr");
+ break;
+ }
+
+ return (error);
+}
+
+static int
+fdesc_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct vattr *vap = ap->a_vap;
+ unsigned fd;
+ int error = 0;
+
+ switch (VTOFDESC(vp)->fd_type) {
+ case Froot:
+ case Fdevfd:
+ case Flink:
+ case Fctty:
+ bzero((caddr_t) vap, sizeof(*vap));
+ vattr_null(vap);
+ vap->va_fileid = VTOFDESC(vp)->fd_ix;
+
+ switch (VTOFDESC(vp)->fd_type) {
+ case Flink:
+ vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+ vap->va_type = VLNK;
+ vap->va_nlink = 1;
+ vap->va_size = strlen(VTOFDESC(vp)->fd_link);
+ break;
+
+ case Fctty:
+ vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+ vap->va_type = VFIFO;
+ vap->va_nlink = 1;
+ vap->va_size = 0;
+ break;
+
+ default:
+ vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+ vap->va_type = VDIR;
+ vap->va_nlink = 2;
+ vap->va_size = DEV_BSIZE;
+ break;
+ }
+ vap->va_uid = 0;
+ vap->va_gid = 0;
+ vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
+ vap->va_blocksize = DEV_BSIZE;
+ vap->va_atime.tv_sec = boottime.tv_sec;
+ vap->va_atime.tv_nsec = 0;
+ vap->va_mtime = vap->va_atime;
+ vap->va_ctime = vap->va_mtime;
+ vap->va_gen = 0;
+ vap->va_flags = 0;
+ vap->va_rdev = 0;
+ vap->va_bytes = 0;
+ break;
+
+ case Fdesc:
+ fd = VTOFDESC(vp)->fd_fd;
+ error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p);
+ break;
+
+ default:
+ panic("fdesc_getattr");
+ break;
+ }
+
+ if (error == 0)
+ vp->v_type = vap->va_type;
+
+ return (error);
+}
+
+static int
+fdesc_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct filedesc *fdp = ap->a_p->p_fd;
+ struct vattr *vap = ap->a_vap;
+ struct file *fp;
+ unsigned fd;
+ int error;
+
+ /*
+ * Can't mess with the root vnode
+ */
+ switch (VTOFDESC(ap->a_vp)->fd_type) {
+ case Fdesc:
+ break;
+
+ case Fctty:
+ if (vap->va_flags != VNOVAL)
+ return (EOPNOTSUPP);
+ return (0);
+
+ default:
+ return (EACCES);
+ }
+
+ fd = VTOFDESC(ap->a_vp)->fd_fd;
+ if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) {
+ return (EBADF);
+ }
+
+ /*
+ * Can setattr the underlying vnode, but not sockets!
+ */
+ switch (fp->f_type) {
+ case DTYPE_FIFO:
+ case DTYPE_PIPE:
+ case DTYPE_VNODE:
+ error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p);
+ break;
+
+ case DTYPE_SOCKET:
+ if (vap->va_flags != VNOVAL)
+ error = EOPNOTSUPP;
+ else
+ error = 0;
+ break;
+
+ default:
+ error = EBADF;
+ break;
+ }
+
+ return (error);
+}
+
+#define UIO_MX 16
+
+static struct dirtmp {
+ u_long d_fileno;
+ u_short d_reclen;
+ u_short d_namlen;
+ char d_name[8];
+} rootent[] = {
+ { FD_DEVFD, UIO_MX, 2, "fd" },
+ { FD_STDIN, UIO_MX, 5, "stdin" },
+ { FD_STDOUT, UIO_MX, 6, "stdout" },
+ { FD_STDERR, UIO_MX, 6, "stderr" },
+ { FD_CTTY, UIO_MX, 3, "tty" },
+};
+
+static int
+fdesc_readdir(ap)
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
+ } */ *ap;
+{
+ struct uio *uio = ap->a_uio;
+ struct filedesc *fdp;
+ int error, i, off;
+
+ /*
+ * We don't allow exporting fdesc mounts, and currently local
+ * requests do not need cookies.
+ */
+ if (ap->a_ncookies)
+ panic("fdesc_readdir: not hungry");
+
+ if (VTOFDESC(ap->a_vp)->fd_type != Froot &&
+ VTOFDESC(ap->a_vp)->fd_type != Fdevfd)
+ panic("fdesc_readdir: not dir");
+
+ off = (int)uio->uio_offset;
+ if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 ||
+ uio->uio_resid < UIO_MX)
+ return (EINVAL);
+ i = (u_int)off / UIO_MX;
+ fdp = uio->uio_procp->p_fd;
+
+ if (VTOFDESC(ap->a_vp)->fd_type == Froot) {
+ struct dirent d;
+ struct dirent *dp = &d;
+ struct dirtmp *dt;
+
+ error = 0;
+
+ while (i < sizeof(rootent) / sizeof(rootent[0]) &&
+ uio->uio_resid >= UIO_MX) {
+ dt = &rootent[i];
+ switch (dt->d_fileno) {
+ case FD_CTTY:
+ if (cttyvp(uio->uio_procp) == NULL)
+ continue;
+ break;
+
+ case FD_STDIN:
+ case FD_STDOUT:
+ case FD_STDERR:
+ if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles)
+ continue;
+ if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL)
+ continue;
+ break;
+ }
+ bzero((caddr_t) dp, UIO_MX);
+ dp->d_fileno = dt->d_fileno;
+ dp->d_namlen = dt->d_namlen;
+ dp->d_type = DT_UNKNOWN;
+ dp->d_reclen = dt->d_reclen;
+ bcopy(dt->d_name, dp->d_name, dp->d_namlen+1);
+ error = uiomove((caddr_t) dp, UIO_MX, uio);
+ if (error)
+ break;
+ i++;
+ }
+ uio->uio_offset = i * UIO_MX;
+ return (error);
+ }
+
+ error = 0;
+ while (i < fdp->fd_nfiles && uio->uio_resid >= UIO_MX) {
+ if (fdp->fd_ofiles[i] != NULL) {
+ struct dirent d;
+ struct dirent *dp = &d;
+
+ bzero((caddr_t) dp, UIO_MX);
+
+ dp->d_namlen = sprintf(dp->d_name, "%d", i);
+ dp->d_reclen = UIO_MX;
+ dp->d_type = DT_UNKNOWN;
+ dp->d_fileno = i + FD_STDIN;
+ /*
+ * And ship to userland
+ */
+ error = uiomove((caddr_t) dp, UIO_MX, uio);
+ if (error)
+ break;
+ }
+ i++;
+ }
+
+ uio->uio_offset = i * UIO_MX;
+ return (error);
+}
+
+static int
+fdesc_readlink(ap)
+ struct vop_readlink_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ int error;
+
+ if (vp->v_type != VLNK)
+ return (EPERM);
+
+ if (VTOFDESC(vp)->fd_type == Flink) {
+ char *ln = VTOFDESC(vp)->fd_link;
+ error = uiomove(ln, strlen(ln), ap->a_uio);
+ } else {
+ error = EOPNOTSUPP;
+ }
+
+ return (error);
+}
+
+static int
+fdesc_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ int error = EOPNOTSUPP;
+
+ switch (VTOFDESC(ap->a_vp)->fd_type) {
+ case Fctty:
+ error = (*ctty_cdevsw.d_read)(devctty, ap->a_uio, ap->a_ioflag);
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+fdesc_write(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ int error = EOPNOTSUPP;
+
+ switch (VTOFDESC(ap->a_vp)->fd_type) {
+ case Fctty:
+ error = (*ctty_cdevsw.d_write)(devctty, ap->a_uio, ap->a_ioflag);
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+fdesc_ioctl(ap)
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ int a_command;
+ caddr_t a_data;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ int error = EOPNOTSUPP;
+
+ switch (VTOFDESC(ap->a_vp)->fd_type) {
+ case Fctty:
+ error = (*ctty_cdevsw.d_ioctl)(devctty, ap->a_command,
+ ap->a_data, ap->a_fflag, ap->a_p);
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+static int
+fdesc_poll(ap)
+ struct vop_poll_args /* {
+ struct vnode *a_vp;
+ int a_events;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ int revents;
+
+ switch (VTOFDESC(ap->a_vp)->fd_type) {
+ case Fctty:
+ revents = (*ctty_cdevsw.d_poll)(devctty, ap->a_events, ap->a_p);
+ break;
+
+ default:
+ revents = seltrue(0, ap->a_events, ap->a_p);
+ break;
+ }
+
+ return (revents);
+}
+
+static int
+fdesc_inactive(ap)
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ /*
+ * Clear out the v_type field to avoid
+ * nasty things happening in vgone().
+ */
+ VOP_UNLOCK(vp, 0, ap->a_p);
+ vp->v_type = VNON;
+ return (0);
+}
+
+static int
+fdesc_reclaim(ap)
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct fdescnode *fd = VTOFDESC(vp);
+
+ LIST_REMOVE(fd, fd_hash);
+ FREE(vp->v_data, M_TEMP);
+ vp->v_data = 0;
+
+ return (0);
+}
+
+/*
+ * Print out the contents of a /dev/fd vnode.
+ */
+/* ARGSUSED */
+static int
+fdesc_print(ap)
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+
+ printf("tag VT_NON, fdesc vnode\n");
+ return (0);
+}
+
+/*
+ * /dev/fd "should never get here" operation
+ */
+static int
+fdesc_badop()
+{
+
+ panic("fdesc: bad op");
+ /* NOTREACHED */
+}
+
+static struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) vop_defaultop },
+ { &vop_access_desc, (vop_t *) vop_null },
+ { &vop_bmap_desc, (vop_t *) fdesc_badop },
+ { &vop_getattr_desc, (vop_t *) fdesc_getattr },
+ { &vop_inactive_desc, (vop_t *) fdesc_inactive },
+ { &vop_ioctl_desc, (vop_t *) fdesc_ioctl },
+ { &vop_lookup_desc, (vop_t *) fdesc_lookup },
+ { &vop_open_desc, (vop_t *) fdesc_open },
+ { &vop_pathconf_desc, (vop_t *) vop_stdpathconf },
+ { &vop_poll_desc, (vop_t *) fdesc_poll },
+ { &vop_print_desc, (vop_t *) fdesc_print },
+ { &vop_read_desc, (vop_t *) fdesc_read },
+ { &vop_readdir_desc, (vop_t *) fdesc_readdir },
+ { &vop_readlink_desc, (vop_t *) fdesc_readlink },
+ { &vop_reclaim_desc, (vop_t *) fdesc_reclaim },
+ { &vop_setattr_desc, (vop_t *) fdesc_setattr },
+ { &vop_write_desc, (vop_t *) fdesc_write },
+ { NULL, NULL }
+};
+static struct vnodeopv_desc fdesc_vnodeop_opv_desc =
+ { &fdesc_vnodeop_p, fdesc_vnodeop_entries };
+
+VNODEOP_SET(fdesc_vnodeop_opv_desc);
OpenPOWER on IntegriCloud