153838Spendry /* 263557Sbostic * Copyright (c) 1992, 1993 363557Sbostic * The Regents of the University of California. All rights reserved. 453838Spendry * All rights reserved. 553838Spendry * 653838Spendry * This code is derived from software donated to Berkeley by 753838Spendry * Jan-Simon Pendry. 853838Spendry * 953838Spendry * %sccs.include.redist.c% 1053838Spendry * 11*65743Spendry * @(#)fdesc_vnops.c 8.8 (Berkeley) 01/14/94 1253838Spendry * 1359255Spendry * $Id: fdesc_vnops.c,v 1.12 1993/04/06 16:17:17 jsp Exp $ 1453838Spendry */ 1553838Spendry 1653838Spendry /* 1753838Spendry * /dev/fd Filesystem 1853838Spendry */ 1953838Spendry 2053838Spendry #include <sys/param.h> 2153838Spendry #include <sys/systm.h> 2253838Spendry #include <sys/types.h> 2353838Spendry #include <sys/time.h> 2453838Spendry #include <sys/proc.h> 2559255Spendry #include <sys/kernel.h> /* boottime */ 2653838Spendry #include <sys/resourcevar.h> 2753838Spendry #include <sys/filedesc.h> 2853838Spendry #include <sys/vnode.h> 2953838Spendry #include <sys/malloc.h> 3053838Spendry #include <sys/file.h> 3153838Spendry #include <sys/stat.h> 3253838Spendry #include <sys/mount.h> 3353838Spendry #include <sys/namei.h> 3453838Spendry #include <sys/buf.h> 3554981Spendry #include <sys/dirent.h> 3655017Smckusick #include <miscfs/fdesc/fdesc.h> 3753838Spendry 3864629Sbostic #define cttyvp(p) ((p)->p_flag & P_CONTROLT ? (p)->p_session->s_ttyvp : NULL) 3959255Spendry 4059255Spendry #define FDL_WANT 0x01 4159255Spendry #define FDL_LOCKED 0x02 4265513Spendry static int fdcache_lock; 4359255Spendry 4465513Spendry dev_t devctty; 4565513Spendry 4659255Spendry #if (FD_STDIN != FD_STDOUT-1) || (FD_STDOUT != FD_STDERR-1) 4759255Spendry FD_STDIN, FD_STDOUT, FD_STDERR must be a sequence n, n+1, n+2 4859255Spendry #endif 4959255Spendry 5065513Spendry #define NFDCACHE 3 5165513Spendry #define FD_NHASH(ix) ((ix) & NFDCACHE) 5265513Spendry 5365513Spendry /* 5465513Spendry * Cache head 5565513Spendry */ 5665513Spendry struct fdcache { 5765513Spendry struct fdescnode *fc_forw; 5865513Spendry struct fdescnode *fc_back; 5965513Spendry }; 6065513Spendry 6165513Spendry static struct fdcache fdcache[NFDCACHE]; 6265513Spendry 6365513Spendry /* 6465513Spendry * Initialise cache headers 6565513Spendry */ 6665513Spendry fdesc_init() 6765513Spendry { 6865513Spendry struct fdcache *fc; 6965513Spendry 7065513Spendry devctty = makedev(nchrdev, 0); 7165513Spendry 7265513Spendry for (fc = fdcache; fc < fdcache + NFDCACHE; fc++) 7365513Spendry fc->fc_forw = fc->fc_back = (struct fdescnode *) fc; 7465513Spendry } 7565513Spendry 7665513Spendry /* 7765513Spendry * Compute hash list for given target vnode 7865513Spendry */ 7965513Spendry static struct fdcache * 8065513Spendry fdesc_hash(ix) 8165513Spendry int ix; 8265513Spendry { 8365513Spendry 8465513Spendry return (&fdcache[FD_NHASH(ix)]); 8565513Spendry } 8665513Spendry 8765513Spendry int 8859255Spendry fdesc_allocvp(ftype, ix, mp, vpp) 8959255Spendry fdntype ftype; 9059255Spendry int ix; 9159255Spendry struct mount *mp; 9259255Spendry struct vnode **vpp; 9359255Spendry { 9465513Spendry struct fdcache *fc; 9565513Spendry struct fdescnode *fd; 9659255Spendry int error = 0; 9759255Spendry 9859457Spendry loop: 9965513Spendry fc = fdesc_hash(ix); 10065513Spendry for (fd = fc->fc_forw; fd != (struct fdescnode *) fc; fd = fd->fd_forw) { 10165513Spendry if (fd->fd_ix == ix && fd->fd_vnode->v_mount == mp) { 10265513Spendry if (vget(fd->fd_vnode, 0)) 10359457Spendry goto loop; 10465513Spendry *vpp = fd->fd_vnode; 10559255Spendry return (error); 10659255Spendry } 10759255Spendry } 10859255Spendry 10959255Spendry /* 11059255Spendry * otherwise lock the array while we call getnewvnode 11159255Spendry * since that can block. 11259255Spendry */ 11365513Spendry if (fdcache_lock & FDL_LOCKED) { 11465513Spendry fdcache_lock |= FDL_WANT; 11565513Spendry sleep((caddr_t) &fdcache_lock, PINOD); 11659457Spendry goto loop; 11759255Spendry } 11865513Spendry fdcache_lock |= FDL_LOCKED; 11959255Spendry 12065380Spendry error = getnewvnode(VT_FDESC, mp, fdesc_vnodeop_p, vpp); 12159255Spendry if (error) 12259255Spendry goto out; 12365513Spendry MALLOC(fd, void *, sizeof(struct fdescnode), M_TEMP, M_WAITOK); 12465513Spendry (*vpp)->v_data = fd; 12565513Spendry fd->fd_vnode = *vpp; 12665513Spendry fd->fd_type = ftype; 12765513Spendry fd->fd_fd = -1; 12865513Spendry fd->fd_link = 0; 12965513Spendry fd->fd_ix = ix; 13065513Spendry fc = fdesc_hash(ix); 13165513Spendry insque(fd, fc); 13259255Spendry 13359255Spendry out:; 13465513Spendry fdcache_lock &= ~FDL_LOCKED; 13559255Spendry 13665513Spendry if (fdcache_lock & FDL_WANT) { 13765513Spendry fdcache_lock &= ~FDL_WANT; 13865513Spendry wakeup((caddr_t) &fdcache_lock); 13959255Spendry } 14059255Spendry 14159255Spendry return (error); 14259255Spendry } 14359255Spendry 14453838Spendry /* 14553838Spendry * vp is the current namei directory 14653838Spendry * ndp is the name to locate in that directory... 14753838Spendry */ 14865513Spendry int 14955017Smckusick fdesc_lookup(ap) 15055017Smckusick struct vop_lookup_args /* { 15155017Smckusick struct vnode * a_dvp; 15255017Smckusick struct vnode ** a_vpp; 15355017Smckusick struct componentname * a_cnp; 15455017Smckusick } */ *ap; 15553838Spendry { 15654049Spendry struct vnode **vpp = ap->a_vpp; 15754049Spendry struct vnode *dvp = ap->a_dvp; 15853838Spendry char *pname; 15953838Spendry struct proc *p; 16053838Spendry int nfiles; 16153838Spendry unsigned fd; 16253838Spendry int error; 16353838Spendry struct vnode *fvp; 16459255Spendry char *ln; 16553838Spendry 16653838Spendry pname = ap->a_cnp->cn_nameptr; 16753838Spendry if (ap->a_cnp->cn_namelen == 1 && *pname == '.') { 16854049Spendry *vpp = dvp; 16954049Spendry VREF(dvp); 17059255Spendry VOP_LOCK(dvp); 17153838Spendry return (0); 17253838Spendry } 17353838Spendry 17453838Spendry p = ap->a_cnp->cn_proc; 17553838Spendry nfiles = p->p_fd->fd_nfiles; 17653838Spendry 17759255Spendry switch (VTOFDESC(dvp)->fd_type) { 17859255Spendry default: 17959255Spendry case Flink: 18059255Spendry case Fdesc: 18159255Spendry case Fctty: 18259255Spendry error = ENOTDIR; 18359255Spendry goto bad; 18459255Spendry 18559255Spendry case Froot: 18659255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "fd", 2) == 0) { 18759255Spendry error = fdesc_allocvp(Fdevfd, FD_DEVFD, dvp->v_mount, &fvp); 18859255Spendry if (error) 18959255Spendry goto bad; 19059255Spendry *vpp = fvp; 19159255Spendry fvp->v_type = VDIR; 19259255Spendry VOP_LOCK(fvp); 19359255Spendry return (0); 19459255Spendry } 19559255Spendry 19659255Spendry if (ap->a_cnp->cn_namelen == 3 && bcmp(pname, "tty", 3) == 0) { 19759255Spendry struct vnode *ttyvp = cttyvp(p); 19859255Spendry if (ttyvp == NULL) { 19959255Spendry error = ENXIO; 20059255Spendry goto bad; 20159255Spendry } 20259255Spendry error = fdesc_allocvp(Fctty, FD_CTTY, dvp->v_mount, &fvp); 20359255Spendry if (error) 20459255Spendry goto bad; 20559255Spendry *vpp = fvp; 20659255Spendry fvp->v_type = VFIFO; 20759255Spendry VOP_LOCK(fvp); 20859255Spendry return (0); 20959255Spendry } 21059255Spendry 21159255Spendry ln = 0; 21259255Spendry switch (ap->a_cnp->cn_namelen) { 21359255Spendry case 5: 21459255Spendry if (bcmp(pname, "stdin", 5) == 0) { 21559255Spendry ln = "fd/0"; 21659255Spendry fd = FD_STDIN; 21759255Spendry } 21853838Spendry break; 21959255Spendry case 6: 22059255Spendry if (bcmp(pname, "stdout", 6) == 0) { 22159255Spendry ln = "fd/1"; 22259255Spendry fd = FD_STDOUT; 22359255Spendry } else 22459255Spendry if (bcmp(pname, "stderr", 6) == 0) { 22559255Spendry ln = "fd/2"; 22659255Spendry fd = FD_STDERR; 22759255Spendry } 22859255Spendry break; 22959255Spendry } 23053838Spendry 23159255Spendry if (ln) { 23259255Spendry error = fdesc_allocvp(Flink, fd, dvp->v_mount, &fvp); 23359255Spendry if (error) 23459255Spendry goto bad; 23559255Spendry VTOFDESC(fvp)->fd_link = ln; 23659255Spendry *vpp = fvp; 23759255Spendry fvp->v_type = VLNK; 23859255Spendry VOP_LOCK(fvp); 23959255Spendry return (0); 24059255Spendry } else { 24159255Spendry error = ENOENT; 24259255Spendry goto bad; 24359255Spendry } 24453838Spendry 24565513Spendry /* FALL THROUGH */ 24653838Spendry 24759255Spendry case Fdevfd: 24859255Spendry if (ap->a_cnp->cn_namelen == 2 && bcmp(pname, "..", 2) == 0) { 24959255Spendry error = fdesc_root(dvp->v_mount, vpp); 25059255Spendry return (error); 25159255Spendry } 25259255Spendry 25359255Spendry fd = 0; 25459255Spendry while (*pname >= '0' && *pname <= '9') { 25559255Spendry fd = 10 * fd + *pname++ - '0'; 25659255Spendry if (fd >= nfiles) 25759255Spendry break; 25859255Spendry } 25959255Spendry 26059255Spendry if (*pname != '\0') { 26159255Spendry error = ENOENT; 26259255Spendry goto bad; 26359255Spendry } 26459255Spendry 26559255Spendry if (fd >= nfiles || p->p_fd->fd_ofiles[fd] == NULL) { 26659255Spendry error = EBADF; 26759255Spendry goto bad; 26859255Spendry } 26959255Spendry 27059255Spendry error = fdesc_allocvp(Fdesc, FD_DESC+fd, dvp->v_mount, &fvp); 27159255Spendry if (error) 27259255Spendry goto bad; 27359255Spendry VTOFDESC(fvp)->fd_fd = fd; 27459255Spendry *vpp = fvp; 27559255Spendry return (0); 27659255Spendry } 27753838Spendry 27853838Spendry bad:; 27954049Spendry *vpp = NULL; 28053838Spendry return (error); 28153838Spendry } 28253838Spendry 28365513Spendry int 28455017Smckusick fdesc_open(ap) 28555017Smckusick struct vop_open_args /* { 28655017Smckusick struct vnode *a_vp; 28755017Smckusick int a_mode; 28855017Smckusick struct ucred *a_cred; 28955017Smckusick struct proc *a_p; 29055017Smckusick } */ *ap; 29153838Spendry { 29254049Spendry struct vnode *vp = ap->a_vp; 29359255Spendry int error = 0; 29454049Spendry 29559255Spendry switch (VTOFDESC(vp)->fd_type) { 29659255Spendry case Fdesc: 29759255Spendry /* 29859255Spendry * XXX Kludge: set p->p_dupfd to contain the value of the 29959255Spendry * the file descriptor being sought for duplication. The error 30059255Spendry * return ensures that the vnode for this device will be 30159255Spendry * released by vn_open. Open will detect this special error and 30259255Spendry * take the actions in dupfdopen. Other callers of vn_open or 30359255Spendry * VOP_OPEN will simply report the error. 30459255Spendry */ 30559255Spendry ap->a_p->p_dupfd = VTOFDESC(vp)->fd_fd; /* XXX */ 30659255Spendry error = ENODEV; 30759255Spendry break; 30853838Spendry 30959255Spendry case Fctty: 31059255Spendry error = cttyopen(devctty, ap->a_mode, 0, ap->a_p); 31159255Spendry break; 31259255Spendry } 31359255Spendry 31459255Spendry return (error); 31553838Spendry } 31653838Spendry 31753838Spendry static int 31853838Spendry fdesc_attr(fd, vap, cred, p) 31953838Spendry int fd; 32053838Spendry struct vattr *vap; 32153838Spendry struct ucred *cred; 32253838Spendry struct proc *p; 32353838Spendry { 32453838Spendry struct filedesc *fdp = p->p_fd; 32553838Spendry struct file *fp; 32659562Spendry struct stat stb; 32753838Spendry int error; 32853838Spendry 32965513Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) 33053838Spendry return (EBADF); 33153838Spendry 33253838Spendry switch (fp->f_type) { 33353838Spendry case DTYPE_VNODE: 33453838Spendry error = VOP_GETATTR((struct vnode *) fp->f_data, vap, cred, p); 33559561Spendry if (error == 0 && vap->va_type == VDIR) { 33659561Spendry /* 33759561Spendry * don't allow directories to show up because 33859561Spendry * that causes loops in the namespace. 33959561Spendry */ 34059561Spendry vap->va_type = VFIFO; 34159561Spendry } 34253838Spendry break; 34353838Spendry 34453838Spendry case DTYPE_SOCKET: 34559562Spendry error = soo_stat((struct socket *)fp->f_data, &stb); 34659562Spendry if (error == 0) { 34759562Spendry vattr_null(vap); 34859562Spendry vap->va_type = VSOCK; 34959562Spendry vap->va_mode = stb.st_mode; 35059562Spendry vap->va_nlink = stb.st_nlink; 35159562Spendry vap->va_uid = stb.st_uid; 35259562Spendry vap->va_gid = stb.st_gid; 35359562Spendry vap->va_fsid = stb.st_dev; 35459562Spendry vap->va_fileid = stb.st_ino; 35559562Spendry vap->va_size = stb.st_size; 35659562Spendry vap->va_blocksize = stb.st_blksize; 35759562Spendry vap->va_atime = stb.st_atimespec; 35859562Spendry vap->va_mtime = stb.st_mtimespec; 35959562Spendry vap->va_ctime = stb.st_ctimespec; 36059562Spendry vap->va_gen = stb.st_gen; 36159562Spendry vap->va_flags = stb.st_flags; 36259562Spendry vap->va_rdev = stb.st_rdev; 36359562Spendry vap->va_bytes = stb.st_blocks * stb.st_blksize; 36459562Spendry } 36553838Spendry break; 36653838Spendry 36753838Spendry default: 36853838Spendry panic("fdesc attr"); 36953838Spendry break; 37053838Spendry } 37153838Spendry 37253838Spendry return (error); 37353838Spendry } 37453838Spendry 37565513Spendry int 37655017Smckusick fdesc_getattr(ap) 37755017Smckusick struct vop_getattr_args /* { 37855017Smckusick struct vnode *a_vp; 37955017Smckusick struct vattr *a_vap; 38055017Smckusick struct ucred *a_cred; 38155017Smckusick struct proc *a_p; 38255017Smckusick } */ *ap; 38353838Spendry { 38454049Spendry struct vnode *vp = ap->a_vp; 38554049Spendry struct vattr *vap = ap->a_vap; 38653838Spendry unsigned fd; 38763556Smckusick int error = 0; 38853838Spendry 38959255Spendry switch (VTOFDESC(vp)->fd_type) { 39059255Spendry case Froot: 39159255Spendry case Fdevfd: 39259255Spendry case Flink: 39359255Spendry case Fctty: 39454049Spendry bzero((caddr_t) vap, sizeof(*vap)); 39554049Spendry vattr_null(vap); 39659255Spendry vap->va_fileid = VTOFDESC(vp)->fd_ix; 39759255Spendry 39859255Spendry switch (VTOFDESC(vp)->fd_type) { 39959255Spendry case Flink: 40059255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 40159255Spendry vap->va_type = VLNK; 40259255Spendry vap->va_nlink = 1; 40359255Spendry vap->va_size = strlen(VTOFDESC(vp)->fd_link); 40459255Spendry break; 40559255Spendry 40659255Spendry case Fctty: 40759255Spendry vap->va_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; 40859255Spendry vap->va_type = VFIFO; 40959255Spendry vap->va_nlink = 1; 41059255Spendry vap->va_size = 0; 41159255Spendry break; 41259255Spendry 41359255Spendry default: 41459255Spendry vap->va_mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH; 41559255Spendry vap->va_type = VDIR; 41659255Spendry vap->va_nlink = 2; 41759255Spendry vap->va_size = DEV_BSIZE; 41859255Spendry break; 41959255Spendry } 42054049Spendry vap->va_uid = 0; 42154049Spendry vap->va_gid = 0; 42254049Spendry vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 42354049Spendry vap->va_blocksize = DEV_BSIZE; 42459255Spendry vap->va_atime.ts_sec = boottime.tv_sec; 42559255Spendry vap->va_atime.ts_nsec = 0; 42654049Spendry vap->va_mtime = vap->va_atime; 42764276Smckusick vap->va_ctime = vap->va_mtime; 42854049Spendry vap->va_gen = 0; 42954049Spendry vap->va_flags = 0; 43054049Spendry vap->va_rdev = 0; 43154049Spendry vap->va_bytes = 0; 43259255Spendry break; 43359255Spendry 43459255Spendry case Fdesc: 43559255Spendry fd = VTOFDESC(vp)->fd_fd; 43659255Spendry error = fdesc_attr(fd, vap, ap->a_cred, ap->a_p); 43759255Spendry break; 43859255Spendry 43959255Spendry default: 44059255Spendry panic("fdesc_getattr"); 44159255Spendry break; 44253838Spendry } 44353838Spendry 44453838Spendry if (error == 0) 44554049Spendry vp->v_type = vap->va_type; 44659255Spendry 44753838Spendry return (error); 44853838Spendry } 44953838Spendry 45065513Spendry int 45155017Smckusick fdesc_setattr(ap) 45255017Smckusick struct vop_setattr_args /* { 45355017Smckusick struct vnode *a_vp; 45455017Smckusick struct vattr *a_vap; 45555017Smckusick struct ucred *a_cred; 45655017Smckusick struct proc *a_p; 45755017Smckusick } */ *ap; 45853838Spendry { 45953838Spendry struct filedesc *fdp = ap->a_p->p_fd; 46053838Spendry struct file *fp; 46153838Spendry unsigned fd; 46253838Spendry int error; 46353838Spendry 46453838Spendry /* 46553838Spendry * Can't mess with the root vnode 46653838Spendry */ 46759255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 46859255Spendry case Fdesc: 46959255Spendry break; 47059255Spendry 47159255Spendry case Fctty: 47259255Spendry return (0); 47359255Spendry 47459255Spendry default: 47553838Spendry return (EACCES); 47659255Spendry } 47753838Spendry 47859255Spendry fd = VTOFDESC(ap->a_vp)->fd_fd; 47953838Spendry if (fd >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[fd]) == NULL) { 48053838Spendry return (EBADF); 48153838Spendry } 48253838Spendry 48353838Spendry /* 48453838Spendry * Can setattr the underlying vnode, but not sockets! 48553838Spendry */ 48653838Spendry switch (fp->f_type) { 48753838Spendry case DTYPE_VNODE: 48853838Spendry error = VOP_SETATTR((struct vnode *) fp->f_data, ap->a_vap, ap->a_cred, ap->a_p); 48953838Spendry break; 49053838Spendry 49153838Spendry case DTYPE_SOCKET: 49258646Spendry error = 0; 49353838Spendry break; 49453838Spendry 49553838Spendry default: 49653838Spendry panic("fdesc setattr"); 49753838Spendry break; 49853838Spendry } 49953838Spendry 50053838Spendry return (error); 50153838Spendry } 50253838Spendry 50359255Spendry #define UIO_MX 16 50459255Spendry 50559255Spendry static struct dirtmp { 50659255Spendry u_long d_fileno; 50759255Spendry u_short d_reclen; 50859255Spendry u_short d_namlen; 50959255Spendry char d_name[8]; 51059255Spendry } rootent[] = { 51159255Spendry { FD_DEVFD, UIO_MX, 2, "fd" }, 51259255Spendry { FD_STDIN, UIO_MX, 5, "stdin" }, 51359255Spendry { FD_STDOUT, UIO_MX, 6, "stdout" }, 51459255Spendry { FD_STDERR, UIO_MX, 6, "stderr" }, 51559255Spendry { FD_CTTY, UIO_MX, 3, "tty" }, 51659255Spendry { 0 } 51759255Spendry }; 51859255Spendry 51965513Spendry int 52055017Smckusick fdesc_readdir(ap) 52155017Smckusick struct vop_readdir_args /* { 52255017Smckusick struct vnode *a_vp; 52355017Smckusick struct uio *a_uio; 52455017Smckusick struct ucred *a_cred; 52555017Smckusick } */ *ap; 52653838Spendry { 52754049Spendry struct uio *uio = ap->a_uio; 52853838Spendry struct filedesc *fdp; 52953838Spendry int i; 53053838Spendry int error; 53153838Spendry 53259255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 53359255Spendry case Fctty: 53459255Spendry return (0); 53553838Spendry 53659255Spendry case Fdesc: 53759255Spendry return (ENOTDIR); 53859255Spendry 53959255Spendry default: 54059255Spendry break; 54159255Spendry } 54259255Spendry 54354049Spendry fdp = uio->uio_procp->p_fd; 54459255Spendry 54559255Spendry if (VTOFDESC(ap->a_vp)->fd_type == Froot) { 54659255Spendry struct dirent d; 54759255Spendry struct dirent *dp = &d; 54859255Spendry struct dirtmp *dt; 54959255Spendry 55059255Spendry i = uio->uio_offset / UIO_MX; 55159255Spendry error = 0; 55259255Spendry 55359255Spendry while (uio->uio_resid > 0) { 55459255Spendry dt = &rootent[i]; 55559255Spendry if (dt->d_fileno == 0) { 55659255Spendry /**eofflagp = 1;*/ 55759255Spendry break; 55859255Spendry } 55959255Spendry i++; 56059255Spendry 56159255Spendry switch (dt->d_fileno) { 56259255Spendry case FD_CTTY: 56359255Spendry if (cttyvp(uio->uio_procp) == NULL) 56459255Spendry continue; 56559255Spendry break; 56659255Spendry 56759255Spendry case FD_STDIN: 56859255Spendry case FD_STDOUT: 56959255Spendry case FD_STDERR: 57064276Smckusick if ((dt->d_fileno-FD_STDIN) >= fdp->fd_nfiles) 57159255Spendry continue; 57264276Smckusick if (fdp->fd_ofiles[dt->d_fileno-FD_STDIN] == NULL) 57359255Spendry continue; 57459255Spendry break; 57559255Spendry } 57664276Smckusick bzero((caddr_t) dp, UIO_MX); 57759255Spendry dp->d_fileno = dt->d_fileno; 57859255Spendry dp->d_namlen = dt->d_namlen; 57959255Spendry dp->d_type = DT_UNKNOWN; 58059255Spendry dp->d_reclen = dt->d_reclen; 58159255Spendry bcopy(dt->d_name, dp->d_name, dp->d_namlen+1); 58259255Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 58359255Spendry if (error) 58459255Spendry break; 58559255Spendry } 58659255Spendry uio->uio_offset = i * UIO_MX; 58759255Spendry return (error); 58859255Spendry } 58959255Spendry 59054049Spendry i = uio->uio_offset / UIO_MX; 59153838Spendry error = 0; 59254049Spendry while (uio->uio_resid > 0) { 59365513Spendry if (i >= fdp->fd_nfiles) 59453838Spendry break; 59565513Spendry 59653838Spendry if (fdp->fd_ofiles[i] != NULL) { 59754981Spendry struct dirent d; 59854981Spendry struct dirent *dp = &d; 59965513Spendry 60053838Spendry bzero((caddr_t) dp, UIO_MX); 60153838Spendry 60253838Spendry dp->d_namlen = sprintf(dp->d_name, "%d", i); 60353838Spendry dp->d_reclen = UIO_MX; 60454981Spendry dp->d_type = DT_UNKNOWN; 60559255Spendry dp->d_fileno = i + FD_STDIN; 60653838Spendry /* 60753838Spendry * And ship to userland 60853838Spendry */ 60954049Spendry error = uiomove((caddr_t) dp, UIO_MX, uio); 61053838Spendry if (error) 61153838Spendry break; 61253838Spendry } 61353838Spendry i++; 61453838Spendry } 61553838Spendry 61654049Spendry uio->uio_offset = i * UIO_MX; 61753838Spendry return (error); 61853838Spendry } 61953838Spendry 62059255Spendry int 62159255Spendry fdesc_readlink(ap) 62259255Spendry struct vop_readlink_args /* { 62359255Spendry struct vnode *a_vp; 62459255Spendry struct uio *a_uio; 62559255Spendry struct ucred *a_cred; 62659255Spendry } */ *ap; 62759255Spendry { 62865513Spendry struct vnode *vp = ap->a_vp; 62959255Spendry int error; 63059255Spendry 63159255Spendry if (vp->v_type != VLNK) 63259255Spendry return (EPERM); 63359255Spendry 63459255Spendry if (VTOFDESC(vp)->fd_type == Flink) { 63559255Spendry char *ln = VTOFDESC(vp)->fd_link; 63659255Spendry error = uiomove(ln, strlen(ln), ap->a_uio); 63759255Spendry } else { 63859255Spendry error = EOPNOTSUPP; 63959255Spendry } 64059255Spendry 64159255Spendry return (error); 64259255Spendry } 64359255Spendry 64465513Spendry int 64559255Spendry fdesc_read(ap) 64659255Spendry struct vop_read_args /* { 64759255Spendry struct vnode *a_vp; 64859255Spendry struct uio *a_uio; 64959255Spendry int a_ioflag; 65059255Spendry struct ucred *a_cred; 65159255Spendry } */ *ap; 65259255Spendry { 65359255Spendry int error = EOPNOTSUPP; 65459255Spendry 65559255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 65659255Spendry case Fctty: 65759255Spendry error = cttyread(devctty, ap->a_uio, ap->a_ioflag); 65859255Spendry break; 65959255Spendry 66059255Spendry default: 66159255Spendry error = EOPNOTSUPP; 66259255Spendry break; 66359255Spendry } 66459255Spendry 66559255Spendry return (error); 66659255Spendry } 66759255Spendry 66865513Spendry int 66959255Spendry fdesc_write(ap) 67059255Spendry struct vop_write_args /* { 67159255Spendry struct vnode *a_vp; 67259255Spendry struct uio *a_uio; 67359255Spendry int a_ioflag; 67459255Spendry struct ucred *a_cred; 67559255Spendry } */ *ap; 67659255Spendry { 67759255Spendry int error = EOPNOTSUPP; 67859255Spendry 67959255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 68059255Spendry case Fctty: 68159255Spendry error = cttywrite(devctty, ap->a_uio, ap->a_ioflag); 68259255Spendry break; 68359255Spendry 68459255Spendry default: 68559255Spendry error = EOPNOTSUPP; 68659255Spendry break; 68759255Spendry } 68859255Spendry 68959255Spendry return (error); 69059255Spendry } 69159255Spendry 69265513Spendry int 69359255Spendry fdesc_ioctl(ap) 69459255Spendry struct vop_ioctl_args /* { 69559255Spendry struct vnode *a_vp; 69659255Spendry int a_command; 69759255Spendry caddr_t a_data; 69859255Spendry int a_fflag; 69959255Spendry struct ucred *a_cred; 70059255Spendry struct proc *a_p; 70159255Spendry } */ *ap; 70259255Spendry { 70359255Spendry int error = EOPNOTSUPP; 70459255Spendry 70559255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 70659255Spendry case Fctty: 70759255Spendry error = cttyioctl(devctty, ap->a_command, ap->a_data, 70859255Spendry ap->a_fflag, ap->a_p); 70959255Spendry break; 71059255Spendry 71159255Spendry default: 71259255Spendry error = EOPNOTSUPP; 71359255Spendry break; 71459255Spendry } 71559255Spendry 71659255Spendry return (error); 71759255Spendry } 71859255Spendry 71965513Spendry int 72059255Spendry fdesc_select(ap) 72159255Spendry struct vop_select_args /* { 72259255Spendry struct vnode *a_vp; 72359255Spendry int a_which; 72459255Spendry int a_fflags; 72559255Spendry struct ucred *a_cred; 72659255Spendry struct proc *a_p; 72759255Spendry } */ *ap; 72859255Spendry { 72959255Spendry int error = EOPNOTSUPP; 73059255Spendry 73159255Spendry switch (VTOFDESC(ap->a_vp)->fd_type) { 73259255Spendry case Fctty: 73359255Spendry error = cttyselect(devctty, ap->a_fflags, ap->a_p); 73459255Spendry break; 73559255Spendry 73659255Spendry default: 73759255Spendry error = EOPNOTSUPP; 73859255Spendry break; 73959255Spendry } 74059255Spendry 74159255Spendry return (error); 74259255Spendry } 74359255Spendry 74465513Spendry int 74555017Smckusick fdesc_inactive(ap) 74655017Smckusick struct vop_inactive_args /* { 74755017Smckusick struct vnode *a_vp; 74855017Smckusick } */ *ap; 74953838Spendry { 75054049Spendry struct vnode *vp = ap->a_vp; 75154049Spendry 75253838Spendry /* 75353838Spendry * Clear out the v_type field to avoid 75453838Spendry * nasty things happening in vgone(). 75553838Spendry */ 75654049Spendry vp->v_type = VNON; 75753838Spendry return (0); 75853838Spendry } 75953838Spendry 76065513Spendry int 76155017Smckusick fdesc_reclaim(ap) 76255017Smckusick struct vop_reclaim_args /* { 76355017Smckusick struct vnode *a_vp; 76455017Smckusick } */ *ap; 76553838Spendry { 76653838Spendry struct vnode *vp = ap->a_vp; 76759255Spendry 76865513Spendry remque(VTOFDESC(vp)); 76965513Spendry FREE(vp->v_data, M_TEMP); 77065513Spendry vp->v_data = 0; 77165513Spendry 77253838Spendry return (0); 77353838Spendry } 77453838Spendry 77553838Spendry /* 776*65743Spendry * Return POSIX pathconf information applicable to special devices. 777*65743Spendry */ 778*65743Spendry fdesc_pathconf(ap) 779*65743Spendry struct vop_pathconf_args /* { 780*65743Spendry struct vnode *a_vp; 781*65743Spendry int a_name; 782*65743Spendry int *a_retval; 783*65743Spendry } */ *ap; 784*65743Spendry { 785*65743Spendry 786*65743Spendry switch (ap->a_name) { 787*65743Spendry case _PC_LINK_MAX: 788*65743Spendry *ap->a_retval = LINK_MAX; 789*65743Spendry return (0); 790*65743Spendry case _PC_MAX_CANON: 791*65743Spendry *ap->a_retval = MAX_CANON; 792*65743Spendry return (0); 793*65743Spendry case _PC_MAX_INPUT: 794*65743Spendry *ap->a_retval = MAX_INPUT; 795*65743Spendry return (0); 796*65743Spendry case _PC_PIPE_BUF: 797*65743Spendry *ap->a_retval = PIPE_BUF; 798*65743Spendry return (0); 799*65743Spendry case _PC_CHOWN_RESTRICTED: 800*65743Spendry *ap->a_retval = 1; 801*65743Spendry return (0); 802*65743Spendry case _PC_VDISABLE: 803*65743Spendry *ap->a_retval = _POSIX_VDISABLE; 804*65743Spendry return (0); 805*65743Spendry default: 806*65743Spendry return (EINVAL); 807*65743Spendry } 808*65743Spendry /* NOTREACHED */ 809*65743Spendry } 810*65743Spendry 811*65743Spendry /* 81253838Spendry * Print out the contents of a /dev/fd vnode. 81353838Spendry */ 81453838Spendry /* ARGSUSED */ 81565513Spendry int 81655017Smckusick fdesc_print(ap) 81755017Smckusick struct vop_print_args /* { 81855017Smckusick struct vnode *a_vp; 81955017Smckusick } */ *ap; 82053838Spendry { 82155017Smckusick 82253838Spendry printf("tag VT_NON, fdesc vnode\n"); 82355017Smckusick return (0); 82453838Spendry } 82553838Spendry 82653838Spendry /*void*/ 82765513Spendry int 82855017Smckusick fdesc_vfree(ap) 82955017Smckusick struct vop_vfree_args /* { 83055017Smckusick struct vnode *a_pvp; 83155017Smckusick ino_t a_ino; 83255017Smckusick int a_mode; 83355017Smckusick } */ *ap; 83453838Spendry { 83553838Spendry 83655017Smckusick return (0); 83753838Spendry } 83853838Spendry 83953838Spendry /* 84053838Spendry * /dev/fd vnode unsupported operation 84153838Spendry */ 84265513Spendry int 84353838Spendry fdesc_enotsupp() 84453838Spendry { 84555017Smckusick 84653838Spendry return (EOPNOTSUPP); 84753838Spendry } 84853838Spendry 84953838Spendry /* 85053838Spendry * /dev/fd "should never get here" operation 85153838Spendry */ 85265513Spendry int 85353838Spendry fdesc_badop() 85453838Spendry { 85555017Smckusick 85653838Spendry panic("fdesc: bad op"); 85753838Spendry /* NOTREACHED */ 85853838Spendry } 85953838Spendry 86053838Spendry /* 86153838Spendry * /dev/fd vnode null operation 86253838Spendry */ 86365513Spendry int 86453838Spendry fdesc_nullop() 86553838Spendry { 86655017Smckusick 86753838Spendry return (0); 86853838Spendry } 86953838Spendry 87053838Spendry #define fdesc_create ((int (*) __P((struct vop_create_args *)))fdesc_enotsupp) 87153838Spendry #define fdesc_mknod ((int (*) __P((struct vop_mknod_args *)))fdesc_enotsupp) 87253838Spendry #define fdesc_close ((int (*) __P((struct vop_close_args *)))nullop) 87353838Spendry #define fdesc_access ((int (*) __P((struct vop_access_args *)))nullop) 87453838Spendry #define fdesc_mmap ((int (*) __P((struct vop_mmap_args *)))fdesc_enotsupp) 87553838Spendry #define fdesc_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 87653838Spendry #define fdesc_seek ((int (*) __P((struct vop_seek_args *)))nullop) 87753838Spendry #define fdesc_remove ((int (*) __P((struct vop_remove_args *)))fdesc_enotsupp) 87853838Spendry #define fdesc_link ((int (*) __P((struct vop_link_args *)))fdesc_enotsupp) 87953838Spendry #define fdesc_rename ((int (*) __P((struct vop_rename_args *)))fdesc_enotsupp) 88053838Spendry #define fdesc_mkdir ((int (*) __P((struct vop_mkdir_args *)))fdesc_enotsupp) 88153838Spendry #define fdesc_rmdir ((int (*) __P((struct vop_rmdir_args *)))fdesc_enotsupp) 88255017Smckusick #define fdesc_symlink ((int (*) __P((struct vop_symlink_args *)))fdesc_enotsupp) 88353838Spendry #define fdesc_abortop ((int (*) __P((struct vop_abortop_args *)))nullop) 88453838Spendry #define fdesc_lock ((int (*) __P((struct vop_lock_args *)))nullop) 88553838Spendry #define fdesc_unlock ((int (*) __P((struct vop_unlock_args *)))nullop) 88653838Spendry #define fdesc_bmap ((int (*) __P((struct vop_bmap_args *)))fdesc_badop) 88753838Spendry #define fdesc_strategy ((int (*) __P((struct vop_strategy_args *)))fdesc_badop) 88853838Spendry #define fdesc_islocked ((int (*) __P((struct vop_islocked_args *)))nullop) 88955017Smckusick #define fdesc_advlock ((int (*) __P((struct vop_advlock_args *)))fdesc_enotsupp) 89055170Spendry #define fdesc_blkatoff \ 89155017Smckusick ((int (*) __P((struct vop_blkatoff_args *)))fdesc_enotsupp) 89253838Spendry #define fdesc_vget ((int (*) __P((struct vop_vget_args *)))fdesc_enotsupp) 89353838Spendry #define fdesc_valloc ((int(*) __P(( \ 89453838Spendry struct vnode *pvp, \ 89553838Spendry int mode, \ 89653838Spendry struct ucred *cred, \ 89753838Spendry struct vnode **vpp))) fdesc_enotsupp) 89855170Spendry #define fdesc_truncate \ 89955017Smckusick ((int (*) __P((struct vop_truncate_args *)))fdesc_enotsupp) 90053838Spendry #define fdesc_update ((int (*) __P((struct vop_update_args *)))fdesc_enotsupp) 90153838Spendry #define fdesc_bwrite ((int (*) __P((struct vop_bwrite_args *)))fdesc_enotsupp) 90253838Spendry 90353838Spendry int (**fdesc_vnodeop_p)(); 90453838Spendry struct vnodeopv_entry_desc fdesc_vnodeop_entries[] = { 90553838Spendry { &vop_default_desc, vn_default_error }, 90653838Spendry { &vop_lookup_desc, fdesc_lookup }, /* lookup */ 90753838Spendry { &vop_create_desc, fdesc_create }, /* create */ 90853838Spendry { &vop_mknod_desc, fdesc_mknod }, /* mknod */ 90955017Smckusick { &vop_open_desc, fdesc_open }, /* open */ 91053838Spendry { &vop_close_desc, fdesc_close }, /* close */ 91153838Spendry { &vop_access_desc, fdesc_access }, /* access */ 91253838Spendry { &vop_getattr_desc, fdesc_getattr }, /* getattr */ 91353838Spendry { &vop_setattr_desc, fdesc_setattr }, /* setattr */ 91455017Smckusick { &vop_read_desc, fdesc_read }, /* read */ 91553838Spendry { &vop_write_desc, fdesc_write }, /* write */ 91653838Spendry { &vop_ioctl_desc, fdesc_ioctl }, /* ioctl */ 91753838Spendry { &vop_select_desc, fdesc_select }, /* select */ 91855017Smckusick { &vop_mmap_desc, fdesc_mmap }, /* mmap */ 91953838Spendry { &vop_fsync_desc, fdesc_fsync }, /* fsync */ 92055017Smckusick { &vop_seek_desc, fdesc_seek }, /* seek */ 92153838Spendry { &vop_remove_desc, fdesc_remove }, /* remove */ 92255017Smckusick { &vop_link_desc, fdesc_link }, /* link */ 92353838Spendry { &vop_rename_desc, fdesc_rename }, /* rename */ 92453838Spendry { &vop_mkdir_desc, fdesc_mkdir }, /* mkdir */ 92553838Spendry { &vop_rmdir_desc, fdesc_rmdir }, /* rmdir */ 92653838Spendry { &vop_symlink_desc, fdesc_symlink }, /* symlink */ 92753838Spendry { &vop_readdir_desc, fdesc_readdir }, /* readdir */ 92853838Spendry { &vop_readlink_desc, fdesc_readlink }, /* readlink */ 92953838Spendry { &vop_abortop_desc, fdesc_abortop }, /* abortop */ 93053838Spendry { &vop_inactive_desc, fdesc_inactive }, /* inactive */ 93153838Spendry { &vop_reclaim_desc, fdesc_reclaim }, /* reclaim */ 93255017Smckusick { &vop_lock_desc, fdesc_lock }, /* lock */ 93353838Spendry { &vop_unlock_desc, fdesc_unlock }, /* unlock */ 93455017Smckusick { &vop_bmap_desc, fdesc_bmap }, /* bmap */ 93553838Spendry { &vop_strategy_desc, fdesc_strategy }, /* strategy */ 93653838Spendry { &vop_print_desc, fdesc_print }, /* print */ 93753838Spendry { &vop_islocked_desc, fdesc_islocked }, /* islocked */ 938*65743Spendry { &vop_pathconf_desc, fdesc_pathconf }, /* pathconf */ 93953838Spendry { &vop_advlock_desc, fdesc_advlock }, /* advlock */ 94053838Spendry { &vop_blkatoff_desc, fdesc_blkatoff }, /* blkatoff */ 94153838Spendry { &vop_valloc_desc, fdesc_valloc }, /* valloc */ 94253838Spendry { &vop_vfree_desc, fdesc_vfree }, /* vfree */ 94353838Spendry { &vop_truncate_desc, fdesc_truncate }, /* truncate */ 94453838Spendry { &vop_update_desc, fdesc_update }, /* update */ 94553838Spendry { &vop_bwrite_desc, fdesc_bwrite }, /* bwrite */ 94653838Spendry { (struct vnodeop_desc*)NULL, (int(*)())NULL } 94753838Spendry }; 94853838Spendry struct vnodeopv_desc fdesc_vnodeop_opv_desc = 94953838Spendry { &fdesc_vnodeop_p, fdesc_vnodeop_entries }; 950