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