/* ARGSUSED */ static int fdread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct) { static struct fddirect dotbuf[] = { { FDROOTINO, "." }, { FDROOTINO, ".." } }; struct fddirect dirbuf; int i, n; int minfd, maxfd, modoff, error = 0; int nentries; rctl_qty_t fdno_ctl; int endoff; if (vp->v_type != VDIR) return (ENOSYS); mutex_enter(&curproc->p_lock); fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE], curproc->p_rctls, curproc); nentries = MIN(P_FINFO(curproc)->fi_nfiles, (int)fdno_ctl); mutex_exit(&curproc->p_lock); endoff = (nentries + 2) * FDSDSIZE; /* * Fake up ".", "..", and the /dev/fd directory entries. */ if (uiop->uio_loffset < (offset_t)0 || uiop->uio_loffset >= (offset_t)endoff || uiop->uio_resid <= 0) return (0); ASSERT(uiop->uio_loffset <= MAXOFF_T); if (uiop->uio_offset < 2*FDSDSIZE) { error = uiomove((caddr_t)dotbuf + uiop->uio_offset, MIN(uiop->uio_resid, 2*FDSDSIZE - uiop->uio_offset), UIO_READ, uiop); if (uiop->uio_resid <= 0 || error) return (error); } minfd = (uiop->uio_offset - 2*FDSDSIZE)/FDSDSIZE; maxfd = (uiop->uio_offset + uiop->uio_resid - 1)/FDSDSIZE; modoff = uiop->uio_offset % FDSDSIZE; for (i = 0; i < FDDIRSIZE; i++) dirbuf.d_name[i] = '\0'; for (i = minfd; i < MIN(maxfd, nentries); i++) { n = i; dirbuf.d_ino = fdtoi(n); numtos((ulong_t)n, dirbuf.d_name); error = uiomove((caddr_t)&dirbuf + modoff, MIN(uiop->uio_resid, FDSDSIZE - modoff), UIO_READ, uiop); if (uiop->uio_resid <= 0 || error) return (error); modoff = 0; } return (error); }
/* ARGSUSED */ static int ctfs_tdir_do_readdir(vnode_t *vp, void *dp, int *eofp, offset_t *offp, offset_t *nextp, void *data, int flags) { uint64_t zuniqid; ctid_t next; ct_type_t *ty = ct_types[gfs_file_index(vp)]; struct dirent64 *odp = dp; ASSERT(!(flags & V_RDDIR_ENTFLAGS)); zuniqid = VTOZONE(vp)->zone_uniqid; next = contract_type_lookup(ty, zuniqid, *offp); if (next == -1) { *eofp = 1; return (0); } odp->d_ino = CTFS_INO_CT_DIR(next); numtos(next, odp->d_name); *offp = next; *nextp = next + 1; return (0); }
/* * gfs_readdir_emitn: like gfs_readdir_emit(), but takes an integer * instead of a string for the entry's name. */ int gfs_readdir_emitn(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff, ino64_t ino, unsigned long num) { char buf[40]; numtos(num, buf); return (gfs_readdir_emit(st, uiop, voff, ino, buf, 0)); }
/* ARGSUSED */ static int fdreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp, caller_context_t *ct, int flags) { /* bp holds one dirent structure */ u_offset_t bp[DIRENT64_RECLEN(FDNSIZE) / sizeof (u_offset_t)]; struct dirent64 *dirent = (struct dirent64 *)bp; int reclen, nentries; rctl_qty_t fdno_ctl; int n; int oresid; off_t off; if (uiop->uio_offset < 0 || uiop->uio_resid <= 0 || (uiop->uio_offset % FDSDSIZE) != 0) return (ENOENT); ASSERT(uiop->uio_loffset <= MAXOFF_T); oresid = uiop->uio_resid; bzero(bp, sizeof (bp)); mutex_enter(&curproc->p_lock); fdno_ctl = rctl_enforced_value(rctlproc_legacy[RLIMIT_NOFILE], curproc->p_rctls, curproc); nentries = MIN(P_FINFO(curproc)->fi_nfiles, (int)fdno_ctl); mutex_exit(&curproc->p_lock); while (uiop->uio_resid > 0) { if ((off = uiop->uio_offset) == 0) { /* "." */ dirent->d_ino = (ino64_t)FDROOTINO; dirent->d_name[0] = '.'; dirent->d_name[1] = '\0'; reclen = DIRENT64_RECLEN(1); } else if (off == FDSDSIZE) { /* ".." */ dirent->d_ino = (ino64_t)FDROOTINO; dirent->d_name[0] = '.'; dirent->d_name[1] = '.'; dirent->d_name[2] = '\0'; reclen = DIRENT64_RECLEN(2); } else { /* * Return entries corresponding to the allowable * number of file descriptors for this process. */ if ((n = (off-2*FDSDSIZE)/FDSDSIZE) >= nentries) break; dirent->d_ino = (ino64_t)fdtoi(n); numtos((ulong_t)n, dirent->d_name); reclen = DIRENT64_RECLEN(strlen(dirent->d_name)); } dirent->d_off = (offset_t)(uiop->uio_offset + FDSDSIZE); dirent->d_reclen = (ushort_t)reclen; if (reclen > uiop->uio_resid) { /* * Error if no entries have been returned yet. */ if (uiop->uio_resid == oresid) return (EINVAL); break; } /* * uiomove() updates both resid and offset by the same * amount. But we want offset to change in increments * of FDSDSIZE, which is different from the number of bytes * being returned to the user. So we set uio_offset * separately, ignoring what uiomove() does. */ if (uiomove((caddr_t)dirent, reclen, UIO_READ, uiop)) return (EFAULT); uiop->uio_offset = off + FDSDSIZE; } if (eofp) *eofp = ((uiop->uio_offset-2*FDSDSIZE)/FDSDSIZE >= nentries); return (0); }
int intpexec( struct vnode *vp, struct execa *uap, struct uarg *args, struct intpdata *idatap, int level, long *execsz, int setid, caddr_t exec_file, struct cred *cred, int brand_action) { _NOTE(ARGUNUSED(brand_action)) vnode_t *nvp; int error = 0; struct intpdata idata; struct pathname intppn; struct pathname resolvepn; char *opath; char devfd[19]; /* 32-bit int fits in 10 digits + 8 for "/dev/fd/" */ int fd = -1; if (level) { /* Can't recurse */ error = ENOEXEC; goto bad; } ASSERT(idatap == (struct intpdata *)NULL); /* * Allocate a buffer to read in the interpreter pathname. */ idata.intp = kmem_alloc(INTPSZ, KM_SLEEP); if (error = getintphead(vp, &idata)) goto fail; /* * Look the new vnode up. */ if (error = pn_get(idata.intp_name, UIO_SYSSPACE, &intppn)) goto fail; pn_alloc(&resolvepn); if (error = lookuppn(&intppn, &resolvepn, FOLLOW, NULLVPP, &nvp)) { pn_free(&resolvepn); pn_free(&intppn); goto fail; } opath = args->pathname; args->pathname = resolvepn.pn_path; /* don't free resolvepn until we are done with args */ pn_free(&intppn); /* * When we're executing a set-uid script resulting in uids * mismatching or when we execute with additional privileges, * we close the "replace script between exec and open by shell" * hole by passing the script as /dev/fd parameter. */ if ((setid & EXECSETID_PRIVS) != 0 || (setid & (EXECSETID_UGIDS|EXECSETID_SETID)) == (EXECSETID_UGIDS|EXECSETID_SETID)) { (void) strcpy(devfd, "/dev/fd/"); if (error = execopen(&vp, &fd)) goto done; numtos(fd, &devfd[8]); args->fname = devfd; } error = gexec(&nvp, uap, args, &idata, ++level, execsz, exec_file, cred, EBA_NONE); done: VN_RELE(nvp); args->pathname = opath; pn_free(&resolvepn); fail: kmem_free(idata.intp, INTPSZ); if (error && fd != -1) (void) execclose(fd); bad: return (error); }