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*67715Smckusick * @(#)fdesc_vnops.c 8.12 (Berkeley) 08/20/94 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 49*67715Smckusick #define NFDCACHE 4 5065513Spendry 51*67715Smckusick #define FD_NHASH(ix) \ 52*67715Smckusick (&fdhashtbl[(ix) & fdhash]) 53*67715Smckusick LIST_HEAD(fdhashhead, fdescnode) *fdhashtbl; 54*67715Smckusick u_long fdhash; 5565513Spendry 5665513Spendry /* 5765513Spendry * Initialise cache headers 5865513Spendry */ 5965513Spendry fdesc_init() 6065513Spendry { 6165513Spendry 6265513Spendry devctty = makedev(nchrdev, 0); 63*67715Smckusick fdhashtbl = hashinit(NFDCACHE, M_CACHE, &fdhash); 6465513Spendry } 6565513Spendry 6665513Spendry int 6759255Spendry fdesc_allocvp(ftype, ix, mp, vpp) 6859255Spendry fdntype ftype; 6959255Spendry int ix; 7059255Spendry struct mount *mp; 7159255Spendry struct vnode **vpp; 7259255Spendry { 73*67715Smckusick struct fdhashhead *fc; 7465513Spendry struct fdescnode *fd; 7559255Spendry int error = 0; 7659255Spendry 77*67715Smckusick fc = FD_NHASH(ix); 7859457Spendry loop: 79*67715Smckusick for (fd = fc->lh_first; fd != 0; fd = fd->fd_hash.le_next) { 8065513Spendry if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 8165513Spendry if (vget(fd->fd_vnode, 0)) 8259457Spendry goto loop; 8365513Spendry *vpp = fd->fd_vnode; 8459255Spendry return (error); 8559255Spendry } 8659255Spendry } 8759255Spendry 8859255Spendry /* 8959255Spendry * otherwise lock the array while we call getnewvnode 9059255Spendry * since that can block. 9159255Spendry */ 9265513Spendry if (fdcache_lock & FDL_LOCKED) { 9365513Spendry fdcache_lock |= FDL_WANT; 9465513Spendry sleep((caddr_t) &fdcache_lock, PINOD); 9559457Spendry goto loop; 9659255Spendry } 9765513Spendry fdcache_lock |= FDL_LOCKED; 9859255Spendry 9965380Spendry error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); 10059255Spendry if (error) 10159255Spendry goto out; 10265513Spendry MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); 10365513Spendry (*vpp)->v_data = fd; 10465513Spendry fd->fd_vnode = *vpp; 10565513Spendry fd->fd_type = ftype; 10665513Spendry fd->fd_fd = -1; 10765513Spendry fd->fd_link = 0; 10865513Spendry fd->fd_ix = ix; 109*67715Smckusick LIST_INSERT_HEAD(fc, fd, fd_hash); 11059255Spendry 11159255Spendry out:; 11265513Spendry fdcache_lock &= ~FDL_LOCKED; 11359255Spendry 11465513Spendry if (fdcache_lock & FDL_WANT) { 11565513Spendry fdcache_lock &= ~FDL_WANT; 11665513Spendry wakeup((caddr_t) &fdcache_lock); 11759255Spendry } 11859255Spendry 11959255Spendry return (error); 12059255Spendry } 12159255Spendry 12253838Spendry /* 12353838Spendry * vp is the current namei directory 12453838Spendry * ndp is the name to locate in that directory... 12553838Spendry */ 12665513Spendry int 12755017Smckusick fdesc_lookup(ap) 12855017Smckusick struct vop_lookup_args /* { 12955017Smckusick struct vnode * a_dvp; 13055017Smckusick struct vnode ** a_vpp; 13155017Smckusick struct componentname * a_cnp; 13255017Smckusick } */ *ap; 13353838Spendry { 13454049Spendry struct vnode **vpp = ap->a_vpp; 13554049Spendry struct vnode *dvp = ap->a_dvp; 13653838Spendry char *pname; 13753838Spendry struct proc *p; 13853838Spendry int nfiles; 13953838Spendry unsigned fd; 14053838Spendry int error; 14153838Spendry struct vnode *fvp; 14259255Spendry char *ln; 14353838Spendry 14453838Spendry pname = ap->a_cnp->cn_nameptr; 14553838Spendry if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { 14654049Spendry *vpp = dvp; 14754049Spendry VREF(dvp); 14859255Spendry VOP_LOCK(dvp); 14953838Spendry return (0); 15053838Spendry } 15153838Spendry 15253838Spendry p = ap->a_cnp->cn_proc; 15353838Spendry nfiles = p->p_fd->fd_nfiles; 15453838Spendry 15559255Spendry switch (VTOFDESC(dvp)->fd_type) { 15659255Spendry default: 15759255Spendry case Flink: 15859255Spendry case Fdesc: 15959255Spendry case Fctty: 16059255Spendry error = ENOTDIR; 16159255Spendry goto bad; 16259255Spendry 16359255Spendry case Froot: 16459255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { 16559255Spendry error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); 16659255Spendry if (error) 16759255Spendry goto bad; 16859255Spendry *vpp = fvp; 16959255Spendry fvp->v_type = VDIR; 17059255Spendry VOP_LOCK(fvp); 17159255Spendry return (0); 17259255Spendry } 17359255Spendry 17459255Spendry if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { 17559255Spendry struct vnode *ttyvp = cttyvp(p); 17659255Spendry if (ttyvp == NULL) { 17759255Spendry error = ENXIO; 17859255Spendry goto bad; 17959255Spendry } 18059255Spendry error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); 18159255Spendry if (error) 18259255Spendry goto bad; 18359255Spendry *vpp = fvp; 18459255Spendry fvp->v_type = VFIFO; 18559255Spendry VOP_LOCK(fvp); 18659255Spendry return (0); 18759255Spendry } 18859255Spendry 18959255Spendry ln = 0; 19059255Spendry switch (ap->a_cnp->cn_namelen) { 19159255Spendry case 5: 19259255Spendry if (bcmp(pname, "stdin", 5) == 0) { 19359255Spendry ln = "fd/0"; 19459255Spendry fd = FD_STDIN; 19559255Spendry } 19653838Spendry break; 19759255Spendry case 6: 19859255Spendry if (bcmp(pname, "stdout", 6) == 0) { 19959255Spendry ln = "fd/1"; 20059255Spendry fd = FD_STDOUT; 20159255Spendry } else 20259255Spendry if (bcmp(pname, "stderr", 6) == 0) { 20359255Spendry ln = "fd/2"; 20459255Spendry fd = FD_STDERR; 20559255Spendry } 20659255Spendry break; 20759255Spendry } 20853838Spendry 20959255Spendry if (ln) { 21059255Spendry error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp); 21159255Spendry if (error) 21259255Spendry goto bad; 21359255Spendry VTOFDESC(fvp)->fd_link = ln; 21459255Spendry *vpp = fvp; 21559255Spendry fvp->v_type = VLNK; 21659255Spendry VOP_LOCK(fvp); 21759255Spendry return (0); 21859255Spendry } else { 21959255Spendry error = ENOENT; 22059255Spendry goto bad; 22159255Spendry } 22253838Spendry 22365513Spendry /* FALL THROUGH */ 22453838Spendry 22559255Spendry case Fdevfd: 22659255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { 22759255Spendry error = fdesc_root(dvp->v_mount, vpp); 22859255Spendry return (error); 22959255Spendry } 23059255Spendry 23159255Spendry fd = 0; 23259255Spendry while (*pname >= '0' && *pname <= '9') { 23359255Spendry fd = 10 * fd + *pname++ - '0'; 23459255Spendry if (fd >= nfiles) 23559255Spendry break; 23659255Spendry } 23759255Spendry 23859255Spendry if (*pname != '\0') { 23959255Spendry error = ENOENT; 24059255Spendry goto bad; 24159255Spendry } 24259255Spendry 24359255Spendry if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 24459255Spendry error = EBADF; 24559255Spendry goto bad; 24659255Spendry } 24759255Spendry 24859255Spendry error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp); 24959255Spendry if (error) 25059255Spendry goto bad; 25159255Spendry VTOFDESC(fvp)->fd_fd = fd; 25259255Spendry *vpp = fvp; 25359255Spendry return (0); 25459255Spendry } 25553838Spendry 25653838Spendry bad:; 25754049Spendry *vpp = NULL; 25853838Spendry return (error); 25953838Spendry } 26053838Spendry 26165513Spendry int 26255017Smckusick fdesc_open(ap) 26355017Smckusick struct vop_open_args /* { 26455017Smckusick struct vnode *a_vp; 26555017Smckusick int a_mode; 26655017Smckusick struct ucred *a_cred; 26755017Smckusick struct proc *a_p; 26855017Smckusick } */ *ap; 26953838Spendry { 27054049Spendry struct vnode *vp = ap->a_vp; 27159255Spendry int error = 0; 27254049Spendry 27359255Spendry switch (VTOFDESC(vp)->fd_type) { 27459255Spendry case Fdesc: 27559255Spendry /* 27659255Spendry * XXX Kludge: set p->p_dupfd to contain the value of the 27759255Spendry * the file descriptor being sought for duplication. The error 27859255Spendry * return ensures that the vnode for this device will be 27959255Spendry * released by vn_open. Open will detect this special error and 28059255Spendry * take the actions in dupfdopen. Other callers of vn_open or 28159255Spendry * VOP_OPEN will simply report the error. 28259255Spendry */ 28359255Spendry ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 28459255Spendry error = ENODEV; 28559255Spendry break; 28653838Spendry 28759255Spendry case Fctty: 28859255Spendry error = cttyopen(devctty, ap->a_mode, 0, ap->a_p); 28959255Spendry break; 29059255Spendry } 29159255Spendry 29259255Spendry return (error); 29353838Spendry } 29453838Spendry 29553838Spendry static int 29653838Spendry fdesc_attr(fd, vap, cred, p) 29753838Spendry int fd; 29853838Spendry struct vattr *vap; 29953838Spendry struct ucred *cred; 30053838Spendry struct proc *p; 30153838Spendry { 30253838Spendry struct filedesc *fdp = p->p_fd; 30353838Spendry struct file *fp; 30459562Spendry struct stat stb; 30553838Spendry int error; 30653838Spendry 30765513Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) 30853838Spendry return (EBADF); 30953838Spendry 31053838Spendry switch (fp->f_type) { 31153838Spendry case DTYPE_VNODE: 31253838Spendry error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 31359561Spendry if (error == 0 && vap->va_type == VDIR) { 31459561Spendry /* 31567542Spendry * directories can cause loops in the namespace, 31667542Spendry * so turn off the 'x' bits to avoid trouble. 31759561Spendry */ 31867542Spendry vap->va_mode &= ~((VEXEC)|(VEXEC>>3)|(VEXEC>>6)); 31959561Spendry } 32053838Spendry break; 32153838Spendry 32253838Spendry case DTYPE_SOCKET: 32359562Spendry error = soo_stat((struct socket *)fp->f_data, &stb); 32459562Spendry if (error == 0) { 32559562Spendry vattr_null(vap); 32659562Spendry vap->va_type = VSOCK; 32759562Spendry vap->va_mode = stb.st_mode; 32859562Spendry vap->va_nlink = stb.st_nlink; 32959562Spendry vap->va_uid = stb.st_uid; 33059562Spendry vap->va_gid = stb.st_gid; 33159562Spendry vap->va_fsid = stb.st_dev; 33259562Spendry vap->va_fileid = stb.st_ino; 33359562Spendry vap->va_size = stb.st_size; 33459562Spendry vap->va_blocksize = stb.st_blksize; 33559562Spendry vap->va_atime = stb.st_atimespec; 33659562Spendry vap->va_mtime = stb.st_mtimespec; 33759562Spendry vap->va_ctime = stb.st_ctimespec; 33859562Spendry vap->va_gen = stb.st_gen; 33959562Spendry vap->va_flags = stb.st_flags; 34059562Spendry vap->va_rdev = stb.st_rdev; 34159562Spendry vap->va_bytes = stb.st_blocks * stb.st_blksize; 34259562Spendry } 34353838Spendry break; 34453838Spendry 34553838Spendry default: 34653838Spendry panic("fdesc attr"); 34753838Spendry break; 34853838Spendry } 34953838Spendry 35053838Spendry return (error); 35153838Spendry } 35253838Spendry 35365513Spendry int 35455017Smckusick fdesc_getattr(ap) 35555017Smckusick struct vop_getattr_args /* { 35655017Smckusick struct vnode *a_vp; 35755017Smckusick struct vattr *a_vap; 35855017Smckusick struct ucred *a_cred; 35955017Smckusick struct proc *a_p; 36055017Smckusick } */ *ap; 36153838Spendry { 36254049Spendry struct vnode *vp = ap->a_vp; 36354049Spendry struct vattr *vap = ap->a_vap; 36453838Spendry unsigned fd; 36563556Smckusick int error = 0; 36653838Spendry 36759255Spendry switch (VTOFDESC(vp)->fd_type) { 36859255Spendry case Froot: 36959255Spendry case Fdevfd: 37059255Spendry case Flink: 37159255Spendry case Fctty: 37254049Spendry bzero((caddr_t) vap, sizeof(*vap)); 37354049Spendry vattr_null(vap); 37459255Spendry vap->va_fileid = VTOFDESC(vp)->fd_ix; 37559255Spendry 37659255Spendry switch (VTOFDESC(vp)->fd_type) { 37759255Spendry case Flink: 37859255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 37959255Spendry vap->va_type = VLNK; 38059255Spendry vap->va_nlink = 1; 38159255Spendry vap->va_size = strlen(VTOFDESC(vp)->fd_link); 38259255Spendry break; 38359255Spendry 38459255Spendry case Fctty: 38559255Spendry vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 38659255Spendry vap->va_type = VFIFO; 38759255Spendry vap->va_nlink = 1; 38859255Spendry vap->va_size = 0; 38959255Spendry break; 39059255Spendry 39159255Spendry default: 39259255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 39359255Spendry vap->va_type = VDIR; 39459255Spendry vap->va_nlink = 2; 39559255Spendry vap->va_size = DEV_BSIZE; 39659255Spendry break; 39759255Spendry } 39854049Spendry vap->va_uid = 0; 39954049Spendry vap->va_gid = 0; 40054049Spendry vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 40154049Spendry vap->va_blocksize = DEV_BSIZE; 40259255Spendry vap->va_atime.ts_sec = boottime.tv_sec; 40359255Spendry vap->va_atime.ts_nsec = 0; 40454049Spendry vap->va_mtime = vap->va_atime; 40564276Smckusick vap->va_ctime = vap->va_mtime; 40654049Spendry vap->va_gen = 0; 40754049Spendry vap->va_flags = 0; 40854049Spendry vap->va_rdev = 0; 40954049Spendry vap->va_bytes = 0; 41059255Spendry break; 41159255Spendry 41259255Spendry case Fdesc: 41359255Spendry fd = VTOFDESC(vp)->fd_fd; 41459255Spendry error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); 41559255Spendry break; 41659255Spendry 41759255Spendry default: 41859255Spendry panic("fdesc_getattr"); 41959255Spendry break; 42053838Spendry } 42153838Spendry 42253838Spendry if (error == 0) 42354049Spendry vp->v_type = vap->va_type; 42459255Spendry 42553838Spendry return (error); 42653838Spendry } 42753838Spendry 42865513Spendry int 42955017Smckusick fdesc_setattr(ap) 43055017Smckusick struct vop_setattr_args /* { 43155017Smckusick struct vnode *a_vp; 43255017Smckusick struct vattr *a_vap; 43355017Smckusick struct ucred *a_cred; 43455017Smckusick struct proc *a_p; 43555017Smckusick } */ *ap; 43653838Spendry { 43753838Spendry struct filedesc *fdp = ap->a_p->p_fd; 43853838Spendry struct file *fp; 43953838Spendry unsigned fd; 44053838Spendry int error; 44153838Spendry 44253838Spendry /* 44353838Spendry * Can't mess with the root vnode 44453838Spendry */ 44559255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 44659255Spendry case Fdesc: 44759255Spendry break; 44859255Spendry 44959255Spendry case Fctty: 45059255Spendry return (0); 45159255Spendry 45259255Spendry default: 45353838Spendry return (EACCES); 45459255Spendry } 45553838Spendry 45659255Spendry fd = VTOFDESC(ap->a_vp)->fd_fd; 45753838Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 45853838Spendry return (EBADF); 45953838Spendry } 46053838Spendry 46153838Spendry /* 46253838Spendry * Can setattr the underlying vnode, but not sockets! 46353838Spendry */ 46453838Spendry switch (fp->f_type) { 46553838Spendry case DTYPE_VNODE: 46653838Spendry error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); 46753838Spendry break; 46853838Spendry 46953838Spendry case DTYPE_SOCKET: 47058646Spendry error = 0; 47153838Spendry break; 47253838Spendry 47353838Spendry default: 47453838Spendry panic("fdesc setattr"); 47553838Spendry break; 47653838Spendry } 47753838Spendry 47853838Spendry return (error); 47953838Spendry } 48053838Spendry 48159255Spendry #define UIO_MX 16 48259255Spendry 48359255Spendry static struct dirtmp { 48459255Spendry u_long d_fileno; 48559255Spendry u_short d_reclen; 48659255Spendry u_short d_namlen; 48759255Spendry char d_name[8]; 48859255Spendry } rootent[] = { 48959255Spendry { FD_DEVFD, UIO_MX, 2, "fd" }, 49059255Spendry { FD_STDIN, UIO_MX, 5, "stdin" }, 49159255Spendry { FD_STDOUT, UIO_MX, 6, "stdout" }, 49259255Spendry { FD_STDERR, UIO_MX, 6, "stderr" }, 49359255Spendry { FD_CTTY, UIO_MX, 3, "tty" }, 49459255Spendry { 0 } 49559255Spendry }; 49659255Spendry 49765513Spendry int 49855017Smckusick fdesc_readdir(ap) 49955017Smckusick struct vop_readdir_args /* { 50055017Smckusick struct vnode *a_vp; 50155017Smckusick struct uio *a_uio; 50255017Smckusick struct ucred *a_cred; 50367364Smckusick int *a_eofflag; 50467364Smckusick u_long *a_cookies; 50567364Smckusick int a_ncookies; 50655017Smckusick } */ *ap; 50753838Spendry { 50854049Spendry struct uio *uio = ap->a_uio; 50953838Spendry struct filedesc *fdp; 51053838Spendry int i; 51153838Spendry int error; 51253838Spendry 51367364Smckusick /* 51467364Smckusick * We don't allow exporting fdesc mounts, and currently local 51567364Smckusick * requests do not need cookies. 51667364Smckusick */ 51767364Smckusick if (ap->a_ncookies) 51867364Smckusick panic("fdesc_readdir: not hungry"); 51967364Smckusick 52059255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 52159255Spendry case Fctty: 52259255Spendry return (0); 52353838Spendry 52459255Spendry case Fdesc: 52559255Spendry return (ENOTDIR); 52659255Spendry 52759255Spendry default: 52859255Spendry break; 52959255Spendry } 53059255Spendry 53154049Spendry fdp = uio->uio_procp->p_fd; 53259255Spendry 53359255Spendry if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 53459255Spendry struct dirent d; 53559255Spendry struct dirent *dp = &d; 53659255Spendry struct dirtmp *dt; 53759255Spendry 53859255Spendry i = uio->uio_offset / UIO_MX; 53959255Spendry error = 0; 54059255Spendry 54159255Spendry while (uio->uio_resid > 0) { 54259255Spendry dt = &rootent[i]; 54359255Spendry if (dt->d_fileno == 0) { 54459255Spendry /**eofflagp = 1;*/ 54559255Spendry break; 54659255Spendry } 54759255Spendry i++; 54859255Spendry 54959255Spendry switch (dt->d_fileno) { 55059255Spendry case FD_CTTY: 55159255Spendry if (cttyvp(uio->uio_procp) == NULL) 55259255Spendry continue; 55359255Spendry break; 55459255Spendry 55559255Spendry case FD_STDIN: 55659255Spendry case FD_STDOUT: 55759255Spendry case FD_STDERR: 55864276Smckusick if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles) 55959255Spendry continue; 56064276Smckusick if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL) 56159255Spendry continue; 56259255Spendry break; 56359255Spendry } 56464276Smckusick bzero((caddr_t) dp, UIO_MX); 56559255Spendry dp->d_fileno = dt->d_fileno; 56659255Spendry dp->d_namlen = dt->d_namlen; 56759255Spendry dp->d_type = DT_UNKNOWN; 56859255Spendry dp->d_reclen = dt->d_reclen; 56959255Spendry bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); 57059255Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 57159255Spendry if (error) 57259255Spendry break; 57359255Spendry } 57459255Spendry uio->uio_offset = i * UIO_MX; 57559255Spendry return (error); 57659255Spendry } 57759255Spendry 57854049Spendry i = uio->uio_offset / UIO_MX; 57953838Spendry error = 0; 58054049Spendry while (uio->uio_resid > 0) { 58165513Spendry if (i >= fdp->fd_nfiles) 58253838Spendry break; 58365513Spendry 58453838Spendry if (fdp->fd_ofiles[i] != NULL) { 58554981Spendry struct dirent d; 58654981Spendry struct dirent *dp = &d; 58765513Spendry 58853838Spendry bzero((caddr_t) dp, UIO_MX); 58953838Spendry 59053838Spendry dp->d_namlen = sprintf(dp->d_name, "%d", i); 59153838Spendry dp->d_reclen = UIO_MX; 59254981Spendry dp->d_type = DT_UNKNOWN; 59359255Spendry dp->d_fileno = i + FD_STDIN; 59453838Spendry /* 59553838Spendry * And ship to userland 59653838Spendry */ 59754049Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 59853838Spendry if (error) 59953838Spendry break; 60053838Spendry } 60153838Spendry i++; 60253838Spendry } 60353838Spendry 60454049Spendry uio->uio_offset = i * UIO_MX; 60553838Spendry return (error); 60653838Spendry } 60753838Spendry 60859255Spendry int 60959255Spendry fdesc_readlink(ap) 61059255Spendry struct vop_readlink_args /* { 61159255Spendry struct vnode *a_vp; 61259255Spendry struct uio *a_uio; 61359255Spendry struct ucred *a_cred; 61459255Spendry } */ *ap; 61559255Spendry { 61665513Spendry struct vnode *vp = ap->a_vp; 61759255Spendry int error; 61859255Spendry 61959255Spendry if (vp->v_type != VLNK) 62059255Spendry return (EPERM); 62159255Spendry 62259255Spendry if (VTOFDESC(vp)->fd_type == Flink) { 62359255Spendry char *ln = VTOFDESC(vp)->fd_link; 62459255Spendry error = uiomove(ln, strlen(ln), ap->a_uio); 62559255Spendry } else { 62659255Spendry error = EOPNOTSUPP; 62759255Spendry } 62859255Spendry 62959255Spendry return (error); 63059255Spendry } 63159255Spendry 63265513Spendry int 63359255Spendry fdesc_read(ap) 63459255Spendry struct vop_read_args /* { 63559255Spendry struct vnode *a_vp; 63659255Spendry struct uio *a_uio; 63759255Spendry int a_ioflag; 63859255Spendry struct ucred *a_cred; 63959255Spendry } */ *ap; 64059255Spendry { 64159255Spendry int error = EOPNOTSUPP; 64259255Spendry 64359255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 64459255Spendry case Fctty: 64559255Spendry error = cttyread(devctty, ap->a_uio, ap->a_ioflag); 64659255Spendry break; 64759255Spendry 64859255Spendry default: 64959255Spendry error = EOPNOTSUPP; 65059255Spendry break; 65159255Spendry } 65259255Spendry 65359255Spendry return (error); 65459255Spendry } 65559255Spendry 65665513Spendry int 65759255Spendry fdesc_write(ap) 65859255Spendry struct vop_write_args /* { 65959255Spendry struct vnode *a_vp; 66059255Spendry struct uio *a_uio; 66159255Spendry int a_ioflag; 66259255Spendry struct ucred *a_cred; 66359255Spendry } */ *ap; 66459255Spendry { 66559255Spendry int error = EOPNOTSUPP; 66659255Spendry 66759255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 66859255Spendry case Fctty: 66959255Spendry error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); 67059255Spendry break; 67159255Spendry 67259255Spendry default: 67359255Spendry error = EOPNOTSUPP; 67459255Spendry break; 67559255Spendry } 67659255Spendry 67759255Spendry return (error); 67859255Spendry } 67959255Spendry 68065513Spendry int 68159255Spendry fdesc_ioctl(ap) 68259255Spendry struct vop_ioctl_args /* { 68359255Spendry struct vnode *a_vp; 68459255Spendry int a_command; 68559255Spendry caddr_t a_data; 68659255Spendry int a_fflag; 68759255Spendry struct ucred *a_cred; 68859255Spendry struct proc *a_p; 68959255Spendry } */ *ap; 69059255Spendry { 69159255Spendry int error = EOPNOTSUPP; 69259255Spendry 69359255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 69459255Spendry case Fctty: 69559255Spendry error = cttyioctl(devctty, ap->a_command, ap->a_data, 69659255Spendry ap->a_fflag, ap->a_p); 69759255Spendry break; 69859255Spendry 69959255Spendry default: 70059255Spendry error = EOPNOTSUPP; 70159255Spendry break; 70259255Spendry } 70359255Spendry 70459255Spendry return (error); 70559255Spendry } 70659255Spendry 70765513Spendry int 70859255Spendry fdesc_select(ap) 70959255Spendry struct vop_select_args /* { 71059255Spendry struct vnode *a_vp; 71159255Spendry int a_which; 71259255Spendry int a_fflags; 71359255Spendry struct ucred *a_cred; 71459255Spendry struct proc *a_p; 71559255Spendry } */ *ap; 71659255Spendry { 71759255Spendry int error = EOPNOTSUPP; 71859255Spendry 71959255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 72059255Spendry case Fctty: 72159255Spendry error = cttyselect(devctty, ap->a_fflags, ap->a_p); 72259255Spendry break; 72359255Spendry 72459255Spendry default: 72559255Spendry error = EOPNOTSUPP; 72659255Spendry break; 72759255Spendry } 72859255Spendry 72959255Spendry return (error); 73059255Spendry } 73159255Spendry 73265513Spendry int 73355017Smckusick fdesc_inactive(ap) 73455017Smckusick struct vop_inactive_args /* { 73555017Smckusick struct vnode *a_vp; 73655017Smckusick } */ *ap; 73753838Spendry { 73854049Spendry struct vnode *vp = ap->a_vp; 73954049Spendry 74053838Spendry /* 74153838Spendry * Clear out the v_type field to avoid 74253838Spendry * nasty things happening in vgone(). 74353838Spendry */ 74454049Spendry vp->v_type = VNON; 74553838Spendry return (0); 74653838Spendry } 74753838Spendry 74865513Spendry int 74955017Smckusick fdesc_reclaim(ap) 75055017Smckusick struct vop_reclaim_args /* { 75155017Smckusick struct vnode *a_vp; 75255017Smckusick } */ *ap; 75353838Spendry { 75453838Spendry struct vnode *vp = ap->a_vp; 755*67715Smckusick struct fdescnode *fd = VTOFDESC(vp); 75659255Spendry 757*67715Smckusick LIST_REMOVE(fd, fd_hash); 75865513Spendry FREE(vp->v_data, M_TEMP); 75965513Spendry vp->v_data = 0; 76065513Spendry 76153838Spendry return (0); 76253838Spendry } 76353838Spendry 76453838Spendry /* 76565743Spendry * Return POSIX pathconf information applicable to special devices. 76665743Spendry */ 76765743Spendry fdesc_pathconf(ap) 76865743Spendry struct vop_pathconf_args /* { 76965743Spendry struct vnode *a_vp; 77065743Spendry int a_name; 77165743Spendry int *a_retval; 77265743Spendry } */ *ap; 77365743Spendry { 77465743Spendry 77565743Spendry switch (ap->a_name) { 77665743Spendry case _PC_LINK_MAX: 77765743Spendry *ap->a_retval = LINK_MAX; 77865743Spendry return (0); 77965743Spendry case _PC_MAX_CANON: 78065743Spendry *ap->a_retval = MAX_CANON; 78165743Spendry return (0); 78265743Spendry case _PC_MAX_INPUT: 78365743Spendry *ap->a_retval = MAX_INPUT; 78465743Spendry return (0); 78565743Spendry case _PC_PIPE_BUF: 78665743Spendry *ap->a_retval = PIPE_BUF; 78765743Spendry return (0); 78865743Spendry case _PC_CHOWN_RESTRICTED: 78965743Spendry *ap->a_retval = 1; 79065743Spendry return (0); 79165743Spendry case _PC_VDISABLE: 79265743Spendry *ap->a_retval = _POSIX_VDISABLE; 79365743Spendry return (0); 79465743Spendry default: 79565743Spendry return (EINVAL); 79665743Spendry } 79765743Spendry /* NOTREACHED */ 79865743Spendry } 79965743Spendry 80065743Spendry /* 80153838Spendry * Print out the contents of a /dev/fd vnode. 80253838Spendry */ 80353838Spendry /* ARGSUSED */ 80465513Spendry int 80555017Smckusick fdesc_print(ap) 80655017Smckusick struct vop_print_args /* { 80755017Smckusick struct vnode *a_vp; 80855017Smckusick } */ *ap; 80953838Spendry { 81055017Smckusick 81153838Spendry printf("tag VT_NON, fdesc vnode\n"); 81255017Smckusick return (0); 81353838Spendry } 81453838Spendry 81553838Spendry /*void*/ 81665513Spendry int 81755017Smckusick fdesc_vfree(ap) 81855017Smckusick struct vop_vfree_args /* { 81955017Smckusick struct vnode *a_pvp; 82055017Smckusick ino_t a_ino; 82155017Smckusick int a_mode; 82255017Smckusick } */ *ap; 82353838Spendry { 82453838Spendry 82555017Smckusick return (0); 82653838Spendry } 82753838Spendry 82853838Spendry /* 82953838Spendry * /dev/fd vnode unsupported operation 83053838Spendry */ 83165513Spendry int 83253838Spendry fdesc_enotsupp() 83353838Spendry { 83455017Smckusick 83553838Spendry return (EOPNOTSUPP); 83653838Spendry } 83753838Spendry 83853838Spendry /* 83953838Spendry * /dev/fd "should never get here" operation 84053838Spendry */ 84165513Spendry int 84253838Spendry fdesc_badop() 84353838Spendry { 84455017Smckusick 84553838Spendry panic("fdesc: bad op"); 84653838Spendry /* NOTREACHED */ 84753838Spendry } 84853838Spendry 84953838Spendry /* 85053838Spendry * /dev/fd vnode null operation 85153838Spendry */ 85265513Spendry int 85353838Spendry fdesc_nullop() 85453838Spendry { 85555017Smckusick 85653838Spendry return (0); 85753838Spendry } 85853838Spendry 85953838Spendry #define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp) 86053838Spendry #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp) 86153838Spendry #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) 86253838Spendry #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) 86353838Spendry #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp) 86453838Spendry #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 86553838Spendry #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) 86653838Spendry #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp) 86753838Spendry #define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp) 86853838Spendry #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp) 86953838Spendry #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp) 87053838Spendry #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp) 87155017Smckusick #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp) 87253838Spendry #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 87353838Spendry #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) 87453838Spendry #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 87553838Spendry #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) 87653838Spendry #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) 87753838Spendry #define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 87855017Smckusick #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp) 87955170Spendry #define fdesc_blkatoff \ 88055017Smckusick ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp) 88153838Spendry #define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp) 88253838Spendry #define fdesc_valloc ((int(*) __P(( \ 88353838Spendry struct vnode *pvp, \ 88453838Spendry int mode, \ 88553838Spendry struct ucred *cred, \ 88653838Spendry struct vnode **vpp))) fdesc_enotsupp) 88755170Spendry #define fdesc_truncate \ 88855017Smckusick ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp) 88953838Spendry #define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp) 89053838Spendry #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp) 89153838Spendry 89253838Spendry int (**fdesc_vnodeop_p)(); 89353838Spendry struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 89453838Spendry { &vop_default_desc, vn_default_error }, 89553838Spendry { &vop_lookup_desc, fdesc_lookup }, /* lookup */ 89653838Spendry { &vop_create_desc, fdesc_create }, /* create */ 89753838Spendry { &vop_mknod_desc, fdesc_mknod }, /* mknod */ 89855017Smckusick { &vop_open_desc, fdesc_open }, /* open */ 89953838Spendry { &vop_close_desc, fdesc_close }, /* close */ 90053838Spendry { &vop_access_desc, fdesc_access }, /* access */ 90153838Spendry { &vop_getattr_desc, fdesc_getattr }, /* getattr */ 90253838Spendry { &vop_setattr_desc, fdesc_setattr }, /* setattr */ 90355017Smckusick { &vop_read_desc, fdesc_read }, /* read */ 90453838Spendry { &vop_write_desc, fdesc_write }, /* write */ 90553838Spendry { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */ 90653838Spendry { &vop_select_desc, fdesc_select }, /* select */ 90755017Smckusick { &vop_mmap_desc, fdesc_mmap }, /* mmap */ 90853838Spendry { &vop_fsync_desc, fdesc_fsync }, /* fsync */ 90955017Smckusick { &vop_seek_desc, fdesc_seek }, /* seek */ 91053838Spendry { &vop_remove_desc, fdesc_remove }, /* remove */ 91155017Smckusick { &vop_link_desc, fdesc_link }, /* link */ 91253838Spendry { &vop_rename_desc, fdesc_rename }, /* rename */ 91353838Spendry { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */ 91453838Spendry { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */ 91553838Spendry { &vop_symlink_desc, fdesc_symlink }, /* symlink */ 91653838Spendry { &vop_readdir_desc, fdesc_readdir }, /* readdir */ 91753838Spendry { &vop_readlink_desc, fdesc_readlink }, /* readlink */ 91853838Spendry { &vop_abortop_desc, fdesc_abortop }, /* abortop */ 91953838Spendry { &vop_inactive_desc, fdesc_inactive }, /* inactive */ 92053838Spendry { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */ 92155017Smckusick { &vop_lock_desc, fdesc_lock }, /* lock */ 92253838Spendry { &vop_unlock_desc, fdesc_unlock }, /* unlock */ 92355017Smckusick { &vop_bmap_desc, fdesc_bmap }, /* bmap */ 92453838Spendry { &vop_strategy_desc, fdesc_strategy }, /* strategy */ 92553838Spendry { &vop_print_desc, fdesc_print }, /* print */ 92653838Spendry { &vop_islocked_desc, fdesc_islocked }, /* islocked */ 92765743Spendry { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */ 92853838Spendry { &vop_advlock_desc, fdesc_advlock }, /* advlock */ 92953838Spendry { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */ 93053838Spendry { &vop_valloc_desc, fdesc_valloc }, /* valloc */ 93153838Spendry { &vop_vfree_desc, fdesc_vfree }, /* vfree */ 93253838Spendry { &vop_truncate_desc, fdesc_truncate }, /* truncate */ 93353838Spendry { &vop_update_desc, fdesc_update }, /* update */ 93453838Spendry { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */ 93553838Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 93653838Spendry }; 93753838Spendry struct vnodeopv_desc fdesc_vnodeop_opv_desc = 93853838Spendry { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 939