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*67364Smckusick * @(#)fdesc_vnops.c 8.10 (Berkeley) 06/04/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 4965513Spendry #define NFDCACHE 3 5065513Spendry #define FD_NHASH(ix) ((ix) & NFDCACHE) 5165513Spendry 5265513Spendry /* 5365513Spendry * Cache head 5465513Spendry */ 5565513Spendry struct fdcache { 5665513Spendry struct fdescnode *fc_forw; 5765513Spendry struct fdescnode *fc_back; 5865513Spendry }; 5965513Spendry 6065513Spendry static struct fdcache fdcache[NFDCACHE]; 6165513Spendry 6265513Spendry /* 6365513Spendry * Initialise cache headers 6465513Spendry */ 6565513Spendry fdesc_init() 6665513Spendry { 6765513Spendry struct fdcache *fc; 6865513Spendry 6965513Spendry devctty = makedev(nchrdev, 0); 7065513Spendry 7165513Spendry for (fc = fdcache; fc < fdcache + NFDCACHE; fc++) 7265513Spendry fc->fc_forw = fc->fc_back = (struct fdescnode *) fc; 7365513Spendry } 7465513Spendry 7565513Spendry /* 7665513Spendry * Compute hash list for given target vnode 7765513Spendry */ 7865513Spendry static struct fdcache * 7965513Spendry fdesc_hash(ix) 8065513Spendry int ix; 8165513Spendry { 8265513Spendry 8365513Spendry return (&fdcache[FD_NHASH(ix)]); 8465513Spendry } 8565513Spendry 8665513Spendry int 8759255Spendry fdesc_allocvp(ftype, ix, mp, vpp) 8859255Spendry fdntype ftype; 8959255Spendry int ix; 9059255Spendry struct mount *mp; 9159255Spendry struct vnode **vpp; 9259255Spendry { 9365513Spendry struct fdcache *fc; 9465513Spendry struct fdescnode *fd; 9559255Spendry int error = 0; 9659255Spendry 9759457Spendry loop: 9865513Spendry fc = fdesc_hash(ix); 9965513Spendry for (fd = fc->fc_forw; fd != (struct fdescnode *) fc; fd = fd->fd_forw) { 10065513Spendry if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 10165513Spendry if (vget(fd->fd_vnode, 0)) 10259457Spendry goto loop; 10365513Spendry *vpp = fd->fd_vnode; 10459255Spendry return (error); 10559255Spendry } 10659255Spendry } 10759255Spendry 10859255Spendry /* 10959255Spendry * otherwise lock the array while we call getnewvnode 11059255Spendry * since that can block. 11159255Spendry */ 11265513Spendry if (fdcache_lock & FDL_LOCKED) { 11365513Spendry fdcache_lock |= FDL_WANT; 11465513Spendry sleep((caddr_t) &fdcache_lock, PINOD); 11559457Spendry goto loop; 11659255Spendry } 11765513Spendry fdcache_lock |= FDL_LOCKED; 11859255Spendry 11965380Spendry error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); 12059255Spendry if (error) 12159255Spendry goto out; 12265513Spendry MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); 12365513Spendry (*vpp)->v_data = fd; 12465513Spendry fd->fd_vnode = *vpp; 12565513Spendry fd->fd_type = ftype; 12665513Spendry fd->fd_fd = -1; 12765513Spendry fd->fd_link = 0; 12865513Spendry fd->fd_ix = ix; 12965513Spendry fc = fdesc_hash(ix); 13065513Spendry insque(fd, fc); 13159255Spendry 13259255Spendry out:; 13365513Spendry fdcache_lock &= ~FDL_LOCKED; 13459255Spendry 13565513Spendry if (fdcache_lock & FDL_WANT) { 13665513Spendry fdcache_lock &= ~FDL_WANT; 13765513Spendry wakeup((caddr_t) &fdcache_lock); 13859255Spendry } 13959255Spendry 14059255Spendry return (error); 14159255Spendry } 14259255Spendry 14353838Spendry /* 14453838Spendry * vp is the current namei directory 14553838Spendry * ndp is the name to locate in that directory... 14653838Spendry */ 14765513Spendry int 14855017Smckusick fdesc_lookup(ap) 14955017Smckusick struct vop_lookup_args /* { 15055017Smckusick struct vnode * a_dvp; 15155017Smckusick struct vnode ** a_vpp; 15255017Smckusick struct componentname * a_cnp; 15355017Smckusick } */ *ap; 15453838Spendry { 15554049Spendry struct vnode **vpp = ap->a_vpp; 15654049Spendry struct vnode *dvp = ap->a_dvp; 15753838Spendry char *pname; 15853838Spendry struct proc *p; 15953838Spendry int nfiles; 16053838Spendry unsigned fd; 16153838Spendry int error; 16253838Spendry struct vnode *fvp; 16359255Spendry char *ln; 16453838Spendry 16553838Spendry pname = ap->a_cnp->cn_nameptr; 16653838Spendry if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { 16754049Spendry *vpp = dvp; 16854049Spendry VREF(dvp); 16959255Spendry VOP_LOCK(dvp); 17053838Spendry return (0); 17153838Spendry } 17253838Spendry 17353838Spendry p = ap->a_cnp->cn_proc; 17453838Spendry nfiles = p->p_fd->fd_nfiles; 17553838Spendry 17659255Spendry switch (VTOFDESC(dvp)->fd_type) { 17759255Spendry default: 17859255Spendry case Flink: 17959255Spendry case Fdesc: 18059255Spendry case Fctty: 18159255Spendry error = ENOTDIR; 18259255Spendry goto bad; 18359255Spendry 18459255Spendry case Froot: 18559255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { 18659255Spendry error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); 18759255Spendry if (error) 18859255Spendry goto bad; 18959255Spendry *vpp = fvp; 19059255Spendry fvp->v_type = VDIR; 19159255Spendry VOP_LOCK(fvp); 19259255Spendry return (0); 19359255Spendry } 19459255Spendry 19559255Spendry if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { 19659255Spendry struct vnode *ttyvp = cttyvp(p); 19759255Spendry if (ttyvp == NULL) { 19859255Spendry error = ENXIO; 19959255Spendry goto bad; 20059255Spendry } 20159255Spendry error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); 20259255Spendry if (error) 20359255Spendry goto bad; 20459255Spendry *vpp = fvp; 20559255Spendry fvp->v_type = VFIFO; 20659255Spendry VOP_LOCK(fvp); 20759255Spendry return (0); 20859255Spendry } 20959255Spendry 21059255Spendry ln = 0; 21159255Spendry switch (ap->a_cnp->cn_namelen) { 21259255Spendry case 5: 21359255Spendry if (bcmp(pname, "stdin", 5) == 0) { 21459255Spendry ln = "fd/0"; 21559255Spendry fd = FD_STDIN; 21659255Spendry } 21753838Spendry break; 21859255Spendry case 6: 21959255Spendry if (bcmp(pname, "stdout", 6) == 0) { 22059255Spendry ln = "fd/1"; 22159255Spendry fd = FD_STDOUT; 22259255Spendry } else 22359255Spendry if (bcmp(pname, "stderr", 6) == 0) { 22459255Spendry ln = "fd/2"; 22559255Spendry fd = FD_STDERR; 22659255Spendry } 22759255Spendry break; 22859255Spendry } 22953838Spendry 23059255Spendry if (ln) { 23159255Spendry error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp); 23259255Spendry if (error) 23359255Spendry goto bad; 23459255Spendry VTOFDESC(fvp)->fd_link = ln; 23559255Spendry *vpp = fvp; 23659255Spendry fvp->v_type = VLNK; 23759255Spendry VOP_LOCK(fvp); 23859255Spendry return (0); 23959255Spendry } else { 24059255Spendry error = ENOENT; 24159255Spendry goto bad; 24259255Spendry } 24353838Spendry 24465513Spendry /* FALL THROUGH */ 24553838Spendry 24659255Spendry case Fdevfd: 24759255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { 24859255Spendry error = fdesc_root(dvp->v_mount, vpp); 24959255Spendry return (error); 25059255Spendry } 25159255Spendry 25259255Spendry fd = 0; 25359255Spendry while (*pname >= '0' && *pname <= '9') { 25459255Spendry fd = 10 * fd + *pname++ - '0'; 25559255Spendry if (fd >= nfiles) 25659255Spendry break; 25759255Spendry } 25859255Spendry 25959255Spendry if (*pname != '\0') { 26059255Spendry error = ENOENT; 26159255Spendry goto bad; 26259255Spendry } 26359255Spendry 26459255Spendry if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 26559255Spendry error = EBADF; 26659255Spendry goto bad; 26759255Spendry } 26859255Spendry 26959255Spendry error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp); 27059255Spendry if (error) 27159255Spendry goto bad; 27259255Spendry VTOFDESC(fvp)->fd_fd = fd; 27359255Spendry *vpp = fvp; 27459255Spendry return (0); 27559255Spendry } 27653838Spendry 27753838Spendry bad:; 27854049Spendry *vpp = NULL; 27953838Spendry return (error); 28053838Spendry } 28153838Spendry 28265513Spendry int 28355017Smckusick fdesc_open(ap) 28455017Smckusick struct vop_open_args /* { 28555017Smckusick struct vnode *a_vp; 28655017Smckusick int a_mode; 28755017Smckusick struct ucred *a_cred; 28855017Smckusick struct proc *a_p; 28955017Smckusick } */ *ap; 29053838Spendry { 29154049Spendry struct vnode *vp = ap->a_vp; 29259255Spendry int error = 0; 29354049Spendry 29459255Spendry switch (VTOFDESC(vp)->fd_type) { 29559255Spendry case Fdesc: 29659255Spendry /* 29759255Spendry * XXX Kludge: set p->p_dupfd to contain the value of the 29859255Spendry * the file descriptor being sought for duplication. The error 29959255Spendry * return ensures that the vnode for this device will be 30059255Spendry * released by vn_open. Open will detect this special error and 30159255Spendry * take the actions in dupfdopen. Other callers of vn_open or 30259255Spendry * VOP_OPEN will simply report the error. 30359255Spendry */ 30459255Spendry ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 30559255Spendry error = ENODEV; 30659255Spendry break; 30753838Spendry 30859255Spendry case Fctty: 30959255Spendry error = cttyopen(devctty, ap->a_mode, 0, ap->a_p); 31059255Spendry break; 31159255Spendry } 31259255Spendry 31359255Spendry return (error); 31453838Spendry } 31553838Spendry 31653838Spendry static int 31753838Spendry fdesc_attr(fd, vap, cred, p) 31853838Spendry int fd; 31953838Spendry struct vattr *vap; 32053838Spendry struct ucred *cred; 32153838Spendry struct proc *p; 32253838Spendry { 32353838Spendry struct filedesc *fdp = p->p_fd; 32453838Spendry struct file *fp; 32559562Spendry struct stat stb; 32653838Spendry int error; 32753838Spendry 32865513Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) 32953838Spendry return (EBADF); 33053838Spendry 33153838Spendry switch (fp->f_type) { 33253838Spendry case DTYPE_VNODE: 33353838Spendry error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 33459561Spendry if (error == 0 && vap->va_type == VDIR) { 33559561Spendry /* 33659561Spendry * don't allow directories to show up because 33759561Spendry * that causes loops in the namespace. 33859561Spendry */ 33959561Spendry vap->va_type = VFIFO; 34059561Spendry } 34153838Spendry break; 34253838Spendry 34353838Spendry case DTYPE_SOCKET: 34459562Spendry error = soo_stat((struct socket *)fp->f_data, &stb); 34559562Spendry if (error == 0) { 34659562Spendry vattr_null(vap); 34759562Spendry vap->va_type = VSOCK; 34859562Spendry vap->va_mode = stb.st_mode; 34959562Spendry vap->va_nlink = stb.st_nlink; 35059562Spendry vap->va_uid = stb.st_uid; 35159562Spendry vap->va_gid = stb.st_gid; 35259562Spendry vap->va_fsid = stb.st_dev; 35359562Spendry vap->va_fileid = stb.st_ino; 35459562Spendry vap->va_size = stb.st_size; 35559562Spendry vap->va_blocksize = stb.st_blksize; 35659562Spendry vap->va_atime = stb.st_atimespec; 35759562Spendry vap->va_mtime = stb.st_mtimespec; 35859562Spendry vap->va_ctime = stb.st_ctimespec; 35959562Spendry vap->va_gen = stb.st_gen; 36059562Spendry vap->va_flags = stb.st_flags; 36159562Spendry vap->va_rdev = stb.st_rdev; 36259562Spendry vap->va_bytes = stb.st_blocks * stb.st_blksize; 36359562Spendry } 36453838Spendry break; 36553838Spendry 36653838Spendry default: 36753838Spendry panic("fdesc attr"); 36853838Spendry break; 36953838Spendry } 37053838Spendry 37153838Spendry return (error); 37253838Spendry } 37353838Spendry 37465513Spendry int 37555017Smckusick fdesc_getattr(ap) 37655017Smckusick struct vop_getattr_args /* { 37755017Smckusick struct vnode *a_vp; 37855017Smckusick struct vattr *a_vap; 37955017Smckusick struct ucred *a_cred; 38055017Smckusick struct proc *a_p; 38155017Smckusick } */ *ap; 38253838Spendry { 38354049Spendry struct vnode *vp = ap->a_vp; 38454049Spendry struct vattr *vap = ap->a_vap; 38553838Spendry unsigned fd; 38663556Smckusick int error = 0; 38753838Spendry 38859255Spendry switch (VTOFDESC(vp)->fd_type) { 38959255Spendry case Froot: 39059255Spendry case Fdevfd: 39159255Spendry case Flink: 39259255Spendry case Fctty: 39354049Spendry bzero((caddr_t) vap, sizeof(*vap)); 39454049Spendry vattr_null(vap); 39559255Spendry vap->va_fileid = VTOFDESC(vp)->fd_ix; 39659255Spendry 39759255Spendry switch (VTOFDESC(vp)->fd_type) { 39859255Spendry case Flink: 39959255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 40059255Spendry vap->va_type = VLNK; 40159255Spendry vap->va_nlink = 1; 40259255Spendry vap->va_size = strlen(VTOFDESC(vp)->fd_link); 40359255Spendry break; 40459255Spendry 40559255Spendry case Fctty: 40659255Spendry vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 40759255Spendry vap->va_type = VFIFO; 40859255Spendry vap->va_nlink = 1; 40959255Spendry vap->va_size = 0; 41059255Spendry break; 41159255Spendry 41259255Spendry default: 41359255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 41459255Spendry vap->va_type = VDIR; 41559255Spendry vap->va_nlink = 2; 41659255Spendry vap->va_size = DEV_BSIZE; 41759255Spendry break; 41859255Spendry } 41954049Spendry vap->va_uid = 0; 42054049Spendry vap->va_gid = 0; 42154049Spendry vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 42254049Spendry vap->va_blocksize = DEV_BSIZE; 42359255Spendry vap->va_atime.ts_sec = boottime.tv_sec; 42459255Spendry vap->va_atime.ts_nsec = 0; 42554049Spendry vap->va_mtime = vap->va_atime; 42664276Smckusick vap->va_ctime = vap->va_mtime; 42754049Spendry vap->va_gen = 0; 42854049Spendry vap->va_flags = 0; 42954049Spendry vap->va_rdev = 0; 43054049Spendry vap->va_bytes = 0; 43159255Spendry break; 43259255Spendry 43359255Spendry case Fdesc: 43459255Spendry fd = VTOFDESC(vp)->fd_fd; 43559255Spendry error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); 43659255Spendry break; 43759255Spendry 43859255Spendry default: 43959255Spendry panic("fdesc_getattr"); 44059255Spendry break; 44153838Spendry } 44253838Spendry 44353838Spendry if (error == 0) 44454049Spendry vp->v_type = vap->va_type; 44559255Spendry 44653838Spendry return (error); 44753838Spendry } 44853838Spendry 44965513Spendry int 45055017Smckusick fdesc_setattr(ap) 45155017Smckusick struct vop_setattr_args /* { 45255017Smckusick struct vnode *a_vp; 45355017Smckusick struct vattr *a_vap; 45455017Smckusick struct ucred *a_cred; 45555017Smckusick struct proc *a_p; 45655017Smckusick } */ *ap; 45753838Spendry { 45853838Spendry struct filedesc *fdp = ap->a_p->p_fd; 45953838Spendry struct file *fp; 46053838Spendry unsigned fd; 46153838Spendry int error; 46253838Spendry 46353838Spendry /* 46453838Spendry * Can't mess with the root vnode 46553838Spendry */ 46659255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 46759255Spendry case Fdesc: 46859255Spendry break; 46959255Spendry 47059255Spendry case Fctty: 47159255Spendry return (0); 47259255Spendry 47359255Spendry default: 47453838Spendry return (EACCES); 47559255Spendry } 47653838Spendry 47759255Spendry fd = VTOFDESC(ap->a_vp)->fd_fd; 47853838Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 47953838Spendry return (EBADF); 48053838Spendry } 48153838Spendry 48253838Spendry /* 48353838Spendry * Can setattr the underlying vnode, but not sockets! 48453838Spendry */ 48553838Spendry switch (fp->f_type) { 48653838Spendry case DTYPE_VNODE: 48753838Spendry error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); 48853838Spendry break; 48953838Spendry 49053838Spendry case DTYPE_SOCKET: 49158646Spendry error = 0; 49253838Spendry break; 49353838Spendry 49453838Spendry default: 49553838Spendry panic("fdesc setattr"); 49653838Spendry break; 49753838Spendry } 49853838Spendry 49953838Spendry return (error); 50053838Spendry } 50153838Spendry 50259255Spendry #define UIO_MX 16 50359255Spendry 50459255Spendry static struct dirtmp { 50559255Spendry u_long d_fileno; 50659255Spendry u_short d_reclen; 50759255Spendry u_short d_namlen; 50859255Spendry char d_name[8]; 50959255Spendry } rootent[] = { 51059255Spendry { FD_DEVFD, UIO_MX, 2, "fd" }, 51159255Spendry { FD_STDIN, UIO_MX, 5, "stdin" }, 51259255Spendry { FD_STDOUT, UIO_MX, 6, "stdout" }, 51359255Spendry { FD_STDERR, UIO_MX, 6, "stderr" }, 51459255Spendry { FD_CTTY, UIO_MX, 3, "tty" }, 51559255Spendry { 0 } 51659255Spendry }; 51759255Spendry 51865513Spendry int 51955017Smckusick fdesc_readdir(ap) 52055017Smckusick struct vop_readdir_args /* { 52155017Smckusick struct vnode *a_vp; 52255017Smckusick struct uio *a_uio; 52355017Smckusick struct ucred *a_cred; 524*67364Smckusick int *a_eofflag; 525*67364Smckusick u_long *a_cookies; 526*67364Smckusick int a_ncookies; 52755017Smckusick } */ *ap; 52853838Spendry { 52954049Spendry struct uio *uio = ap->a_uio; 53053838Spendry struct filedesc *fdp; 53153838Spendry int i; 53253838Spendry int error; 53353838Spendry 534*67364Smckusick /* 535*67364Smckusick * We don't allow exporting fdesc mounts, and currently local 536*67364Smckusick * requests do not need cookies. 537*67364Smckusick */ 538*67364Smckusick if (ap->a_ncookies) 539*67364Smckusick panic("fdesc_readdir: not hungry"); 540*67364Smckusick 54159255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 54259255Spendry case Fctty: 54359255Spendry return (0); 54453838Spendry 54559255Spendry case Fdesc: 54659255Spendry return (ENOTDIR); 54759255Spendry 54859255Spendry default: 54959255Spendry break; 55059255Spendry } 55159255Spendry 55254049Spendry fdp = uio->uio_procp->p_fd; 55359255Spendry 55459255Spendry if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 55559255Spendry struct dirent d; 55659255Spendry struct dirent *dp = &d; 55759255Spendry struct dirtmp *dt; 55859255Spendry 55959255Spendry i = uio->uio_offset / UIO_MX; 56059255Spendry error = 0; 56159255Spendry 56259255Spendry while (uio->uio_resid > 0) { 56359255Spendry dt = &rootent[i]; 56459255Spendry if (dt->d_fileno == 0) { 56559255Spendry /**eofflagp = 1;*/ 56659255Spendry break; 56759255Spendry } 56859255Spendry i++; 56959255Spendry 57059255Spendry switch (dt->d_fileno) { 57159255Spendry case FD_CTTY: 57259255Spendry if (cttyvp(uio->uio_procp) == NULL) 57359255Spendry continue; 57459255Spendry break; 57559255Spendry 57659255Spendry case FD_STDIN: 57759255Spendry case FD_STDOUT: 57859255Spendry case FD_STDERR: 57964276Smckusick if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles) 58059255Spendry continue; 58164276Smckusick if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL) 58259255Spendry continue; 58359255Spendry break; 58459255Spendry } 58564276Smckusick bzero((caddr_t) dp, UIO_MX); 58659255Spendry dp->d_fileno = dt->d_fileno; 58759255Spendry dp->d_namlen = dt->d_namlen; 58859255Spendry dp->d_type = DT_UNKNOWN; 58959255Spendry dp->d_reclen = dt->d_reclen; 59059255Spendry bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); 59159255Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 59259255Spendry if (error) 59359255Spendry break; 59459255Spendry } 59559255Spendry uio->uio_offset = i * UIO_MX; 59659255Spendry return (error); 59759255Spendry } 59859255Spendry 59954049Spendry i = uio->uio_offset / UIO_MX; 60053838Spendry error = 0; 60154049Spendry while (uio->uio_resid > 0) { 60265513Spendry if (i >= fdp->fd_nfiles) 60353838Spendry break; 60465513Spendry 60553838Spendry if (fdp->fd_ofiles[i] != NULL) { 60654981Spendry struct dirent d; 60754981Spendry struct dirent *dp = &d; 60865513Spendry 60953838Spendry bzero((caddr_t) dp, UIO_MX); 61053838Spendry 61153838Spendry dp->d_namlen = sprintf(dp->d_name, "%d", i); 61253838Spendry dp->d_reclen = UIO_MX; 61354981Spendry dp->d_type = DT_UNKNOWN; 61459255Spendry dp->d_fileno = i + FD_STDIN; 61553838Spendry /* 61653838Spendry * And ship to userland 61753838Spendry */ 61854049Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 61953838Spendry if (error) 62053838Spendry break; 62153838Spendry } 62253838Spendry i++; 62353838Spendry } 62453838Spendry 62554049Spendry uio->uio_offset = i * UIO_MX; 62653838Spendry return (error); 62753838Spendry } 62853838Spendry 62959255Spendry int 63059255Spendry fdesc_readlink(ap) 63159255Spendry struct vop_readlink_args /* { 63259255Spendry struct vnode *a_vp; 63359255Spendry struct uio *a_uio; 63459255Spendry struct ucred *a_cred; 63559255Spendry } */ *ap; 63659255Spendry { 63765513Spendry struct vnode *vp = ap->a_vp; 63859255Spendry int error; 63959255Spendry 64059255Spendry if (vp->v_type != VLNK) 64159255Spendry return (EPERM); 64259255Spendry 64359255Spendry if (VTOFDESC(vp)->fd_type == Flink) { 64459255Spendry char *ln = VTOFDESC(vp)->fd_link; 64559255Spendry error = uiomove(ln, strlen(ln), ap->a_uio); 64659255Spendry } else { 64759255Spendry error = EOPNOTSUPP; 64859255Spendry } 64959255Spendry 65059255Spendry return (error); 65159255Spendry } 65259255Spendry 65365513Spendry int 65459255Spendry fdesc_read(ap) 65559255Spendry struct vop_read_args /* { 65659255Spendry struct vnode *a_vp; 65759255Spendry struct uio *a_uio; 65859255Spendry int a_ioflag; 65959255Spendry struct ucred *a_cred; 66059255Spendry } */ *ap; 66159255Spendry { 66259255Spendry int error = EOPNOTSUPP; 66359255Spendry 66459255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 66559255Spendry case Fctty: 66659255Spendry error = cttyread(devctty, ap->a_uio, ap->a_ioflag); 66759255Spendry break; 66859255Spendry 66959255Spendry default: 67059255Spendry error = EOPNOTSUPP; 67159255Spendry break; 67259255Spendry } 67359255Spendry 67459255Spendry return (error); 67559255Spendry } 67659255Spendry 67765513Spendry int 67859255Spendry fdesc_write(ap) 67959255Spendry struct vop_write_args /* { 68059255Spendry struct vnode *a_vp; 68159255Spendry struct uio *a_uio; 68259255Spendry int a_ioflag; 68359255Spendry struct ucred *a_cred; 68459255Spendry } */ *ap; 68559255Spendry { 68659255Spendry int error = EOPNOTSUPP; 68759255Spendry 68859255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 68959255Spendry case Fctty: 69059255Spendry error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); 69159255Spendry break; 69259255Spendry 69359255Spendry default: 69459255Spendry error = EOPNOTSUPP; 69559255Spendry break; 69659255Spendry } 69759255Spendry 69859255Spendry return (error); 69959255Spendry } 70059255Spendry 70165513Spendry int 70259255Spendry fdesc_ioctl(ap) 70359255Spendry struct vop_ioctl_args /* { 70459255Spendry struct vnode *a_vp; 70559255Spendry int a_command; 70659255Spendry caddr_t a_data; 70759255Spendry int a_fflag; 70859255Spendry struct ucred *a_cred; 70959255Spendry struct proc *a_p; 71059255Spendry } */ *ap; 71159255Spendry { 71259255Spendry int error = EOPNOTSUPP; 71359255Spendry 71459255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 71559255Spendry case Fctty: 71659255Spendry error = cttyioctl(devctty, ap->a_command, ap->a_data, 71759255Spendry ap->a_fflag, ap->a_p); 71859255Spendry break; 71959255Spendry 72059255Spendry default: 72159255Spendry error = EOPNOTSUPP; 72259255Spendry break; 72359255Spendry } 72459255Spendry 72559255Spendry return (error); 72659255Spendry } 72759255Spendry 72865513Spendry int 72959255Spendry fdesc_select(ap) 73059255Spendry struct vop_select_args /* { 73159255Spendry struct vnode *a_vp; 73259255Spendry int a_which; 73359255Spendry int a_fflags; 73459255Spendry struct ucred *a_cred; 73559255Spendry struct proc *a_p; 73659255Spendry } */ *ap; 73759255Spendry { 73859255Spendry int error = EOPNOTSUPP; 73959255Spendry 74059255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 74159255Spendry case Fctty: 74259255Spendry error = cttyselect(devctty, ap->a_fflags, ap->a_p); 74359255Spendry break; 74459255Spendry 74559255Spendry default: 74659255Spendry error = EOPNOTSUPP; 74759255Spendry break; 74859255Spendry } 74959255Spendry 75059255Spendry return (error); 75159255Spendry } 75259255Spendry 75365513Spendry int 75455017Smckusick fdesc_inactive(ap) 75555017Smckusick struct vop_inactive_args /* { 75655017Smckusick struct vnode *a_vp; 75755017Smckusick } */ *ap; 75853838Spendry { 75954049Spendry struct vnode *vp = ap->a_vp; 76054049Spendry 76153838Spendry /* 76253838Spendry * Clear out the v_type field to avoid 76353838Spendry * nasty things happening in vgone(). 76453838Spendry */ 76554049Spendry vp->v_type = VNON; 76653838Spendry return (0); 76753838Spendry } 76853838Spendry 76965513Spendry int 77055017Smckusick fdesc_reclaim(ap) 77155017Smckusick struct vop_reclaim_args /* { 77255017Smckusick struct vnode *a_vp; 77355017Smckusick } */ *ap; 77453838Spendry { 77553838Spendry struct vnode *vp = ap->a_vp; 77659255Spendry 77765513Spendry remque(VTOFDESC(vp)); 77865513Spendry FREE(vp->v_data, M_TEMP); 77965513Spendry vp->v_data = 0; 78065513Spendry 78153838Spendry return (0); 78253838Spendry } 78353838Spendry 78453838Spendry /* 78565743Spendry * Return POSIX pathconf information applicable to special devices. 78665743Spendry */ 78765743Spendry fdesc_pathconf(ap) 78865743Spendry struct vop_pathconf_args /* { 78965743Spendry struct vnode *a_vp; 79065743Spendry int a_name; 79165743Spendry int *a_retval; 79265743Spendry } */ *ap; 79365743Spendry { 79465743Spendry 79565743Spendry switch (ap->a_name) { 79665743Spendry case _PC_LINK_MAX: 79765743Spendry *ap->a_retval = LINK_MAX; 79865743Spendry return (0); 79965743Spendry case _PC_MAX_CANON: 80065743Spendry *ap->a_retval = MAX_CANON; 80165743Spendry return (0); 80265743Spendry case _PC_MAX_INPUT: 80365743Spendry *ap->a_retval = MAX_INPUT; 80465743Spendry return (0); 80565743Spendry case _PC_PIPE_BUF: 80665743Spendry *ap->a_retval = PIPE_BUF; 80765743Spendry return (0); 80865743Spendry case _PC_CHOWN_RESTRICTED: 80965743Spendry *ap->a_retval = 1; 81065743Spendry return (0); 81165743Spendry case _PC_VDISABLE: 81265743Spendry *ap->a_retval = _POSIX_VDISABLE; 81365743Spendry return (0); 81465743Spendry default: 81565743Spendry return (EINVAL); 81665743Spendry } 81765743Spendry /* NOTREACHED */ 81865743Spendry } 81965743Spendry 82065743Spendry /* 82153838Spendry * Print out the contents of a /dev/fd vnode. 82253838Spendry */ 82353838Spendry /* ARGSUSED */ 82465513Spendry int 82555017Smckusick fdesc_print(ap) 82655017Smckusick struct vop_print_args /* { 82755017Smckusick struct vnode *a_vp; 82855017Smckusick } */ *ap; 82953838Spendry { 83055017Smckusick 83153838Spendry printf("tag VT_NON, fdesc vnode\n"); 83255017Smckusick return (0); 83353838Spendry } 83453838Spendry 83553838Spendry /*void*/ 83665513Spendry int 83755017Smckusick fdesc_vfree(ap) 83855017Smckusick struct vop_vfree_args /* { 83955017Smckusick struct vnode *a_pvp; 84055017Smckusick ino_t a_ino; 84155017Smckusick int a_mode; 84255017Smckusick } */ *ap; 84353838Spendry { 84453838Spendry 84555017Smckusick return (0); 84653838Spendry } 84753838Spendry 84853838Spendry /* 84953838Spendry * /dev/fd vnode unsupported operation 85053838Spendry */ 85165513Spendry int 85253838Spendry fdesc_enotsupp() 85353838Spendry { 85455017Smckusick 85553838Spendry return (EOPNOTSUPP); 85653838Spendry } 85753838Spendry 85853838Spendry /* 85953838Spendry * /dev/fd "should never get here" operation 86053838Spendry */ 86165513Spendry int 86253838Spendry fdesc_badop() 86353838Spendry { 86455017Smckusick 86553838Spendry panic("fdesc: bad op"); 86653838Spendry /* NOTREACHED */ 86753838Spendry } 86853838Spendry 86953838Spendry /* 87053838Spendry * /dev/fd vnode null operation 87153838Spendry */ 87265513Spendry int 87353838Spendry fdesc_nullop() 87453838Spendry { 87555017Smckusick 87653838Spendry return (0); 87753838Spendry } 87853838Spendry 87953838Spendry #define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp) 88053838Spendry #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp) 88153838Spendry #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) 88253838Spendry #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) 88353838Spendry #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp) 88453838Spendry #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 88553838Spendry #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) 88653838Spendry #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp) 88753838Spendry #define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp) 88853838Spendry #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp) 88953838Spendry #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp) 89053838Spendry #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp) 89155017Smckusick #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp) 89253838Spendry #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 89353838Spendry #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) 89453838Spendry #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 89553838Spendry #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) 89653838Spendry #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) 89753838Spendry #define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 89855017Smckusick #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp) 89955170Spendry #define fdesc_blkatoff \ 90055017Smckusick ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp) 90153838Spendry #define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp) 90253838Spendry #define fdesc_valloc ((int(*) __P(( \ 90353838Spendry struct vnode *pvp, \ 90453838Spendry int mode, \ 90553838Spendry struct ucred *cred, \ 90653838Spendry struct vnode **vpp))) fdesc_enotsupp) 90755170Spendry #define fdesc_truncate \ 90855017Smckusick ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp) 90953838Spendry #define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp) 91053838Spendry #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp) 91153838Spendry 91253838Spendry int (**fdesc_vnodeop_p)(); 91353838Spendry struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 91453838Spendry { &vop_default_desc, vn_default_error }, 91553838Spendry { &vop_lookup_desc, fdesc_lookup }, /* lookup */ 91653838Spendry { &vop_create_desc, fdesc_create }, /* create */ 91753838Spendry { &vop_mknod_desc, fdesc_mknod }, /* mknod */ 91855017Smckusick { &vop_open_desc, fdesc_open }, /* open */ 91953838Spendry { &vop_close_desc, fdesc_close }, /* close */ 92053838Spendry { &vop_access_desc, fdesc_access }, /* access */ 92153838Spendry { &vop_getattr_desc, fdesc_getattr }, /* getattr */ 92253838Spendry { &vop_setattr_desc, fdesc_setattr }, /* setattr */ 92355017Smckusick { &vop_read_desc, fdesc_read }, /* read */ 92453838Spendry { &vop_write_desc, fdesc_write }, /* write */ 92553838Spendry { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */ 92653838Spendry { &vop_select_desc, fdesc_select }, /* select */ 92755017Smckusick { &vop_mmap_desc, fdesc_mmap }, /* mmap */ 92853838Spendry { &vop_fsync_desc, fdesc_fsync }, /* fsync */ 92955017Smckusick { &vop_seek_desc, fdesc_seek }, /* seek */ 93053838Spendry { &vop_remove_desc, fdesc_remove }, /* remove */ 93155017Smckusick { &vop_link_desc, fdesc_link }, /* link */ 93253838Spendry { &vop_rename_desc, fdesc_rename }, /* rename */ 93353838Spendry { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */ 93453838Spendry { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */ 93553838Spendry { &vop_symlink_desc, fdesc_symlink }, /* symlink */ 93653838Spendry { &vop_readdir_desc, fdesc_readdir }, /* readdir */ 93753838Spendry { &vop_readlink_desc, fdesc_readlink }, /* readlink */ 93853838Spendry { &vop_abortop_desc, fdesc_abortop }, /* abortop */ 93953838Spendry { &vop_inactive_desc, fdesc_inactive }, /* inactive */ 94053838Spendry { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */ 94155017Smckusick { &vop_lock_desc, fdesc_lock }, /* lock */ 94253838Spendry { &vop_unlock_desc, fdesc_unlock }, /* unlock */ 94355017Smckusick { &vop_bmap_desc, fdesc_bmap }, /* bmap */ 94453838Spendry { &vop_strategy_desc, fdesc_strategy }, /* strategy */ 94553838Spendry { &vop_print_desc, fdesc_print }, /* print */ 94653838Spendry { &vop_islocked_desc, fdesc_islocked }, /* islocked */ 94765743Spendry { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */ 94853838Spendry { &vop_advlock_desc, fdesc_advlock }, /* advlock */ 94953838Spendry { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */ 95053838Spendry { &vop_valloc_desc, fdesc_valloc }, /* valloc */ 95153838Spendry { &vop_vfree_desc, fdesc_vfree }, /* vfree */ 95253838Spendry { &vop_truncate_desc, fdesc_truncate }, /* truncate */ 95353838Spendry { &vop_update_desc, fdesc_update }, /* update */ 95453838Spendry { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */ 95553838Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 95653838Spendry }; 95753838Spendry struct vnodeopv_desc fdesc_vnodeop_opv_desc = 95853838Spendry { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 959