153838Spendry /* 263557Sbostic * Copyright (c) 1992, 1993 363557Sbostic * The Regents of the University of California. All rights reserved. 453838Spendry * 553838Spendry * This code is derived from software donated to Berkeley by 653838Spendry * Jan-Simon Pendry. 753838Spendry * 853838Spendry * %sccs.include.redist.c% 953838Spendry * 10*68729Smckusick * @(#)fdesc_vnops.c 8.14 (Berkeley) 04/03/95 1153838Spendry * 1259255Spendry * $Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp $ 1353838Spendry */ 1453838Spendry 1553838Spendry /* 1653838Spendry * /dev/fd Filesystem 1753838Spendry */ 1853838Spendry 1953838Spendry #include <sys/param.h> 2053838Spendry #include <sys/systm.h> 2153838Spendry #include <sys/types.h> 2253838Spendry #include <sys/time.h> 2353838Spendry #include <sys/proc.h> 2459255Spendry #include <sys/kernel.h> /* boottime */ 2553838Spendry #include <sys/resourcevar.h> 2653838Spendry #include <sys/filedesc.h> 2753838Spendry #include <sys/vnode.h> 2853838Spendry #include <sys/malloc.h> 2953838Spendry #include <sys/file.h> 3053838Spendry #include <sys/stat.h> 3153838Spendry #include <sys/mount.h> 3253838Spendry #include <sys/namei.h> 3353838Spendry #include <sys/buf.h> 3454981Spendry #include <sys/dirent.h> 3555017Smckusick #include <miscfs/fdesc/fdesc.h> 3653838Spendry 3764629Sbostic #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 3859255Spendry 3959255Spendry #define FDL_WANT 0x01 4059255Spendry #define FDL_LOCKED 0x02 4165513Spendry static int fdcache_lock; 4259255Spendry 4365513Spendry dev_t devctty; 4465513Spendry 4559255Spendry #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) 4659255Spendry FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 4759255Spendry #endif 4859255Spendry 4967715Smckusick #define NFDCACHE 4 5065513Spendry 5167715Smckusick #define FD_NHASH(ix) \ 5267715Smckusick (&fdhashtbl[(ix) & fdhash]) 5367715Smckusick LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; 5467715Smckusick u_long fdhash; 5565513Spendry 5665513Spendry /* 5765513Spendry * Initialise cache headers 5865513Spendry */ 5968616Smckusick fdesc_init(vfsp) 6068616Smckusick struct vfsconf *vfsp; 6165513Spendry { 6265513Spendry 6365513Spendry devctty = makedev(nchrdev, 0); 6467715Smckusick fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); 6565513Spendry } 6665513Spendry 6765513Spendry int 6859255Spendry fdesc_allocvp(ftype, ix, mp, vpp) 6959255Spendry fdntype ftype; 7059255Spendry int ix; 7159255Spendry struct mount *mp; 7259255Spendry struct vnode **vpp; 7359255Spendry { 7467715Smckusick struct fdhashhead *fc; 7565513Spendry struct fdescnode *fd; 7659255Spendry int error = 0; 7759255Spendry 7867715Smckusick fc = FD_NHASH(ix); 7959457Spendry loop: 8067715Smckusick for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { 8165513Spendry if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 8265513Spendry if (vget(fd->fd_vnode, 0)) 8359457Spendry goto loop; 8465513Spendry *vpp = fd->fd_vnode; 8559255Spendry return (error); 8659255Spendry } 8759255Spendry } 8859255Spendry 8959255Spendry /* 9059255Spendry * otherwise lock the array while we call getnewvnode 9159255Spendry * since that can block. 9259255Spendry */ 9365513Spendry if (fdcache_lock & FDL_LOCKED) { 9465513Spendry fdcache_lock |= FDL_WANT; 9565513Spendry sleep((caddr_t) &fdcache_lock, PINOD); 9659457Spendry goto loop; 9759255Spendry } 9865513Spendry fdcache_lock |= FDL_LOCKED; 9959255Spendry 10065380Spendry error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); 10159255Spendry if (error) 10259255Spendry goto out; 10365513Spendry MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); 10465513Spendry (*vpp)->v_data = fd; 10565513Spendry fd->fd_vnode = *vpp; 10665513Spendry fd->fd_type = ftype; 10765513Spendry fd->fd_fd = -1; 10865513Spendry fd->fd_link = 0; 10965513Spendry fd->fd_ix = ix; 11067715Smckusick LIST_INSERT_HEAD(fc, fd, fd_hash); 11159255Spendry 11259255Spendry out:; 11365513Spendry fdcache_lock &= ~FDL_LOCKED; 11459255Spendry 11565513Spendry if (fdcache_lock & FDL_WANT) { 11665513Spendry fdcache_lock &= ~FDL_WANT; 11765513Spendry wakeup((caddr_t) &fdcache_lock); 11859255Spendry } 11959255Spendry 12059255Spendry return (error); 12159255Spendry } 12259255Spendry 12353838Spendry /* 12453838Spendry * vp is the current namei directory 12553838Spendry * ndp is the name to locate in that directory... 12653838Spendry */ 12765513Spendry int 12855017Smckusick fdesc_lookup(ap) 12955017Smckusick struct vop_lookup_args /* { 13055017Smckusick struct vnode * a_dvp; 13155017Smckusick struct vnode ** a_vpp; 13255017Smckusick struct componentname * a_cnp; 13355017Smckusick } */ *ap; 13453838Spendry { 13554049Spendry struct vnode **vpp = ap->a_vpp; 13654049Spendry struct vnode *dvp = ap->a_dvp; 13753838Spendry char *pname; 13853838Spendry struct proc *p; 13953838Spendry int nfiles; 14053838Spendry unsigned fd; 14153838Spendry int error; 14253838Spendry struct vnode *fvp; 14359255Spendry char *ln; 14453838Spendry 14553838Spendry pname = ap->a_cnp->cn_nameptr; 14653838Spendry if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { 14754049Spendry *vpp = dvp; 14854049Spendry VREF(dvp); 14959255Spendry VOP_LOCK(dvp); 15053838Spendry return (0); 15153838Spendry } 15253838Spendry 15353838Spendry p = ap->a_cnp->cn_proc; 15453838Spendry nfiles = p->p_fd->fd_nfiles; 15553838Spendry 15659255Spendry switch (VTOFDESC(dvp)->fd_type) { 15759255Spendry default: 15859255Spendry case Flink: 15959255Spendry case Fdesc: 16059255Spendry case Fctty: 16159255Spendry error = ENOTDIR; 16259255Spendry goto bad; 16359255Spendry 16459255Spendry case Froot: 16559255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { 16659255Spendry error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); 16759255Spendry if (error) 16859255Spendry goto bad; 16959255Spendry *vpp = fvp; 17059255Spendry fvp->v_type = VDIR; 17159255Spendry VOP_LOCK(fvp); 17259255Spendry return (0); 17359255Spendry } 17459255Spendry 17559255Spendry if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { 17659255Spendry struct vnode *ttyvp = cttyvp(p); 17759255Spendry if (ttyvp == NULL) { 17859255Spendry error = ENXIO; 17959255Spendry goto bad; 18059255Spendry } 18159255Spendry error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); 18259255Spendry if (error) 18359255Spendry goto bad; 18459255Spendry *vpp = fvp; 18559255Spendry fvp->v_type = VFIFO; 18659255Spendry VOP_LOCK(fvp); 18759255Spendry return (0); 18859255Spendry } 18959255Spendry 19059255Spendry ln = 0; 19159255Spendry switch (ap->a_cnp->cn_namelen) { 19259255Spendry case 5: 19359255Spendry if (bcmp(pname, "stdin", 5) == 0) { 19459255Spendry ln = "fd/0"; 19559255Spendry fd = FD_STDIN; 19659255Spendry } 19753838Spendry break; 19859255Spendry case 6: 19959255Spendry if (bcmp(pname, "stdout", 6) == 0) { 20059255Spendry ln = "fd/1"; 20159255Spendry fd = FD_STDOUT; 20259255Spendry } else 20359255Spendry if (bcmp(pname, "stderr", 6) == 0) { 20459255Spendry ln = "fd/2"; 20559255Spendry fd = FD_STDERR; 20659255Spendry } 20759255Spendry break; 20859255Spendry } 20953838Spendry 21059255Spendry if (ln) { 21159255Spendry error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp); 21259255Spendry if (error) 21359255Spendry goto bad; 21459255Spendry VTOFDESC(fvp)->fd_link = ln; 21559255Spendry *vpp = fvp; 21659255Spendry fvp->v_type = VLNK; 21759255Spendry VOP_LOCK(fvp); 21859255Spendry return (0); 21959255Spendry } else { 22059255Spendry error = ENOENT; 22159255Spendry goto bad; 22259255Spendry } 22353838Spendry 22465513Spendry /* FALL THROUGH */ 22553838Spendry 22659255Spendry case Fdevfd: 22759255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { 22859255Spendry error = fdesc_root(dvp->v_mount, vpp); 22959255Spendry return (error); 23059255Spendry } 23159255Spendry 23259255Spendry fd = 0; 23359255Spendry while (*pname >= '0' && *pname <= '9') { 23459255Spendry fd = 10 * fd + *pname++ - '0'; 23559255Spendry if (fd >= nfiles) 23659255Spendry break; 23759255Spendry } 23859255Spendry 23959255Spendry if (*pname != '\0') { 24059255Spendry error = ENOENT; 24159255Spendry goto bad; 24259255Spendry } 24359255Spendry 24459255Spendry if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 24559255Spendry error = EBADF; 24659255Spendry goto bad; 24759255Spendry } 24859255Spendry 24959255Spendry error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp); 25059255Spendry if (error) 25159255Spendry goto bad; 25259255Spendry VTOFDESC(fvp)->fd_fd = fd; 25359255Spendry *vpp = fvp; 25459255Spendry return (0); 25559255Spendry } 25653838Spendry 25753838Spendry bad:; 25854049Spendry *vpp = NULL; 25953838Spendry return (error); 26053838Spendry } 26153838Spendry 26265513Spendry int 26355017Smckusick fdesc_open(ap) 26455017Smckusick struct vop_open_args /* { 26555017Smckusick struct vnode *a_vp; 26655017Smckusick int a_mode; 26755017Smckusick struct ucred *a_cred; 26855017Smckusick struct proc *a_p; 26955017Smckusick } */ *ap; 27053838Spendry { 27154049Spendry struct vnode *vp = ap->a_vp; 27259255Spendry int error = 0; 27354049Spendry 27459255Spendry switch (VTOFDESC(vp)->fd_type) { 27559255Spendry case Fdesc: 27659255Spendry /* 27759255Spendry * XXX Kludge: set p->p_dupfd to contain the value of the 27859255Spendry * the file descriptor being sought for duplication. The error 27959255Spendry * return ensures that the vnode for this device will be 28059255Spendry * released by vn_open. Open will detect this special error and 28159255Spendry * take the actions in dupfdopen. Other callers of vn_open or 28259255Spendry * VOP_OPEN will simply report the error. 28359255Spendry */ 28459255Spendry ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 28559255Spendry error = ENODEV; 28659255Spendry break; 28753838Spendry 28859255Spendry case Fctty: 28959255Spendry error = cttyopen(devctty, ap->a_mode, 0, ap->a_p); 29059255Spendry break; 29159255Spendry } 29259255Spendry 29359255Spendry return (error); 29453838Spendry } 29553838Spendry 29653838Spendry static int 29753838Spendry fdesc_attr(fd, vap, cred, p) 29853838Spendry int fd; 29953838Spendry struct vattr *vap; 30053838Spendry struct ucred *cred; 30153838Spendry struct proc *p; 30253838Spendry { 30353838Spendry struct filedesc *fdp = p->p_fd; 30453838Spendry struct file *fp; 30559562Spendry struct stat stb; 30653838Spendry int error; 30753838Spendry 30865513Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) 30953838Spendry return (EBADF); 31053838Spendry 31153838Spendry switch (fp->f_type) { 31253838Spendry case DTYPE_VNODE: 31353838Spendry error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 31459561Spendry if (error == 0 && vap->va_type == VDIR) { 31559561Spendry /* 31667542Spendry * directories can cause loops in the namespace, 31767542Spendry * so turn off the 'x' bits to avoid trouble. 31859561Spendry */ 31967542Spendry vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6)); 32059561Spendry } 32153838Spendry break; 32253838Spendry 32353838Spendry case DTYPE_SOCKET: 32459562Spendry error = soo_stat((struct socket *)fp->f_data, &stb); 32559562Spendry if (error == 0) { 32659562Spendry vattr_null(vap); 32759562Spendry vap->va_type = VSOCK; 32859562Spendry vap->va_mode = stb.st_mode; 32959562Spendry vap->va_nlink = stb.st_nlink; 33059562Spendry vap->va_uid = stb.st_uid; 33159562Spendry vap->va_gid = stb.st_gid; 33259562Spendry vap->va_fsid = stb.st_dev; 33359562Spendry vap->va_fileid = stb.st_ino; 33459562Spendry vap->va_size = stb.st_size; 33559562Spendry vap->va_blocksize = stb.st_blksize; 33659562Spendry vap->va_atime = stb.st_atimespec; 33759562Spendry vap->va_mtime = stb.st_mtimespec; 33859562Spendry vap->va_ctime = stb.st_ctimespec; 33959562Spendry vap->va_gen = stb.st_gen; 34059562Spendry vap->va_flags = stb.st_flags; 34159562Spendry vap->va_rdev = stb.st_rdev; 34259562Spendry vap->va_bytes = stb.st_blocks * stb.st_blksize; 34359562Spendry } 34453838Spendry break; 34553838Spendry 34653838Spendry default: 34753838Spendry panic("fdesc attr"); 34853838Spendry break; 34953838Spendry } 35053838Spendry 35153838Spendry return (error); 35253838Spendry } 35353838Spendry 35465513Spendry int 35555017Smckusick fdesc_getattr(ap) 35655017Smckusick struct vop_getattr_args /* { 35755017Smckusick struct vnode *a_vp; 35855017Smckusick struct vattr *a_vap; 35955017Smckusick struct ucred *a_cred; 36055017Smckusick struct proc *a_p; 36155017Smckusick } */ *ap; 36253838Spendry { 36354049Spendry struct vnode *vp = ap->a_vp; 36454049Spendry struct vattr *vap = ap->a_vap; 36553838Spendry unsigned fd; 36663556Smckusick int error = 0; 36753838Spendry 36859255Spendry switch (VTOFDESC(vp)->fd_type) { 36959255Spendry case Froot: 37059255Spendry case Fdevfd: 37159255Spendry case Flink: 37259255Spendry case Fctty: 37354049Spendry bzero((caddr_t) vap, sizeof(*vap)); 37454049Spendry vattr_null(vap); 37559255Spendry vap->va_fileid = VTOFDESC(vp)->fd_ix; 37659255Spendry 37759255Spendry switch (VTOFDESC(vp)->fd_type) { 37859255Spendry case Flink: 37959255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 38059255Spendry vap->va_type = VLNK; 38159255Spendry vap->va_nlink = 1; 38259255Spendry vap->va_size = strlen(VTOFDESC(vp)->fd_link); 38359255Spendry break; 38459255Spendry 38559255Spendry case Fctty: 38659255Spendry vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 38759255Spendry vap->va_type = VFIFO; 38859255Spendry vap->va_nlink = 1; 38959255Spendry vap->va_size = 0; 39059255Spendry break; 39159255Spendry 39259255Spendry default: 39359255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 39459255Spendry vap->va_type = VDIR; 39559255Spendry vap->va_nlink = 2; 39659255Spendry vap->va_size = DEV_BSIZE; 39759255Spendry break; 39859255Spendry } 39954049Spendry vap->va_uid = 0; 40054049Spendry vap->va_gid = 0; 40154049Spendry vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 40254049Spendry vap->va_blocksize = DEV_BSIZE; 40359255Spendry vap->va_atime.ts_sec = boottime.tv_sec; 40459255Spendry vap->va_atime.ts_nsec = 0; 40554049Spendry vap->va_mtime = vap->va_atime; 40664276Smckusick vap->va_ctime = vap->va_mtime; 40754049Spendry vap->va_gen = 0; 40854049Spendry vap->va_flags = 0; 40954049Spendry vap->va_rdev = 0; 41054049Spendry vap->va_bytes = 0; 41159255Spendry break; 41259255Spendry 41359255Spendry case Fdesc: 41459255Spendry fd = VTOFDESC(vp)->fd_fd; 41559255Spendry error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); 41659255Spendry break; 41759255Spendry 41859255Spendry default: 41959255Spendry panic("fdesc_getattr"); 42059255Spendry break; 42153838Spendry } 42253838Spendry 42353838Spendry if (error == 0) 42454049Spendry vp->v_type = vap->va_type; 42559255Spendry 42653838Spendry return (error); 42753838Spendry } 42853838Spendry 42965513Spendry int 43055017Smckusick fdesc_setattr(ap) 43155017Smckusick struct vop_setattr_args /* { 43255017Smckusick struct vnode *a_vp; 43355017Smckusick struct vattr *a_vap; 43455017Smckusick struct ucred *a_cred; 43555017Smckusick struct proc *a_p; 43655017Smckusick } */ *ap; 43753838Spendry { 43853838Spendry struct filedesc *fdp = ap->a_p->p_fd; 43953838Spendry struct file *fp; 44053838Spendry unsigned fd; 44153838Spendry int error; 44253838Spendry 44353838Spendry /* 44453838Spendry * Can't mess with the root vnode 44553838Spendry */ 44659255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 44759255Spendry case Fdesc: 44859255Spendry break; 44959255Spendry 45059255Spendry case Fctty: 45159255Spendry return (0); 45259255Spendry 45359255Spendry default: 45453838Spendry return (EACCES); 45559255Spendry } 45653838Spendry 45759255Spendry fd = VTOFDESC(ap->a_vp)->fd_fd; 45853838Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 45953838Spendry return (EBADF); 46053838Spendry } 46153838Spendry 46253838Spendry /* 46353838Spendry * Can setattr the underlying vnode, but not sockets! 46453838Spendry */ 46553838Spendry switch (fp->f_type) { 46653838Spendry case DTYPE_VNODE: 46753838Spendry error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); 46853838Spendry break; 46953838Spendry 47053838Spendry case DTYPE_SOCKET: 47158646Spendry error = 0; 47253838Spendry break; 47353838Spendry 47453838Spendry default: 47553838Spendry panic("fdesc setattr"); 47653838Spendry break; 47753838Spendry } 47853838Spendry 47953838Spendry return (error); 48053838Spendry } 48153838Spendry 48259255Spendry #define UIO_MX 16 48359255Spendry 48459255Spendry static struct dirtmp { 48559255Spendry u_long d_fileno; 48659255Spendry u_short d_reclen; 48759255Spendry u_short d_namlen; 48859255Spendry char d_name[8]; 48959255Spendry } rootent[] = { 49059255Spendry { FD_DEVFD, UIO_MX, 2, "fd" }, 49159255Spendry { FD_STDIN, UIO_MX, 5, "stdin" }, 49259255Spendry { FD_STDOUT, UIO_MX, 6, "stdout" }, 49359255Spendry { FD_STDERR, UIO_MX, 6, "stderr" }, 49459255Spendry { FD_CTTY, UIO_MX, 3, "tty" }, 49559255Spendry { 0 } 49659255Spendry }; 49759255Spendry 49865513Spendry int 49955017Smckusick fdesc_readdir(ap) 50055017Smckusick struct vop_readdir_args /* { 50155017Smckusick struct vnode *a_vp; 50255017Smckusick struct uio *a_uio; 50355017Smckusick struct ucred *a_cred; 50467364Smckusick int *a_eofflag; 50567364Smckusick u_long *a_cookies; 50667364Smckusick int a_ncookies; 50755017Smckusick } */ *ap; 50853838Spendry { 50954049Spendry struct uio *uio = ap->a_uio; 51053838Spendry struct filedesc *fdp; 51153838Spendry int i; 51253838Spendry int error; 51353838Spendry 51467364Smckusick /* 51567364Smckusick * We don't allow exporting fdesc mounts, and currently local 51667364Smckusick * requests do not need cookies. 51767364Smckusick */ 51867364Smckusick if (ap->a_ncookies) 51967364Smckusick panic("fdesc_readdir: not hungry"); 52067364Smckusick 52159255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 52259255Spendry case Fctty: 52359255Spendry return (0); 52453838Spendry 52559255Spendry case Fdesc: 52659255Spendry return (ENOTDIR); 52759255Spendry 52859255Spendry default: 52959255Spendry break; 53059255Spendry } 53159255Spendry 53254049Spendry fdp = uio->uio_procp->p_fd; 53359255Spendry 53459255Spendry if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 53559255Spendry struct dirent d; 53659255Spendry struct dirent *dp = &d; 53759255Spendry struct dirtmp *dt; 53859255Spendry 53959255Spendry i = uio->uio_offset / UIO_MX; 54059255Spendry error = 0; 54159255Spendry 54259255Spendry while (uio->uio_resid > 0) { 54359255Spendry dt = &rootent[i]; 54459255Spendry if (dt->d_fileno == 0) { 54559255Spendry /**eofflagp = 1;*/ 54659255Spendry break; 54759255Spendry } 54859255Spendry i++; 54959255Spendry 55059255Spendry switch (dt->d_fileno) { 55159255Spendry case FD_CTTY: 55259255Spendry if (cttyvp(uio->uio_procp) == NULL) 55359255Spendry continue; 55459255Spendry break; 55559255Spendry 55659255Spendry case FD_STDIN: 55759255Spendry case FD_STDOUT: 55859255Spendry case FD_STDERR: 55964276Smckusick if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles) 56059255Spendry continue; 56164276Smckusick if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL) 56259255Spendry continue; 56359255Spendry break; 56459255Spendry } 56564276Smckusick bzero((caddr_t) dp, UIO_MX); 56659255Spendry dp->d_fileno = dt->d_fileno; 56759255Spendry dp->d_namlen = dt->d_namlen; 56859255Spendry dp->d_type = DT_UNKNOWN; 56959255Spendry dp->d_reclen = dt->d_reclen; 57059255Spendry bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); 57159255Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 57259255Spendry if (error) 57359255Spendry break; 57459255Spendry } 57559255Spendry uio->uio_offset = i * UIO_MX; 57659255Spendry return (error); 57759255Spendry } 57859255Spendry 57954049Spendry i = uio->uio_offset / UIO_MX; 58053838Spendry error = 0; 58154049Spendry while (uio->uio_resid > 0) { 58265513Spendry if (i >= fdp->fd_nfiles) 58353838Spendry break; 58465513Spendry 58553838Spendry if (fdp->fd_ofiles[i] != NULL) { 58654981Spendry struct dirent d; 58754981Spendry struct dirent *dp = &d; 58865513Spendry 58953838Spendry bzero((caddr_t) dp, UIO_MX); 59053838Spendry 59153838Spendry dp->d_namlen = sprintf(dp->d_name, "%d", i); 59253838Spendry dp->d_reclen = UIO_MX; 59354981Spendry dp->d_type = DT_UNKNOWN; 59459255Spendry dp->d_fileno = i + FD_STDIN; 59553838Spendry /* 59653838Spendry * And ship to userland 59753838Spendry */ 59854049Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 59953838Spendry if (error) 60053838Spendry break; 60153838Spendry } 60253838Spendry i++; 60353838Spendry } 60453838Spendry 60554049Spendry uio->uio_offset = i * UIO_MX; 60653838Spendry return (error); 60753838Spendry } 60853838Spendry 60959255Spendry int 61059255Spendry fdesc_readlink(ap) 61159255Spendry struct vop_readlink_args /* { 61259255Spendry struct vnode *a_vp; 61359255Spendry struct uio *a_uio; 61459255Spendry struct ucred *a_cred; 61559255Spendry } */ *ap; 61659255Spendry { 61765513Spendry struct vnode *vp = ap->a_vp; 61859255Spendry int error; 61959255Spendry 62059255Spendry if (vp->v_type != VLNK) 62159255Spendry return (EPERM); 62259255Spendry 62359255Spendry if (VTOFDESC(vp)->fd_type == Flink) { 62459255Spendry char *ln = VTOFDESC(vp)->fd_link; 62559255Spendry error = uiomove(ln, strlen(ln), ap->a_uio); 62659255Spendry } else { 62759255Spendry error = EOPNOTSUPP; 62859255Spendry } 62959255Spendry 63059255Spendry return (error); 63159255Spendry } 63259255Spendry 63365513Spendry int 63459255Spendry fdesc_read(ap) 63559255Spendry struct vop_read_args /* { 63659255Spendry struct vnode *a_vp; 63759255Spendry struct uio *a_uio; 63859255Spendry int a_ioflag; 63959255Spendry struct ucred *a_cred; 64059255Spendry } */ *ap; 64159255Spendry { 64259255Spendry int error = EOPNOTSUPP; 64359255Spendry 64459255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 64559255Spendry case Fctty: 64659255Spendry error = cttyread(devctty, ap->a_uio, ap->a_ioflag); 64759255Spendry break; 64859255Spendry 64959255Spendry default: 65059255Spendry error = EOPNOTSUPP; 65159255Spendry break; 65259255Spendry } 65359255Spendry 65459255Spendry return (error); 65559255Spendry } 65659255Spendry 65765513Spendry int 65859255Spendry fdesc_write(ap) 65959255Spendry struct vop_write_args /* { 66059255Spendry struct vnode *a_vp; 66159255Spendry struct uio *a_uio; 66259255Spendry int a_ioflag; 66359255Spendry struct ucred *a_cred; 66459255Spendry } */ *ap; 66559255Spendry { 66659255Spendry int error = EOPNOTSUPP; 66759255Spendry 66859255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 66959255Spendry case Fctty: 67059255Spendry error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); 67159255Spendry break; 67259255Spendry 67359255Spendry default: 67459255Spendry error = EOPNOTSUPP; 67559255Spendry break; 67659255Spendry } 67759255Spendry 67859255Spendry return (error); 67959255Spendry } 68059255Spendry 68165513Spendry int 68259255Spendry fdesc_ioctl(ap) 68359255Spendry struct vop_ioctl_args /* { 68459255Spendry struct vnode *a_vp; 68559255Spendry int a_command; 68659255Spendry caddr_t a_data; 68759255Spendry int a_fflag; 68859255Spendry struct ucred *a_cred; 68959255Spendry struct proc *a_p; 69059255Spendry } */ *ap; 69159255Spendry { 69259255Spendry int error = EOPNOTSUPP; 69359255Spendry 69459255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 69559255Spendry case Fctty: 69659255Spendry error = cttyioctl(devctty, ap->a_command, ap->a_data, 69759255Spendry ap->a_fflag, ap->a_p); 69859255Spendry break; 69959255Spendry 70059255Spendry default: 70159255Spendry error = EOPNOTSUPP; 70259255Spendry break; 70359255Spendry } 70459255Spendry 70559255Spendry return (error); 70659255Spendry } 70759255Spendry 70865513Spendry int 70959255Spendry fdesc_select(ap) 71059255Spendry struct vop_select_args /* { 71159255Spendry struct vnode *a_vp; 71259255Spendry int a_which; 71359255Spendry int a_fflags; 71459255Spendry struct ucred *a_cred; 71559255Spendry struct proc *a_p; 71659255Spendry } */ *ap; 71759255Spendry { 71859255Spendry int error = EOPNOTSUPP; 71959255Spendry 72059255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 72159255Spendry case Fctty: 72259255Spendry error = cttyselect(devctty, ap->a_fflags, ap->a_p); 72359255Spendry break; 72459255Spendry 72559255Spendry default: 72659255Spendry error = EOPNOTSUPP; 72759255Spendry break; 72859255Spendry } 72959255Spendry 73059255Spendry return (error); 73159255Spendry } 73259255Spendry 73365513Spendry int 73455017Smckusick fdesc_inactive(ap) 73555017Smckusick struct vop_inactive_args /* { 73655017Smckusick struct vnode *a_vp; 73755017Smckusick } */ *ap; 73853838Spendry { 73954049Spendry struct vnode *vp = ap->a_vp; 74054049Spendry 74153838Spendry /* 74253838Spendry * Clear out the v_type field to avoid 74353838Spendry * nasty things happening in vgone(). 74453838Spendry */ 74554049Spendry vp->v_type = VNON; 74653838Spendry return (0); 74753838Spendry } 74853838Spendry 74965513Spendry int 75055017Smckusick fdesc_reclaim(ap) 75155017Smckusick struct vop_reclaim_args /* { 75255017Smckusick struct vnode *a_vp; 75355017Smckusick } */ *ap; 75453838Spendry { 75553838Spendry struct vnode *vp = ap->a_vp; 75667715Smckusick struct fdescnode *fd = VTOFDESC(vp); 75759255Spendry 75867715Smckusick LIST_REMOVE(fd, fd_hash); 75965513Spendry FREE(vp->v_data, M_TEMP); 76065513Spendry vp->v_data = 0; 76165513Spendry 76253838Spendry return (0); 76353838Spendry } 76453838Spendry 76553838Spendry /* 76665743Spendry * Return POSIX pathconf information applicable to special devices. 76765743Spendry */ 76865743Spendry fdesc_pathconf(ap) 76965743Spendry struct vop_pathconf_args /* { 77065743Spendry struct vnode *a_vp; 77165743Spendry int a_name; 77265743Spendry int *a_retval; 77365743Spendry } */ *ap; 77465743Spendry { 77565743Spendry 77665743Spendry switch (ap->a_name) { 77765743Spendry case _PC_LINK_MAX: 77865743Spendry *ap->a_retval = LINK_MAX; 77965743Spendry return (0); 78065743Spendry case _PC_MAX_CANON: 78165743Spendry *ap->a_retval = MAX_CANON; 78265743Spendry return (0); 78365743Spendry case _PC_MAX_INPUT: 78465743Spendry *ap->a_retval = MAX_INPUT; 78565743Spendry return (0); 78665743Spendry case _PC_PIPE_BUF: 78765743Spendry *ap->a_retval = PIPE_BUF; 78865743Spendry return (0); 78965743Spendry case _PC_CHOWN_RESTRICTED: 79065743Spendry *ap->a_retval = 1; 79165743Spendry return (0); 79265743Spendry case _PC_VDISABLE: 79365743Spendry *ap->a_retval = _POSIX_VDISABLE; 79465743Spendry return (0); 79565743Spendry default: 79665743Spendry return (EINVAL); 79765743Spendry } 79865743Spendry /* NOTREACHED */ 79965743Spendry } 80065743Spendry 80165743Spendry /* 80253838Spendry * Print out the contents of a /dev/fd vnode. 80353838Spendry */ 80453838Spendry /* ARGSUSED */ 80565513Spendry int 80655017Smckusick fdesc_print(ap) 80755017Smckusick struct vop_print_args /* { 80855017Smckusick struct vnode *a_vp; 80955017Smckusick } */ *ap; 81053838Spendry { 81155017Smckusick 81253838Spendry printf("tag VT_NON, fdesc vnode\n"); 81355017Smckusick return (0); 81453838Spendry } 81553838Spendry 81653838Spendry /*void*/ 81765513Spendry int 81855017Smckusick fdesc_vfree(ap) 81955017Smckusick struct vop_vfree_args /* { 82055017Smckusick struct vnode *a_pvp; 82155017Smckusick ino_t a_ino; 82255017Smckusick int a_mode; 82355017Smckusick } */ *ap; 82453838Spendry { 82553838Spendry 82655017Smckusick return (0); 82753838Spendry } 82853838Spendry 82953838Spendry /* 83053838Spendry * /dev/fd "should never get here" operation 83153838Spendry */ 83265513Spendry int 83353838Spendry fdesc_badop() 83453838Spendry { 83555017Smckusick 83653838Spendry panic("fdesc: bad op"); 83753838Spendry /* NOTREACHED */ 83853838Spendry } 83953838Spendry 84068616Smckusick #define fdesc_create ((int (*) __P((struct vop_create_args *)))eopnotsupp) 84168616Smckusick #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp) 84253838Spendry #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) 84353838Spendry #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) 84468616Smckusick #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))eopnotsupp) 845*68729Smckusick #define fdesc_revoke vop_revoke 84653838Spendry #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 84753838Spendry #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) 84868616Smckusick #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))eopnotsupp) 84968616Smckusick #define fdesc_link ((int (*) __P((struct vop_link_args *)))eopnotsupp) 85068616Smckusick #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))eopnotsupp) 85168616Smckusick #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp) 85268616Smckusick #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp) 85368616Smckusick #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))eopnotsupp) 85453838Spendry #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 85553838Spendry #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) 85653838Spendry #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 85753838Spendry #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) 85853838Spendry #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) 85953838Spendry #define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 86068616Smckusick #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))eopnotsupp) 86155170Spendry #define fdesc_blkatoff \ 86268616Smckusick ((int (*) __P((struct vop_blkatoff_args *)))eopnotsupp) 86353838Spendry #define fdesc_valloc ((int(*) __P(( \ 86453838Spendry struct vnode *pvp, \ 86553838Spendry int mode, \ 86653838Spendry struct ucred *cred, \ 86768616Smckusick struct vnode **vpp))) eopnotsupp) 86855170Spendry #define fdesc_truncate \ 86968616Smckusick ((int (*) __P((struct vop_truncate_args *)))eopnotsupp) 87068616Smckusick #define fdesc_update ((int (*) __P((struct vop_update_args *)))eopnotsupp) 87168616Smckusick #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp) 87253838Spendry 87353838Spendry int (**fdesc_vnodeop_p)(); 87453838Spendry struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 87553838Spendry { &vop_default_desc, vn_default_error }, 87653838Spendry { &vop_lookup_desc, fdesc_lookup }, /* lookup */ 87753838Spendry { &vop_create_desc, fdesc_create }, /* create */ 87853838Spendry { &vop_mknod_desc, fdesc_mknod }, /* mknod */ 87955017Smckusick { &vop_open_desc, fdesc_open }, /* open */ 88053838Spendry { &vop_close_desc, fdesc_close }, /* close */ 88153838Spendry { &vop_access_desc, fdesc_access }, /* access */ 88253838Spendry { &vop_getattr_desc, fdesc_getattr }, /* getattr */ 88353838Spendry { &vop_setattr_desc, fdesc_setattr }, /* setattr */ 88455017Smckusick { &vop_read_desc, fdesc_read }, /* read */ 88553838Spendry { &vop_write_desc, fdesc_write }, /* write */ 88653838Spendry { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */ 88753838Spendry { &vop_select_desc, fdesc_select }, /* select */ 888*68729Smckusick { &vop_revoke_desc, fdesc_revoke }, /* revoke */ 88955017Smckusick { &vop_mmap_desc, fdesc_mmap }, /* mmap */ 89053838Spendry { &vop_fsync_desc, fdesc_fsync }, /* fsync */ 89155017Smckusick { &vop_seek_desc, fdesc_seek }, /* seek */ 89253838Spendry { &vop_remove_desc, fdesc_remove }, /* remove */ 89355017Smckusick { &vop_link_desc, fdesc_link }, /* link */ 89453838Spendry { &vop_rename_desc, fdesc_rename }, /* rename */ 89553838Spendry { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */ 89653838Spendry { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */ 89753838Spendry { &vop_symlink_desc, fdesc_symlink }, /* symlink */ 89853838Spendry { &vop_readdir_desc, fdesc_readdir }, /* readdir */ 89953838Spendry { &vop_readlink_desc, fdesc_readlink }, /* readlink */ 90053838Spendry { &vop_abortop_desc, fdesc_abortop }, /* abortop */ 90153838Spendry { &vop_inactive_desc, fdesc_inactive }, /* inactive */ 90253838Spendry { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */ 90355017Smckusick { &vop_lock_desc, fdesc_lock }, /* lock */ 90453838Spendry { &vop_unlock_desc, fdesc_unlock }, /* unlock */ 90555017Smckusick { &vop_bmap_desc, fdesc_bmap }, /* bmap */ 90653838Spendry { &vop_strategy_desc, fdesc_strategy }, /* strategy */ 90753838Spendry { &vop_print_desc, fdesc_print }, /* print */ 90853838Spendry { &vop_islocked_desc, fdesc_islocked }, /* islocked */ 90965743Spendry { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */ 91053838Spendry { &vop_advlock_desc, fdesc_advlock }, /* advlock */ 91153838Spendry { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */ 91253838Spendry { &vop_valloc_desc, fdesc_valloc }, /* valloc */ 91353838Spendry { &vop_vfree_desc, fdesc_vfree }, /* vfree */ 91453838Spendry { &vop_truncate_desc, fdesc_truncate }, /* truncate */ 91553838Spendry { &vop_update_desc, fdesc_update }, /* update */ 91653838Spendry { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */ 91753838Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 91853838Spendry }; 91953838Spendry struct vnodeopv_desc fdesc_vnodeop_opv_desc = 92053838Spendry { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 921