xref: /csrg-svn/sys/sparc/sunos/sun_misc.c (revision 55174)
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