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