155099Storek /* 255099Storek * Copyright (c) 1992 The Regents of the University of California. 355099Storek * All rights reserved. 455099Storek * 555099Storek * This software was developed by the Computer Systems Engineering group 655099Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 755099Storek * contributed to Berkeley. 855099Storek * 955099Storek * %sccs.include.redist.c% 1055099Storek * 11*55174Storek * @(#)sun_misc.c 7.2 (Berkeley) 07/13/92 1255099Storek * 1355099Storek * from: $Header: sun_misc.c,v 1.12 92/07/12 13:26:10 torek Exp $ 1455099Storek */ 1555099Storek 1655099Storek /* 1755099Storek * SunOS compatibility module. 1855099Storek * 1955099Storek * SunOS system calls that are implemented differently in BSD are 2055099Storek * handled here. 2155099Storek */ 2255099Storek 2355099Storek #include "param.h" 2455099Storek #include "proc.h" 2555099Storek #include "file.h" 2655099Storek #include "filedesc.h" 2755099Storek #include "ioctl.h" 2855099Storek #include "malloc.h" 2955099Storek #include "mbuf.h" 3055099Storek #include "mman.h" 3155099Storek #include "mount.h" 3255099Storek #include "resource.h" 3355099Storek #include "resourcevar.h" 3455099Storek #include "signal.h" 3555099Storek #include "signalvar.h" 3655099Storek #include "socket.h" 3755099Storek #include "vnode.h" 3855099Storek #include "uio.h" 3955099Storek #include "wait.h" 4055099Storek 41*55174Storek #include "miscfs/specfs/specdev.h" 42*55174Storek 4355099Storek #include "vm/vm.h" 4455099Storek 4555099Storek struct sun_wait4_args { 4655099Storek int pid; 4755099Storek int *status; 4855099Storek int options; 4955099Storek struct rusage *rusage; 5055099Storek }; 5155099Storek sun_wait4(p, uap, retval) 5255099Storek struct proc *p; 5355099Storek struct sun_wait4_args *uap; 5455099Storek int *retval; 5555099Storek { 5655099Storek 5755099Storek if (uap->pid == 0) 5855099Storek uap->pid = WAIT_ANY; 5955099Storek return (wait4(p, uap, retval)); 6055099Storek } 6155099Storek 6255099Storek struct sun_creat_args { 6355099Storek char *fname; 6455099Storek int fmode; 6555099Storek }; 6655099Storek sun_creat(p, uap, retval) 6755099Storek struct proc *p; 6855099Storek struct sun_creat_args *uap; 6955099Storek int *retval; 7055099Storek { 7155099Storek struct args { 7255099Storek char *fname; 7355099Storek int mode; 7455099Storek int crtmode; 7555099Storek } openuap; 7655099Storek 7755099Storek openuap.fname = uap->fname; 7855099Storek openuap.crtmode = uap->fmode; 7955099Storek openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 8055099Storek return (open(p, &openuap, retval)); 8155099Storek } 8255099Storek 8355099Storek struct sun_execv_args { 8455099Storek char *fname; 8555099Storek char **argp; 8655099Storek char **envp; /* pseudo */ 8755099Storek }; 8855099Storek sun_execv(p, uap, retval) 8955099Storek struct proc *p; 9055099Storek struct sun_execv_args *uap; 9155099Storek int *retval; 9255099Storek { 9355099Storek 9455099Storek uap->envp = NULL; 9555099Storek return (execve(p, uap, retval)); 9655099Storek } 9755099Storek 9855099Storek struct sun_omsync_args { 9955099Storek caddr_t addr; 10055099Storek int len; 10155099Storek int flags; 10255099Storek }; 10355099Storek sun_omsync(p, uap, retval) 10455099Storek struct proc *p; 10555099Storek struct sun_omsync_args *uap; 10655099Storek int *retval; 10755099Storek { 10855099Storek 10955099Storek if (uap->flags) 11055099Storek return (EINVAL); 11155099Storek return (msync(p, uap, retval)); 11255099Storek } 11355099Storek 11455099Storek struct sun_unmount_args { 11555099Storek char *name; 11655099Storek int flags; /* pseudo */ 11755099Storek }; 11855099Storek sun_unmount(p, uap, retval) 11955099Storek struct proc *p; 12055099Storek struct sun_unmount_args *uap; 12155099Storek int *retval; 12255099Storek { 12355099Storek 12455099Storek uap->flags = MNT_NOFORCE; 12555099Storek return (unmount(p, uap, retval)); 12655099Storek } 12755099Storek 12855099Storek static int 12955099Storek gettype(tptr) 13055099Storek int *tptr; 13155099Storek { 13255099Storek int type, error; 13355099Storek char in[20]; 13455099Storek 13555099Storek if (error = copyinstr((caddr_t)*tptr, in, sizeof in, (u_int *)0)) 13655099Storek return (error); 13755099Storek if (strcmp(in, "4.2") == 0 || strcmp(in, "ufs") == 0) 13855099Storek type = MOUNT_UFS; 13955099Storek else if (strcmp(in, "nfs") == 0) 14055099Storek type = MOUNT_NFS; 14155099Storek else 14255099Storek return (EINVAL); 14355099Storek *tptr = type; 14455099Storek return (0); 14555099Storek } 14655099Storek 14755099Storek #define SUNM_RDONLY 0x01 /* mount fs read-only */ 14855099Storek #define SUNM_NOSUID 0x02 /* mount fs with setuid disallowed */ 14955099Storek #define SUNM_NEWTYPE 0x04 /* type is string (char *), not int */ 15055099Storek #define SUNM_GRPID 0x08 /* (bsd semantics; ignored) */ 15155099Storek #define SUNM_REMOUNT 0x10 /* update existing mount */ 15255099Storek #define SUNM_NOSUB 0x20 /* prevent submounts (rejected) */ 15355099Storek #define SUNM_MULTI 0x40 /* (ignored) */ 15455099Storek #define SUNM_SYS5 0x80 /* Sys 5-specific semantics (rejected) */ 15555099Storek 15655099Storek struct sun_mount_args { 15755099Storek int type; 15855099Storek char *dir; 15955099Storek int flags; 16055099Storek caddr_t data; 16155099Storek }; 16255099Storek sun_mount(p, uap, retval) 16355099Storek struct proc *p; 16455099Storek struct sun_mount_args *uap; 16555099Storek int *retval; 16655099Storek { 16755099Storek int oflags = uap->flags, nflags, error; 16855099Storek 16955099Storek if (oflags & (SUNM_NOSUB | SUNM_SYS5)) 17055099Storek return (EINVAL); 17155099Storek if (oflags & SUNM_NEWTYPE && (error = gettype(&uap->type))) 17255099Storek return (error); 17355099Storek nflags = 0; 17455099Storek if (oflags & SUNM_RDONLY) 17555099Storek nflags |= MNT_RDONLY; 17655099Storek if (oflags & SUNM_NOSUID) 17755099Storek nflags |= MNT_NOSUID; 17855099Storek if (oflags & SUNM_REMOUNT) 17955099Storek nflags |= MNT_UPDATE; 18055099Storek uap->flags = nflags; 18155099Storek return (mount(p, uap, retval)); 18255099Storek } 18355099Storek 18455099Storek struct sun_sigpending_args { 18555099Storek int *mask; 18655099Storek }; 18755099Storek sun_sigpending(p, uap, retval) 18855099Storek struct proc *p; 18955099Storek struct sun_sigpending_args *uap; 19055099Storek int *retval; 19155099Storek { 19255099Storek int mask = p->p_sig & p->p_sigmask; 19355099Storek 19455099Storek return (copyout((caddr_t)&mask, (caddr_t)uap->mask, sizeof(int))); 19555099Storek } 19655099Storek 19755099Storek #if 0 19855099Storek /* here is the sun layout (not used directly): */ 19955099Storek struct sun_dirent { 20055099Storek long d_off; 20155099Storek u_long d_fileno; 20255099Storek u_short d_reclen; 20355099Storek u_short d_namlen; 20455099Storek char d_name[256]; 20555099Storek }; 20655099Storek #endif 20755099Storek /* and the BSD layout: */ 20855099Storek struct bsd_dirent { 20955099Storek u_long d_fileno; 21055099Storek u_short d_reclen; 21155099Storek u_short d_namlen; 21255099Storek char d_name[256]; 21355099Storek }; 21455099Storek 21555099Storek /* 21655099Storek * Read Sun-style directory entries. We suck them into kernel space so 21755099Storek * that they can be massaged before being copied out to user code. Like 21855099Storek * SunOS, we squish out `empty' entries. 21955099Storek * 22055099Storek * This is quite ugly, but what do you expect from compatibility code? 22155099Storek */ 22255099Storek struct sun_getdents_args { 22355099Storek int fd; 22455099Storek char *buf; 22555099Storek int nbytes; 22655099Storek }; 22755099Storek sun_getdents(p, uap, retval) 22855099Storek struct proc *p; 22955099Storek register struct sun_getdents_args *uap; 23055099Storek int *retval; 23155099Storek { 23255099Storek register struct vnode *vp; 23355099Storek register caddr_t inp, buf; /* BSD-format */ 23455099Storek register int len, reclen; /* BSD-format */ 23555099Storek register caddr_t outp; /* Sun-format */ 23655099Storek register int resid; /* Sun-format */ 23755099Storek struct file *fp; 23855099Storek struct uio auio; 23955099Storek struct iovec aiov; 24055099Storek off_t off; /* true file offset */ 24155099Storek long soff; /* Sun file offset */ 24255099Storek int buflen, error, eofflag; 24355099Storek #define SUN_RECLEN(reclen) (reclen + sizeof(long)) 24455099Storek 24555099Storek if ((error = getvnode(p->p_fd, uap->fd, &fp)) != 0) 24655099Storek return (error); 24755099Storek if ((fp->f_flag & FREAD) == 0) 24855099Storek return (EBADF); 24955099Storek vp = (struct vnode *)fp->f_data; 25055099Storek if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 25155099Storek return (EINVAL); 25255099Storek buflen = min(MAXBSIZE, uap->nbytes); 25355099Storek buf = malloc(buflen, M_TEMP, M_WAITOK); 25455099Storek VOP_LOCK(vp); 25555099Storek off = fp->f_offset; 25655099Storek again: 25755099Storek aiov.iov_base = buf; 25855099Storek aiov.iov_len = buflen; 25955099Storek auio.uio_iov = &aiov; 26055099Storek auio.uio_iovcnt = 1; 26155099Storek auio.uio_rw = UIO_READ; 26255099Storek auio.uio_segflg = UIO_SYSSPACE; 26355099Storek auio.uio_procp = p; 26455099Storek auio.uio_resid = buflen; 26555099Storek auio.uio_offset = off; 26655099Storek /* 26755099Storek * First we read into the malloc'ed buffer, then 26855099Storek * we massage it into user space, one record at a time. 26955099Storek */ 27055099Storek if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag)) 27155099Storek goto out; 27255099Storek inp = buf; 27355099Storek outp = uap->buf; 27455099Storek resid = uap->nbytes; 27555099Storek if ((len = buflen - auio.uio_resid) == 0) 27655099Storek goto eof; 27755099Storek for (; len > 0; len -= reclen) { 27855099Storek reclen = ((struct bsd_dirent *)inp)->d_reclen; 27955099Storek if (reclen & 3) 28055099Storek panic("sun_getdents"); 28155099Storek off += reclen; /* each entry points to next */ 28255099Storek if (((struct bsd_dirent *)inp)->d_fileno == 0) { 28355099Storek inp += reclen; /* it is a hole; squish it out */ 28455099Storek continue; 28555099Storek } 28655099Storek if (reclen > len || resid < SUN_RECLEN(reclen)) { 28755099Storek /* entry too big for buffer, so just stop */ 28855099Storek outp++; 28955099Storek break; 29055099Storek } 29155099Storek /* copy out a Sun-shaped dirent */ 29255099Storek ((struct bsd_dirent *)inp)->d_reclen = SUN_RECLEN(reclen); 29355099Storek soff = off; 29455099Storek if ((error = copyout((caddr_t)&soff, outp, sizeof soff)) != 0 || 29555099Storek (error = copyout(inp, outp + sizeof soff, reclen)) != 0) 29655099Storek goto out; 29755099Storek /* advance past this real entry */ 29855099Storek inp += reclen; 29955099Storek /* advance output past Sun-shaped entry */ 30055099Storek outp += SUN_RECLEN(reclen); 30155099Storek resid -= SUN_RECLEN(reclen); 30255099Storek } 30355099Storek /* if we squished out the whole block, try again */ 30455099Storek if (outp == uap->buf) 30555099Storek goto again; 30655099Storek fp->f_offset = off; /* update the vnode offset */ 30755099Storek eof: 30855099Storek *retval = uap->nbytes - resid; 30955099Storek out: 31055099Storek VOP_UNLOCK(vp); 31155099Storek free(buf, M_TEMP); 31255099Storek return (error); 31355099Storek } 31455099Storek 31555099Storek #define MAXDOMAINNAME 64 31655099Storek char sun_domainname[MAXDOMAINNAME]; 31755099Storek int sun_domainnamelen = 1; 31855099Storek 31955099Storek struct sun_getdomainname_args { 32055099Storek char *name; 32155099Storek int namelen; 32255099Storek }; 32355099Storek sun_getdomainname(p, uap, retval) 32455099Storek struct proc *p; 32555099Storek struct sun_getdomainname_args *uap; 32655099Storek int *retval; 32755099Storek { 32855099Storek register int l = min(uap->namelen, sun_domainnamelen + 1); 32955099Storek 33055099Storek return (copyout(sun_domainname, uap->name, l)); 33155099Storek } 33255099Storek 33355099Storek struct sun_setdomainname_args { 33455099Storek char *name; 33555099Storek int namelen; 33655099Storek }; 33755099Storek sun_setdomainname(p, uap, retval) 33855099Storek struct proc *p; 33955099Storek struct sun_setdomainname_args *uap; 34055099Storek int *retval; 34155099Storek { 34255099Storek register int l = uap->namelen, error; 34355099Storek 34455099Storek if (l >= MAXDOMAINNAME) 34555099Storek return (EINVAL); /* ??? ENAMETOOLONG? */ 34655099Storek if (error = suser(p->p_ucred, &p->p_acflag)) 34755099Storek return (error); 34855099Storek if (error = copyin(uap->name, sun_domainname, l)) 34955099Storek return (error); 35055099Storek sun_domainname[l] = 0; 35155099Storek return (0); 35255099Storek } 35355099Storek 35455099Storek #define SUN_MMAP_MASK 0xf /* mask for SHARED/PRIVATE */ 35555099Storek #define SUN_MMAP_CANDO 0x80000000 /* if not, old mmap & cannot handle */ 35655099Storek 35755099Storek #define DEVZERO makedev(3, 12) /* major,minor of /dev/zero */ 35855099Storek 35955099Storek #define SUN_MMAP_SAME (MAP_SHARED|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT) 36055099Storek 36155099Storek struct sun_mmap_args { 36255099Storek caddr_t addr; 36355099Storek size_t len; 36455099Storek int prot; 36555099Storek int flags; 36655099Storek int fd; 36755099Storek long off; /* not off_t! */ 36855099Storek quad_t qoff; /* created here and fed to smmap() */ 36955099Storek }; 37055099Storek sun_mmap(p, uap, retval) 37155099Storek register struct proc *p; 37255099Storek register struct sun_mmap_args *uap; 37355099Storek int *retval; 37455099Storek { 37555099Storek register int flags; 37655099Storek register struct filedesc *fdp; 37755099Storek register struct file *fp; 37855099Storek register struct vnode *vp; 37955099Storek 38055099Storek /* 38155099Storek * Verify the arguments. 38255099Storek */ 38355099Storek flags = uap->flags; 38455099Storek if ((flags & SUN_MMAP_CANDO) == 0) 38555099Storek return (EINVAL); 38655099Storek if ((flags & SUN_MMAP_MASK) != MAP_SHARED && 38755099Storek (flags & SUN_MMAP_MASK) != MAP_PRIVATE) 38855099Storek return (EINVAL); 38955099Storek flags &= ~SUN_MMAP_CANDO; 39055099Storek 39155099Storek /* 39255099Storek * Special case: if fd refers to /dev/zero, map as MAP_ANON. (XXX) 39355099Storek */ 39455099Storek fdp = p->p_fd; 39555099Storek if ((unsigned)uap->fd < fdp->fd_nfiles && /*XXX*/ 39655099Storek (fp = fdp->fd_ofiles[uap->fd]) != NULL && /*XXX*/ 39755099Storek fp->f_type == DTYPE_VNODE && /*XXX*/ 39855099Storek (vp = (struct vnode *)fp->f_data)->v_type == VCHR && /*XXX*/ 39955099Storek vp->v_rdev == DEVZERO) { /*XXX*/ 40055099Storek flags |= MAP_ANON; 40155099Storek uap->fd = -1; 40255099Storek } 40355099Storek 40455099Storek /* All done, fix up fields and go. */ 40555099Storek uap->flags = flags; 40655099Storek uap->qoff = (quad_t)uap->off; 40755099Storek return (smmap(p, uap, retval)); 40855099Storek } 40955099Storek 41055099Storek #define MC_SYNC 1 41155099Storek #define MC_LOCK 2 41255099Storek #define MC_UNLOCK 3 41355099Storek #define MC_ADVISE 4 41455099Storek #define MC_LOCKAS 5 41555099Storek #define MC_UNLOCKAS 6 41655099Storek 41755099Storek struct sun_mctl_args { 41855099Storek caddr_t addr; 41955099Storek size_t len; 42055099Storek int func; 42155099Storek void *arg; 42255099Storek }; 42355099Storek sun_mctl(p, uap, retval) 42455099Storek register struct proc *p; 42555099Storek register struct sun_mctl_args *uap; 42655099Storek int *retval; 42755099Storek { 42855099Storek 42955099Storek switch (uap->func) { 43055099Storek 43155099Storek case MC_ADVISE: /* ignore for now */ 43255099Storek return (0); 43355099Storek 43455099Storek case MC_SYNC: /* translate to msync */ 43555099Storek return (msync(p, uap, retval)); 43655099Storek 43755099Storek default: 43855099Storek return (EINVAL); 43955099Storek } 44055099Storek } 44155099Storek 44255099Storek struct sun_setreuid_args { 44355099Storek int ruid; /* not uid_t */ 44455099Storek int euid; 44555099Storek }; 44655099Storek sun_setreuid(p, uap, retval) 44755099Storek struct proc *p; 44855099Storek struct sun_setreuid_args *uap; 44955099Storek int *retval; 45055099Storek { 45155099Storek register struct pcred *pc = p->p_cred; 45255099Storek register uid_t ruid, euid; 45355099Storek int error; 45455099Storek 45555099Storek if (uap->ruid == -1) 45655099Storek ruid = pc->p_ruid; 45755099Storek else 45855099Storek ruid = uap->ruid; 45955099Storek /* 46055099Storek * Allow setting real uid to previous effective, for swapping real and 46155099Storek * effective. This should be: 46255099Storek * 46355099Storek * if (ruid != pc->p_ruid && 46455099Storek * (error = suser(pc->pc_ucred, &p->p_acflag))) 46555099Storek */ 46655099Storek if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && 46755099Storek (error = suser(pc->pc_ucred, &p->p_acflag))) 46855099Storek return (error); 46955099Storek if (uap->euid == -1) 47055099Storek euid = pc->pc_ucred->cr_uid; 47155099Storek else 47255099Storek euid = uap->euid; 47355099Storek if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && 47455099Storek euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) 47555099Storek return (error); 47655099Storek /* 47755099Storek * Everything's okay, do it. Copy credentials so other references do 47855099Storek * not see our changes. 47955099Storek */ 48055099Storek pc->pc_ucred = crcopy(pc->pc_ucred); 48155099Storek pc->pc_ucred->cr_uid = euid; 48255099Storek pc->p_ruid = ruid; 48355099Storek p->p_flag |= SUGID; 48455099Storek return (0); 48555099Storek } 48655099Storek 48755099Storek struct sun_setregid_args { 48855099Storek int rgid; /* not gid_t */ 48955099Storek int egid; 49055099Storek }; 49155099Storek sun_setregid(p, uap, retval) 49255099Storek struct proc *p; 49355099Storek struct sun_setregid_args *uap; 49455099Storek int *retval; 49555099Storek { 49655099Storek register struct pcred *pc = p->p_cred; 49755099Storek register gid_t rgid, egid; 49855099Storek int error; 49955099Storek 50055099Storek if (uap->rgid == -1) 50155099Storek rgid = pc->p_rgid; 50255099Storek else 50355099Storek rgid = uap->rgid; 50455099Storek /* 50555099Storek * Allow setting real gid to previous effective, for swapping real and 50655099Storek * effective. This didn't really work correctly in 4.[23], but is 50755099Storek * preserved so old stuff doesn't fail. This should be: 50855099Storek * 50955099Storek * if (rgid != pc->p_rgid && 51055099Storek * (error = suser(pc->pc_ucred, &p->p_acflag))) 51155099Storek */ 51255099Storek if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && 51355099Storek (error = suser(pc->pc_ucred, &p->p_acflag))) 51455099Storek return (error); 51555099Storek if (uap->egid == -1) 51655099Storek egid = pc->pc_ucred->cr_groups[0]; 51755099Storek else 51855099Storek egid = uap->egid; 51955099Storek if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && 52055099Storek egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 52155099Storek return (error); 52255099Storek pc->pc_ucred = crcopy(pc->pc_ucred); 52355099Storek pc->pc_ucred->cr_groups[0] = egid; 52455099Storek pc->p_rgid = rgid; 52555099Storek p->p_flag |= SUGID; 52655099Storek return (0); 52755099Storek } 52855099Storek 52955099Storek struct sun_setsockopt_args { 53055099Storek int s; 53155099Storek int level; 53255099Storek int name; 53355099Storek caddr_t val; 53455099Storek int valsize; 53555099Storek }; 53655099Storek sun_setsockopt(p, uap, retval) 53755099Storek struct proc *p; 53855099Storek register struct sun_setsockopt_args *uap; 53955099Storek int *retval; 54055099Storek { 54155099Storek struct file *fp; 54255099Storek struct mbuf *m = NULL; 54355099Storek int error; 54455099Storek 54555099Storek if (error = getsock(p->p_fd, uap->s, &fp)) 54655099Storek return (error); 54755099Storek #define SO_DONTLINGER (~SO_LINGER) 54855099Storek if (uap->name == SO_DONTLINGER) { 54955099Storek m = m_get(M_WAIT, MT_SOOPTS); 55055099Storek if (m == NULL) 55155099Storek return (ENOBUFS); 55255099Storek mtod(m, struct linger *)->l_onoff = 0; 55355099Storek m->m_len = sizeof(struct linger); 55455099Storek return (sosetopt((struct socket *)fp->f_data, uap->level, 55555099Storek SO_LINGER, m)); 55655099Storek } 55755099Storek if (uap->valsize > MLEN) 55855099Storek return (EINVAL); 55955099Storek if (uap->val) { 56055099Storek m = m_get(M_WAIT, MT_SOOPTS); 56155099Storek if (m == NULL) 56255099Storek return (ENOBUFS); 56355099Storek if (error = copyin(uap->val, mtod(m, caddr_t), 56455099Storek (u_int)uap->valsize)) { 56555099Storek (void) m_free(m); 56655099Storek return (error); 56755099Storek } 56855099Storek m->m_len = uap->valsize; 56955099Storek } 57055099Storek return (sosetopt((struct socket *)fp->f_data, uap->level, 57155099Storek uap->name, m)); 57255099Storek } 57355099Storek 57455099Storek struct sun_fchroot_args { 57555099Storek int fdes; 57655099Storek }; 57755099Storek sun_fchroot(p, uap, retval) 57855099Storek register struct proc *p; 57955099Storek register struct sun_fchroot_args *uap; 58055099Storek int *retval; 58155099Storek { 58255099Storek register struct filedesc *fdp = p->p_fd; 58355099Storek register struct vnode *vp; 58455099Storek struct file *fp; 58555099Storek int error; 58655099Storek 58755099Storek if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 58855099Storek return (error); 58955099Storek if ((error = getvnode(fdp, uap->fdes, &fp)) != 0) 59055099Storek return (error); 59155099Storek vp = (struct vnode *)fp->f_data; 59255099Storek VOP_LOCK(vp); 59355099Storek if (vp->v_type != VDIR) 59455099Storek error = ENOTDIR; 59555099Storek else 59655099Storek error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 59755099Storek VOP_UNLOCK(vp); 59855099Storek if (error) 59955099Storek return (error); 60055099Storek VREF(vp); 60155099Storek if (fdp->fd_rdir != NULL) 60255099Storek vrele(fdp->fd_rdir); 60355099Storek fdp->fd_rdir = vp; 60455099Storek return (0); 60555099Storek } 606