xref: /csrg-svn/sys/kern/sysv_shm.c (revision 68306)
141490Smckusick /*
241490Smckusick  * Copyright (c) 1988 University of Utah.
363178Sbostic  * Copyright (c) 1990, 1993
463178Sbostic  *	The Regents of the University of California.  All rights reserved.
565771Sbostic  * (c) UNIX System Laboratories, Inc.
665771Sbostic  * All or some portions of this file are derived from material licensed
765771Sbostic  * to the University of California by American Telephone and Telegraph
865771Sbostic  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
965771Sbostic  * the permission of UNIX System Laboratories, Inc.
1041490Smckusick  *
1141490Smckusick  * This code is derived from software contributed to Berkeley by
1241490Smckusick  * the Systems Programming Group of the University of Utah Computer
1365771Sbostic  * Science Department.  Originally from the University of Wisconsin.
1441490Smckusick  *
1564553Sbostic  * %sccs.include.proprietary.c%
1641490Smckusick  *
1754856Shibler  * from: Utah $Hdr: uipc_shm.c 1.11 92/04/23$
1841490Smckusick  *
19*68306Scgd  *	@(#)sysv_shm.c	8.7 (Berkeley) 02/14/95
2041490Smckusick  */
2141490Smckusick 
2241490Smckusick /*
2341490Smckusick  * System V shared memory routines.
2443630Skarels  * TEMPORARY, until mmap is in place;
2543630Skarels  * needed now for HP-UX compatibility and X server (yech!).
2641490Smckusick  */
2741490Smckusick 
2841490Smckusick #ifdef SYSVSHM
2941490Smckusick 
3056517Sbostic #include <sys/param.h>
3156517Sbostic #include <sys/systm.h>
3256517Sbostic #include <sys/kernel.h>
3356517Sbostic #include <sys/proc.h>
3456517Sbostic #include <sys/shm.h>
3556517Sbostic #include <sys/malloc.h>
3656517Sbostic #include <sys/mman.h>
3764399Smckusick #include <sys/stat.h>
3841490Smckusick 
3956517Sbostic #include <vm/vm.h>
4056517Sbostic #include <vm/vm_kern.h>
4156517Sbostic #include <vm/vm_inherit.h>
4256517Sbostic #include <vm/vm_pager.h>
4356517Sbostic 
4441490Smckusick int	shmat(), shmctl(), shmdt(), shmget();
4541490Smckusick int	(*shmcalls[])() = { shmat, shmctl, shmdt, shmget };
4641490Smckusick int	shmtot = 0;
4741490Smckusick 
4845737Smckusick /*
4945737Smckusick  * Per process internal structure for managing segments.
5045737Smckusick  * Each process using shm will have an array of ``shmseg'' of these.
5145737Smckusick  */
5245737Smckusick struct	shmdesc {
5345737Smckusick 	vm_offset_t	shmd_uva;
5445737Smckusick 	int		shmd_id;
5545737Smckusick };
5641490Smckusick 
5745737Smckusick /*
5845737Smckusick  * Per segment internal structure (shm_handle).
5945737Smckusick  */
6045737Smckusick struct	shmhandle {
6145737Smckusick 	vm_offset_t	shmh_kva;
6245737Smckusick 	caddr_t		shmh_id;
6345737Smckusick };
6445737Smckusick 
6545737Smckusick vm_map_t shm_map;	/* address space for shared memory segments */
6645737Smckusick 
shminit()6741490Smckusick shminit()
6841490Smckusick {
6941490Smckusick 	register int i;
7045737Smckusick 	vm_offset_t whocares1, whocares2;
7141490Smckusick 
7245737Smckusick 	shm_map = kmem_suballoc(kernel_map, &whocares1, &whocares2,
7365668Shibler 				shminfo.shmall * NBPG, TRUE);
7441490Smckusick 	if (shminfo.shmmni > SHMMMNI)
7541490Smckusick 		shminfo.shmmni = SHMMMNI;
7641490Smckusick 	for (i = 0; i < shminfo.shmmni; i++) {
7741490Smckusick 		shmsegs[i].shm_perm.mode = 0;
7841490Smckusick 		shmsegs[i].shm_perm.seq = 0;
7941490Smckusick 	}
8041490Smckusick }
8141490Smckusick 
8242961Smckusick /*
8342961Smckusick  * Entry point for all SHM calls
8442961Smckusick  */
8554932Storek struct shmsys_args {
8654932Storek 	u_int which;
8754932Storek };
88*68306Scgd compat_43_shmsys(p, uap, retval)
8942961Smckusick 	struct proc *p;
9054932Storek 	struct shmsys_args *uap;
9142961Smckusick 	int *retval;
9241490Smckusick {
9341490Smckusick 
9442961Smckusick 	if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
9544405Skarels 		return (EINVAL);
9644405Skarels 	return ((*shmcalls[uap->which])(p, &uap[1], retval));
9741490Smckusick }
9841490Smckusick 
9942961Smckusick /*
10042961Smckusick  * Get a shared memory segment
10142961Smckusick  */
10254932Storek struct shmget_args {
10354932Storek 	key_t key;
10454932Storek 	int size;
10554932Storek 	int shmflg;
10654932Storek };
10742961Smckusick shmget(p, uap, retval)
10842961Smckusick 	struct proc *p;
10954932Storek 	register struct shmget_args *uap;
11042961Smckusick 	int *retval;
11142961Smckusick {
11241490Smckusick 	register struct shmid_ds *shp;
11347540Skarels 	register struct ucred *cred = p->p_ucred;
11441490Smckusick 	register int i;
11542961Smckusick 	int error, size, rval = 0;
11645737Smckusick 	register struct shmhandle *shmh;
11741490Smckusick 
11841490Smckusick 	/* look up the specified shm_id */
11941490Smckusick 	if (uap->key != IPC_PRIVATE) {
12041490Smckusick 		for (i = 0; i < shminfo.shmmni; i++)
12141490Smckusick 			if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) &&
12241490Smckusick 			    shmsegs[i].shm_perm.key == uap->key) {
12341490Smckusick 				rval = i;
12441490Smckusick 				break;
12541490Smckusick 			}
12641490Smckusick 	} else
12741490Smckusick 		i = shminfo.shmmni;
12841490Smckusick 
12941490Smckusick 	/* create a new shared segment if necessary */
13041490Smckusick 	if (i == shminfo.shmmni) {
13142961Smckusick 		if ((uap->shmflg & IPC_CREAT) == 0)
13242961Smckusick 			return (ENOENT);
13342961Smckusick 		if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
13442961Smckusick 			return (EINVAL);
13541490Smckusick 		for (i = 0; i < shminfo.shmmni; i++)
13641490Smckusick 			if ((shmsegs[i].shm_perm.mode & SHM_ALLOC) == 0) {
13741490Smckusick 				rval = i;
13841490Smckusick 				break;
13941490Smckusick 			}
14042961Smckusick 		if (i == shminfo.shmmni)
14142961Smckusick 			return (ENOSPC);
14241490Smckusick 		size = clrnd(btoc(uap->size));
14342961Smckusick 		if (shmtot + size > shminfo.shmall)
14442961Smckusick 			return (ENOMEM);
14541490Smckusick 		shp = &shmsegs[rval];
14641490Smckusick 		/*
14741490Smckusick 		 * We need to do a couple of things to ensure consistency
14841490Smckusick 		 * in case we sleep in malloc().  We mark segment as
14941490Smckusick 		 * allocated so that other shmgets() will not allocate it.
15041490Smckusick 		 * We mark it as "destroyed" to insure that shmvalid() is
15141490Smckusick 		 * false making most operations fail (XXX).  We set the key,
15241490Smckusick 		 * so that other shmget()s will fail.
15341490Smckusick 		 */
15441490Smckusick 		shp->shm_perm.mode = SHM_ALLOC | SHM_DEST;
15541490Smckusick 		shp->shm_perm.key = uap->key;
15645737Smckusick 		shmh = (struct shmhandle *)
15745737Smckusick 			malloc(sizeof(struct shmhandle), M_SHM, M_WAITOK);
15845737Smckusick 		shmh->shmh_kva = 0;
15945737Smckusick 		shmh->shmh_id = (caddr_t)(0xc0000000|rval);	/* XXX */
16045737Smckusick 		error = vm_mmap(shm_map, &shmh->shmh_kva, ctob(size),
16158595Shibler 				VM_PROT_ALL, VM_PROT_ALL,
16258595Shibler 				MAP_ANON, shmh->shmh_id, 0);
16345737Smckusick 		if (error) {
16445737Smckusick 			free((caddr_t)shmh, M_SHM);
16541490Smckusick 			shp->shm_perm.mode = 0;
16645737Smckusick 			return(ENOMEM);
16741490Smckusick 		}
16845737Smckusick 		shp->shm_handle = (void *) shmh;
16941490Smckusick 		shmtot += size;
17042961Smckusick 		shp->shm_perm.cuid = shp->shm_perm.uid = cred->cr_uid;
17142961Smckusick 		shp->shm_perm.cgid = shp->shm_perm.gid = cred->cr_gid;
17264399Smckusick 		shp->shm_perm.mode = SHM_ALLOC | (uap->shmflg & ACCESSPERMS);
17341490Smckusick 		shp->shm_segsz = uap->size;
17442922Smckusick 		shp->shm_cpid = p->p_pid;
17541490Smckusick 		shp->shm_lpid = shp->shm_nattch = 0;
17641490Smckusick 		shp->shm_atime = shp->shm_dtime = 0;
17741490Smckusick 		shp->shm_ctime = time.tv_sec;
17841490Smckusick 	} else {
17941490Smckusick 		shp = &shmsegs[rval];
18041490Smckusick 		/* XXX: probably not the right thing to do */
18142961Smckusick 		if (shp->shm_perm.mode & SHM_DEST)
18242961Smckusick 			return (EBUSY);
18364399Smckusick 		if (error = ipcaccess(&shp->shm_perm, uap->shmflg & ACCESSPERMS,
18464399Smckusick 			    cred))
18542961Smckusick 			return (error);
18642961Smckusick 		if (uap->size && uap->size > shp->shm_segsz)
18742961Smckusick 			return (EINVAL);
18842961Smckusick 		if ((uap->shmflg&IPC_CREAT) && (uap->shmflg&IPC_EXCL))
18942961Smckusick 			return (EEXIST);
19041490Smckusick 	}
19142961Smckusick 	*retval = shp->shm_perm.seq * SHMMMNI + rval;
19243408Shibler 	return (0);
19341490Smckusick }
19441490Smckusick 
19542961Smckusick /*
19642961Smckusick  * Shared memory control
19742961Smckusick  */
19854932Storek struct shmctl_args {
19954932Storek 	int shmid;
20054932Storek 	int cmd;
20154932Storek 	caddr_t buf;
20254932Storek };
20342961Smckusick /* ARGSUSED */
20442961Smckusick shmctl(p, uap, retval)
20542961Smckusick 	struct proc *p;
20654932Storek 	register struct shmctl_args *uap;
20742961Smckusick 	int *retval;
20842961Smckusick {
20941490Smckusick 	register struct shmid_ds *shp;
21047540Skarels 	register struct ucred *cred = p->p_ucred;
21141490Smckusick 	struct shmid_ds sbuf;
21242961Smckusick 	int error;
21341490Smckusick 
21442961Smckusick 	if (error = shmvalid(uap->shmid))
21542961Smckusick 		return (error);
21641490Smckusick 	shp = &shmsegs[uap->shmid % SHMMMNI];
21741490Smckusick 	switch (uap->cmd) {
21841490Smckusick 	case IPC_STAT:
21943408Shibler 		if (error = ipcaccess(&shp->shm_perm, IPC_R, cred))
22042961Smckusick 			return (error);
22142961Smckusick 		return (copyout((caddr_t)shp, uap->buf, sizeof(*shp)));
22241490Smckusick 
22341490Smckusick 	case IPC_SET:
22442961Smckusick 		if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
22542961Smckusick 		    cred->cr_uid != shp->shm_perm.cuid)
22642961Smckusick 			return (EPERM);
22742961Smckusick 		if (error = copyin(uap->buf, (caddr_t)&sbuf, sizeof sbuf))
22842961Smckusick 			return (error);
22942961Smckusick 		shp->shm_perm.uid = sbuf.shm_perm.uid;
23042961Smckusick 		shp->shm_perm.gid = sbuf.shm_perm.gid;
23164399Smckusick 		shp->shm_perm.mode = (shp->shm_perm.mode & ~ACCESSPERMS)
23264399Smckusick 			| (sbuf.shm_perm.mode & ACCESSPERMS);
23342961Smckusick 		shp->shm_ctime = time.tv_sec;
23441490Smckusick 		break;
23541490Smckusick 
23641490Smckusick 	case IPC_RMID:
23742961Smckusick 		if (cred->cr_uid && cred->cr_uid != shp->shm_perm.uid &&
23842961Smckusick 		    cred->cr_uid != shp->shm_perm.cuid)
23942961Smckusick 			return (EPERM);
24041490Smckusick 		/* set ctime? */
24141490Smckusick 		shp->shm_perm.key = IPC_PRIVATE;
24241490Smckusick 		shp->shm_perm.mode |= SHM_DEST;
24341490Smckusick 		if (shp->shm_nattch <= 0)
24441490Smckusick 			shmfree(shp);
24541490Smckusick 		break;
24641490Smckusick 
24741490Smckusick 	default:
24842961Smckusick 		return (EINVAL);
24941490Smckusick 	}
25042961Smckusick 	return (0);
25141490Smckusick }
25241490Smckusick 
25342961Smckusick /*
25442961Smckusick  * Attach to shared memory segment.
25542961Smckusick  */
25654932Storek struct shmat_args {
25754932Storek 	int	shmid;
25854932Storek 	caddr_t	shmaddr;
25954932Storek 	int	shmflg;
26054932Storek };
26142961Smckusick shmat(p, uap, retval)
26242961Smckusick 	struct proc *p;
26354932Storek 	register struct shmat_args *uap;
26442961Smckusick 	int *retval;
26542961Smckusick {
26641490Smckusick 	register struct shmid_ds *shp;
26741490Smckusick 	register int size;
26841490Smckusick 	caddr_t uva;
26945737Smckusick 	int error;
27045737Smckusick 	int flags;
27145737Smckusick 	vm_prot_t prot;
27245737Smckusick 	struct shmdesc *shmd;
27341490Smckusick 
27445737Smckusick 	/*
27545737Smckusick 	 * Allocate descriptors now (before validity check)
27645737Smckusick 	 * in case malloc() blocks.
27745737Smckusick 	 */
27847540Skarels 	shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
27945737Smckusick 	size = shminfo.shmseg * sizeof(struct shmdesc);
28045737Smckusick 	if (shmd == NULL) {
28145737Smckusick 		shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK);
28245737Smckusick 		bzero((caddr_t)shmd, size);
28347540Skarels 		p->p_vmspace->vm_shm = (caddr_t)shmd;
28445737Smckusick 	}
28542961Smckusick 	if (error = shmvalid(uap->shmid))
28642961Smckusick 		return (error);
28741490Smckusick 	shp = &shmsegs[uap->shmid % SHMMMNI];
28841490Smckusick 	if (shp->shm_handle == NULL)
28942349Smckusick 		panic("shmat NULL handle");
29043408Shibler 	if (error = ipcaccess(&shp->shm_perm,
29147540Skarels 	    (uap->shmflg&SHM_RDONLY) ? IPC_R : IPC_R|IPC_W, p->p_ucred))
29242961Smckusick 		return (error);
29341490Smckusick 	uva = uap->shmaddr;
29441490Smckusick 	if (uva && ((int)uva & (SHMLBA-1))) {
29541490Smckusick 		if (uap->shmflg & SHM_RND)
29641490Smckusick 			uva = (caddr_t) ((int)uva & ~(SHMLBA-1));
29742961Smckusick 		else
29842961Smckusick 			return (EINVAL);
29941490Smckusick 	}
30041490Smckusick 	/*
30141490Smckusick 	 * Make sure user doesn't use more than their fair share
30241490Smckusick 	 */
30345737Smckusick 	for (size = 0; size < shminfo.shmseg; size++) {
30445737Smckusick 		if (shmd->shmd_uva == 0)
30545737Smckusick 			break;
30645737Smckusick 		shmd++;
30745737Smckusick 	}
30842961Smckusick 	if (size >= shminfo.shmseg)
30942961Smckusick 		return (EMFILE);
31041490Smckusick 	size = ctob(clrnd(btoc(shp->shm_segsz)));
31145737Smckusick 	prot = VM_PROT_READ;
31245737Smckusick 	if ((uap->shmflg & SHM_RDONLY) == 0)
31345737Smckusick 		prot |= VM_PROT_WRITE;
31445737Smckusick 	flags = MAP_ANON|MAP_SHARED;
31545737Smckusick 	if (uva)
31645737Smckusick 		flags |= MAP_FIXED;
31745737Smckusick 	else
31845737Smckusick 		uva = (caddr_t)0x1000000;	/* XXX */
31953313Smckusick 	error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)&uva,
32058595Shibler 			(vm_size_t)size, prot, VM_PROT_ALL, flags,
32158595Shibler 			((struct shmhandle *)shp->shm_handle)->shmh_id, 0);
32242961Smckusick 	if (error)
32345737Smckusick 		return(error);
32445737Smckusick 	shmd->shmd_uva = (vm_offset_t)uva;
32545737Smckusick 	shmd->shmd_id = uap->shmid;
32641490Smckusick 	/*
32741490Smckusick 	 * Fill in the remaining fields
32841490Smckusick 	 */
32942922Smckusick 	shp->shm_lpid = p->p_pid;
33041490Smckusick 	shp->shm_atime = time.tv_sec;
33141490Smckusick 	shp->shm_nattch++;
33242961Smckusick 	*retval = (int) uva;
33343408Shibler 	return (0);
33441490Smckusick }
33541490Smckusick 
33642961Smckusick /*
33742961Smckusick  * Detach from shared memory segment.
33842961Smckusick  */
33954932Storek struct shmdt_args {
34054932Storek 	caddr_t	shmaddr;
34154932Storek };
34242961Smckusick /* ARGSUSED */
34342961Smckusick shmdt(p, uap, retval)
34442961Smckusick 	struct proc *p;
34554932Storek 	struct shmdt_args *uap;
34642961Smckusick 	int *retval;
34741490Smckusick {
34845737Smckusick 	register struct shmdesc *shmd;
34945737Smckusick 	register int i;
35041490Smckusick 
35147540Skarels 	shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
35245737Smckusick 	for (i = 0; i < shminfo.shmseg; i++, shmd++)
35345737Smckusick 		if (shmd->shmd_uva &&
35445737Smckusick 		    shmd->shmd_uva == (vm_offset_t)uap->shmaddr)
35541490Smckusick 			break;
35645737Smckusick 	if (i == shminfo.shmseg)
35764833Storek 		return (EINVAL);
35845737Smckusick 	shmufree(p, shmd);
35945737Smckusick 	shmsegs[shmd->shmd_id % SHMMMNI].shm_lpid = p->p_pid;
36064833Storek 	return (0);
36141490Smckusick }
36241490Smckusick 
36347540Skarels shmfork(p1, p2, isvfork)
36447540Skarels 	struct proc *p1, *p2;
36545737Smckusick 	int isvfork;
36641490Smckusick {
36745737Smckusick 	register struct shmdesc *shmd;
36845737Smckusick 	register int size;
36941490Smckusick 
37045737Smckusick 	/*
37145737Smckusick 	 * Copy parents descriptive information
37245737Smckusick 	 */
37345737Smckusick 	size = shminfo.shmseg * sizeof(struct shmdesc);
37445737Smckusick 	shmd = (struct shmdesc *)malloc(size, M_SHM, M_WAITOK);
37547540Skarels 	bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmd, size);
37647540Skarels 	p2->p_vmspace->vm_shm = (caddr_t)shmd;
37745737Smckusick 	/*
37845737Smckusick 	 * Increment reference counts
37945737Smckusick 	 */
38045737Smckusick 	for (size = 0; size < shminfo.shmseg; size++, shmd++)
38145737Smckusick 		if (shmd->shmd_uva)
38245737Smckusick 			shmsegs[shmd->shmd_id % SHMMMNI].shm_nattch++;
38341490Smckusick }
38441490Smckusick 
38545737Smckusick shmexit(p)
38645737Smckusick 	struct proc *p;
38741490Smckusick {
38845737Smckusick 	register struct shmdesc *shmd;
38945737Smckusick 	register int i;
39041490Smckusick 
39147540Skarels 	shmd = (struct shmdesc *)p->p_vmspace->vm_shm;
39245737Smckusick 	for (i = 0; i < shminfo.shmseg; i++, shmd++)
39345737Smckusick 		if (shmd->shmd_uva)
39445737Smckusick 			shmufree(p, shmd);
39547540Skarels 	free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
39647540Skarels 	p->p_vmspace->vm_shm = NULL;
39741490Smckusick }
39841490Smckusick 
shmvalid(id)39941490Smckusick shmvalid(id)
40041490Smckusick 	register int id;
40141490Smckusick {
40241490Smckusick 	register struct shmid_ds *shp;
40341490Smckusick 
40441490Smckusick 	if (id < 0 || (id % SHMMMNI) >= shminfo.shmmni)
40542961Smckusick 		return(EINVAL);
40641490Smckusick 	shp = &shmsegs[id % SHMMMNI];
40741490Smckusick 	if (shp->shm_perm.seq == (id / SHMMMNI) &&
40841490Smckusick 	    (shp->shm_perm.mode & (SHM_ALLOC|SHM_DEST)) == SHM_ALLOC)
40942961Smckusick 		return(0);
41042961Smckusick 	return(EINVAL);
41141490Smckusick }
41241490Smckusick 
41341490Smckusick /*
41441490Smckusick  * Free user resources associated with a shared memory segment
41541490Smckusick  */
41645737Smckusick shmufree(p, shmd)
41742922Smckusick 	struct proc *p;
41845737Smckusick 	struct shmdesc *shmd;
41941490Smckusick {
42041490Smckusick 	register struct shmid_ds *shp;
42141490Smckusick 
42245737Smckusick 	shp = &shmsegs[shmd->shmd_id % SHMMMNI];
42349710Shibler 	(void) vm_deallocate(&p->p_vmspace->vm_map, shmd->shmd_uva,
42445737Smckusick 			     ctob(clrnd(btoc(shp->shm_segsz))));
42545737Smckusick 	shmd->shmd_id = 0;
42645737Smckusick 	shmd->shmd_uva = 0;
42741490Smckusick 	shp->shm_dtime = time.tv_sec;
42841490Smckusick 	if (--shp->shm_nattch <= 0 && (shp->shm_perm.mode & SHM_DEST))
42941490Smckusick 		shmfree(shp);
43041490Smckusick }
43141490Smckusick 
43241490Smckusick /*
43341490Smckusick  * Deallocate resources associated with a shared memory segment
43441490Smckusick  */
shmfree(shp)43541490Smckusick shmfree(shp)
43641490Smckusick 	register struct shmid_ds *shp;
43741490Smckusick {
43841490Smckusick 
43941490Smckusick 	if (shp->shm_handle == NULL)
44041490Smckusick 		panic("shmfree");
44145737Smckusick 	/*
44245737Smckusick 	 * Lose our lingering object reference by deallocating space
44345737Smckusick 	 * in kernel.  Pager will also be deallocated as a side-effect.
44445737Smckusick 	 */
44545737Smckusick 	vm_deallocate(shm_map,
44645737Smckusick 		      ((struct shmhandle *)shp->shm_handle)->shmh_kva,
44749668Shibler 		      ctob(clrnd(btoc(shp->shm_segsz))));
44845737Smckusick 	free((caddr_t)shp->shm_handle, M_SHM);
44941490Smckusick 	shp->shm_handle = NULL;
45041490Smckusick 	shmtot -= clrnd(btoc(shp->shm_segsz));
45141490Smckusick 	shp->shm_perm.mode = 0;
45241490Smckusick 	/*
45341490Smckusick 	 * Increment the sequence number to ensure that outstanding
45441490Smckusick 	 * shmids for this segment will be invalid in the event that
45541490Smckusick 	 * the segment is reallocated.  Note that shmids must be
45641490Smckusick 	 * positive as decreed by SVID.
45741490Smckusick 	 */
45841490Smckusick 	shp->shm_perm.seq++;
45941490Smckusick 	if ((int)(shp->shm_perm.seq * SHMMMNI) < 0)
46041490Smckusick 		shp->shm_perm.seq = 0;
46141490Smckusick }
46241490Smckusick 
46341490Smckusick /*
46441490Smckusick  * XXX This routine would be common to all sysV style IPC
46541490Smckusick  *     (if the others were implemented).
46641490Smckusick  */
ipcaccess(ipc,mode,cred)46742961Smckusick ipcaccess(ipc, mode, cred)
46841490Smckusick 	register struct ipc_perm *ipc;
46942961Smckusick 	int mode;
47042961Smckusick 	register struct ucred *cred;
47141490Smckusick {
47241490Smckusick 	register int m;
47341490Smckusick 
47442961Smckusick 	if (cred->cr_uid == 0)
47541490Smckusick 		return(0);
47641490Smckusick 	/*
47741490Smckusick 	 * Access check is based on only one of owner, group, public.
47841490Smckusick 	 * If not owner, then check group.
47941490Smckusick 	 * If not a member of the group, then check public access.
48041490Smckusick 	 */
48141490Smckusick 	mode &= 0700;
48241490Smckusick 	m = ipc->mode;
48342961Smckusick 	if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) {
48441490Smckusick 		m <<= 3;
48542961Smckusick 		if (!groupmember(ipc->gid, cred) &&
48642961Smckusick 		    !groupmember(ipc->cgid, cred))
48741490Smckusick 			m <<= 3;
48841490Smckusick 	}
48941490Smckusick 	if ((mode&m) == mode)
49042961Smckusick 		return (0);
49142961Smckusick 	return (EACCES);
49241490Smckusick }
49341490Smckusick #endif /* SYSVSHM */
494