sysv_shm.c from Adam.

sysv_ipc.c from me.
and various sundry changes to make sysv_ipc.c fit in.
(somewhat untested and not very pleasant reading material)
This commit is contained in:
hpeyerl 1994-05-25 02:14:24 +00:00
parent d1584360d9
commit 2d7c7416dd
4 changed files with 584 additions and 93 deletions

View File

@ -1,102 +1,61 @@
/*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990 The Regents of the University of California.
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* the Systems Programming Group of the University of Utah Computer
* Science Department. Originally from University of Wisconsin.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$
*
* from: @(#)sysv_shm.c 7.15 (Berkeley) 5/13/91
* $Id: sysv_ipc.c,v 1.3 1994/05/12 00:54:58 cgd Exp $
*/
/*
* IPC routines shared by some or all of the SYSV IPC system calls.
*/
#ifndef SYSVIPC
#ifdef SYSVSHM
#define SYSVIPC
#endif
#ifdef SYSVSEM
#define SYSVIPC
#endif
#ifdef SYSVMSG
#define SYSVIPC
#endif
#endif
#ifdef SYSVIPC
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/ipc.h>
#include <sys/systm.h>
/*
* Perform access checking.
* Check for ipc permission
*/
ipcaccess(ipc, mode, cred)
register struct ipc_perm *ipc;
int
ipcperm(uc, perm, mode)
struct ucred *uc;
struct ipc_perm *perm;
int mode;
register struct ucred *cred;
{
register int m;
int i = 0;
if (cred->cr_uid == 0)
if (uc->cr_uid == 0)
return(0);
/*
* Access check is based on only one of owner, group, public.
* If not owner, then check group.
* If not a member of the group, then check public access.
* Does the user have permission?
*/
mode &= 0700;
m = ipc->mode;
if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) {
m <<= 3;
if (!groupmember(ipc->gid, cred) &&
!groupmember(ipc->cgid, cred))
m <<= 3;
if (uc->cr_uid != perm->cuid && uc->cr_uid != perm->uid) {
i = 3;
/*
* Does the group have permission?
*/
if (!groupmember(perm->gid, uc) && !groupmember(perm->cgid, uc))
i += 3;
}
if ((mode&m) == mode)
return (0);
return (EACCES);
if (((mode&0700) & (perm->mode << i)) != mode)
return(EACCES);
}
#endif /* SYSVSHM */

View File

@ -16,7 +16,7 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
* $Id: sysv_msg.c,v 1.5 1994/02/15 13:35:53 mycroft Exp $
* $Id: sysv_msg.c,v 1.6 1994/05/25 02:14:33 hpeyerl Exp $
*/
#include <sys/param.h>
@ -257,7 +257,7 @@ msgctl(p, uap, retval)
break;
case IPC_STAT:
if ((eval = ipcaccess(&msqptr->msg_perm, IPC_R, cred))) {
if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
#ifdef MSG_DEBUG_OK
printf("requester doesn't have read access\n");
#endif
@ -317,8 +317,7 @@ msgget(p, uap, retval)
#endif
return(EEXIST);
}
if ((eval = ipcaccess(&msqptr->msg_perm, msgflg & 0700,
cred))) {
if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) {
#ifdef MSG_DEBUG_OK
printf("requester doesn't have 0%o access\n",
msgflg & 0700);
@ -437,7 +436,7 @@ msgsnd(p, uap, retval)
return(EINVAL);
}
if ((eval = ipcaccess(&msqptr->msg_perm, IPC_W, cred))) {
if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
#ifdef MSG_DEBUG_OK
printf("requester doesn't have write access\n");
#endif
@ -774,7 +773,7 @@ msgrcv(p, uap, retval)
return(EINVAL);
}
if ((eval = ipcaccess(&msqptr->msg_perm, IPC_R, cred))) {
if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
#ifdef MSG_DEBUG_OK
printf("requester doesn't have read access\n");
#endif

View File

@ -5,7 +5,7 @@
*
* This software is provided ``AS IS'' without any warranties of any kind.
*
* $Id: sysv_sem.c,v 1.6 1994/02/13 11:31:16 mycroft Exp $
* $Id: sysv_sem.c,v 1.7 1994/05/25 02:14:29 hpeyerl Exp $
*/
#include <sys/param.h>
@ -361,7 +361,7 @@ semctl(p, uap, retval)
break;
case IPC_STAT:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
@ -370,7 +370,7 @@ semctl(p, uap, retval)
break;
case GETNCNT:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
@ -378,7 +378,7 @@ semctl(p, uap, retval)
break;
case GETPID:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
@ -386,7 +386,7 @@ semctl(p, uap, retval)
break;
case GETVAL:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
@ -394,7 +394,7 @@ semctl(p, uap, retval)
break;
case GETALL:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
@ -407,7 +407,7 @@ semctl(p, uap, retval)
break;
case GETZCNT:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
@ -415,7 +415,7 @@ semctl(p, uap, retval)
break;
case SETVAL:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
return(eval);
if (semnum < 0 || semnum >= semaptr->sem_nsems)
return(EINVAL);
@ -427,7 +427,7 @@ semctl(p, uap, retval)
break;
case SETALL:
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)))
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
return(eval);
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
return(eval);
@ -483,8 +483,8 @@ semget(p, uap, retval)
#ifdef SEM_DEBUG
printf("found public key\n");
#endif
if ((eval = ipcaccess(&sema[semid].sem_perm,
semflg & 0700, cred)))
if ((eval = ipcperm(cred, &sema[semid].sem_perm,
semflg & 0700)))
return(eval);
if (nsems > 0 && sema[semid].sem_nsems < nsems) {
#ifdef SEM_DEBUG
@ -602,7 +602,7 @@ semop(p, uap, retval)
if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
return(EINVAL);
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred))) {
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
#ifdef SEM_DEBUG
printf("eval = %d from ipaccess\n", eval);
#endif

View File

@ -1 +1,534 @@
revision 1.10 intentionally removed
/*
* Copyright (c) 1994 Adam Glass
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the Author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* based on ..., ..., and ...
* $Header: /cvsroot/src/sys/kern/sysv_shm.c,v 1.11 1994/05/25 02:14:27 hpeyerl Exp $
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/shm.h>
#include <sys/proc.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/systm.h>
#include <vm/vm.h>
#include <vm/vm_map.h>
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
/*
* Provides the following externally accessible functions:
*
* shminit(void); initialization
* shmexit(struct proc *) cleanup
* shmfork(struct proc *, struct proc *, int) fork handling
* shmsys(arg1, arg2, arg3, arg4); shm{at,ctl,dt,get}(arg2, arg3, arg4)
*
* Structures:
* shmsegs (an array of 'struct shmid_ds')
* per proc array of 'struct shmmap_state'
*/
#define SHMSEG_FREE 0x200
#define SHMSEG_REMOVED 0x400
#define SHMSEG_ALLOCATED 0x800
#define SHMSEG_INVALID (SHMSEG_FREE | SHMSEG_REMOVED)
#define SHMSEG_PERM_MASK 0x1FF
vm_map_t sysvshm_map;
int shm_last_free, shm_nused, shm_committed;
struct shmat_args {
u_int shm_syscall;
int shmid;
void *shmaddr;
int shmflg;
};
struct shmctl_args {
u_int shm_syscall;
int shmid;
int cmd;
struct shmat_ds *ubuf;
};
struct shmdt_args {
u_int shm_syscall;
int shmid;
void *shmaddr;
int shmflg;
};
struct shmget_args {
u_int shm_syscall;
key_t key;
size_t size;
int shmflg;
};
struct shmsys_args {
u_int shm_syscall;
};
struct shm_handle {
vm_offset_t kva;
};
struct shmmap_state {
vm_offset_t va;
int shmid;
};
/* external intefaces */
int shmsys __P((struct proc *, struct shmsys_args *, int *));
void shminit __P((void));
/* internal functions */
static int shmseg_alloc __P((struct proc *, key_t, size_t, int, int *));
static int shmseg_find_key __P((key_t));
static struct shmid_ds *shmseg_find_shmid __P((int, int *));
static int shmget_existing __P((struct proc *, struct shmget_args *, int,
int, int *));
static int shmget __P((struct proc *, struct shmget_args *, int *));
static int shmctl __P((struct proc *, struct shmctl_args *, int *));
static int shmseg_alloc(p, key, size, mode, retval)
struct proc *p;
key_t key;
size_t size;
int mode;
int *retval;
{
int i, segnum, result, shmid;
struct ucred *ucred = p->p_ucred;
struct shmid_ds *shmseg;
struct shm_handle *shm_handle;
if (shm_nused >= shminfo.shmmni) /* any shmids left? */
return ENOSPC;
if (shm_last_free < 0) {
for (i=0; i < shminfo.shmmni; i++)
if (shmsegs[i].shm_perm.mode & SHMSEG_FREE) break;
if (i == shminfo.shmmni)
panic("shmseg free count inconsistent");
segnum = i;
}
else
segnum = shm_last_free;
shmseg = &shmsegs[segnum];
shmseg->shm_perm.mode = SHMSEG_ALLOCATED;
shm_handle = (struct shm_handle *)
malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
result = vm_mmap(sysvshm_map, &shm_handle->kva,
ctob(clrnd(btoc(size))), VM_PROT_ALL, VM_PROT_DEFAULT,
MAP_ANON, shmid, 0);
if (result != KERN_SUCCESS) {
shmseg->shm_perm.mode = SHMSEG_FREE;
free((caddr_t) shm_handle, M_SHM);
return ENOMEM;
}
shmseg->shm_internal = shm_handle;
shmseg->shm_perm.cuid = shmseg->shm_perm.uid =
ucred->cr_uid;
shmseg->shm_perm.cgid = shmseg->shm_perm.gid =
ucred->cr_gid;
shmseg->shm_perm.mode = mode;
shmseg->shm_perm.seq = shmseg->shm_perm.seq + 1;
shmseg->shm_perm.key = key;
shmseg->shm_segsz = size;
shmseg->shm_cpid = p->p_pid;
shmseg->shm_lpid = shmseg->shm_nattch =
shmseg->shm_atime = shmseg->shm_dtime = 0;
shmseg->shm_ctime = time.tv_sec;
shmseg->shm_internal = NULL; /* we aren't using this field */
shm_committed += clrnd(btoc(size));
shm_nused++;
shm_last_free = -1;
*retval = shmid;
return 0;
}
static int shmseg_find_key(key)
key_t key;
{
int i;
for (i=0; i < shminfo.shmmni; i++) {
if (shmsegs[i].shm_perm.mode & SHMSEG_INVALID) continue;
if (shmsegs[i].shm_perm.key != key) continue;
return i;
}
return -1;
}
static struct shmid_ds *shmseg_find_shmid(shmid, where)
int shmid;
int *where;
{
int segnum;
struct shmid_ds *shmseg;
segnum = IPCID_TO_IX(shmid);
if (segnum >= shminfo.shmmni)
return NULL;
shmseg = &shmsegs[segnum];
if ((shmseg->shm_perm.mode & (SHMSEG_FREE|SHMSEG_ALLOCATED)) ||
(shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid)))
return NULL;
if (where)
*where = segnum;
return shmseg;
}
static vm_offset_t shm_find_space(p, size)
struct proc *p;
size_t size;
{
vm_offset_t low_end, range, current;
int result;
low_end = (vm_offset_t) p->p_vmspace->vm_daddr +
NBPG * p->p_vmspace->vm_dsize;
range = (USRSTACK - low_end);
/* current = range *3/4 + low_end */
current = ((range&1)<<1 + range)>>2 + range>>1 + low_end;
#if 0
result = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &current, size,
TRUE);
if (result)
return NULL;
#endif
return current;
}
static int shmdt_seg(p, shmseg, shmmap_s)
struct proc *p;
struct shmid_ds *shmseg;
struct shmmap_state *shmmap_s;
{
int result;
size_t size;
size = ctob(clrnd(btoc(shmseg->shm_segsz)));
result = vm_deallocate(&p->p_vmspace->vm_map, shmmap_s->va, size);
if (result != KERN_SUCCESS)
return EINVAL;
shmseg->shm_nattch--;
shmseg->shm_dtime = time.tv_sec;
if ((shmseg->shm_nattch == 0) &&
(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
shmseg->shm_perm.mode = SHMSEG_FREE;
shm_last_free = IPCID_TO_IX(shmmap_s->shmid);
}
shmmap_s->va = 0;
return 0;
}
static int shmdt(p, uap, retval)
struct proc *p;
struct shmdt_args *uap;
int *retval;
{
int i;
struct shmid_ds *shmseg;
struct shmmap_state *shmmap_s;
if (p->p_vmspace->vm_shm == NULL)
return EINVAL;
shmseg = shmseg_find_shmid(uap->shmid, NULL);
if (shmseg == NULL)
return EINVAL;
shmmap_s = (struct shmmap_state *) p->p_vmspace->vm_shm;
for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
if ((shmmap_s->va != (vm_offset_t) uap->shmaddr) ||
(shmmap_s->shmid != uap->shmid)) continue;
break;
}
if (i == shminfo.shmseg)
return EINVAL;
return shmdt_seg(p, shmseg, shmmap_s);
}
static int shmat(p, uap, retval)
struct proc *p;
struct shmat_args *uap;
int *retval;
{
int error, segnum, i, ipc_prot;
struct ucred *ucred = p->p_ucred;
struct shmid_ds *shmseg;
struct shmmap_state *shmmap_s = NULL;
vm_offset_t attach_va;
vm_prot_t prot;
vm_size_t size;
start:
shmseg = shmseg_find_shmid(uap->shmid, NULL);
if (shmseg == NULL)
return EINVAL;
if (error = ipcperm(ucred, &shmseg->shm_perm,
((uap->shmflg & SHM_RDONLY) ? IPC_R :
(IPC_R|IPC_W)))) return error;
prot = VM_PROT_READ | ((uap->shmflg & SHM_RDONLY) ? 0 : VM_PROT_WRITE);
if (p->p_vmspace->vm_shm == NULL) {
shmmap_s = malloc(sizeof(struct shmmap_state)*shminfo.shmseg,
M_SHM, M_WAITOK);
bzero((caddr_t) shmmap_s, sizeof(struct shmmap_state) *
shminfo.shmseg);
p->p_vmspace->vm_shm = (caddr_t) shmmap_s;
goto start; /* things may have changed if we slept */
}
if (shmmap_s == NULL) {
shmmap_s = (struct shmmap_state *) p->p_vmspace->vm_shm;
for (i = 0; i < shminfo.shmseg; i++) {
if (shmmap_s->va == 0) break;
shmmap_s++;
}
if (i == shminfo.shmseg)
return EMFILE;
}
if (uap->shmaddr) {
if (uap->shmflg & SHM_RND)
attach_va = (vm_offset_t) uap->shmaddr -
((vm_offset_t)uap->shmaddr % SHMLBA);
else
attach_va = (vm_offset_t) uap->shmaddr;
}
else attach_va = shm_find_space(p, shmseg->shm_segsz);
if (attach_va == NULL)
return ENOMEM;
size = ctob(clrnd(btoc(shmseg->shm_segsz)));
error = vm_mmap(&p->p_vmspace->vm_map, &attach_va, size,
prot, VM_PROT_DEFAULT,
MAP_ANON|MAP_SHARED|(uap->shmaddr ? MAP_FIXED : 0),
uap->shmid, 0);
if (error)
return error;
shmmap_s->shmid = uap->shmid;
shmseg->shm_lpid = p->p_pid;
shmseg->shm_atime = time.tv_sec;
shmseg->shm_nattch++;
*retval = shmmap_s->va = attach_va;
return 0;
}
static int shmctl(p, uap, retval)
struct proc *p;
struct shmctl_args *uap;
int *retval;
{
int error, segnum;
struct ucred *ucred = p->p_ucred;
struct shmid_ds inbuf;
struct shmid_ds *shmseg;
shmseg = shmseg_find_shmid(uap->shmid, &segnum);
if (shmseg == NULL)
return EINVAL;
switch (uap->cmd) {
case IPC_STAT:
if (error = ipcperm(ucred, &shmseg->shm_perm, IPC_R))
return error;
if (error = copyout((caddr_t) shmseg,
uap->ubuf, sizeof(inbuf)))
return error;
break;
case IPC_SET:
if (ucred->cr_uid && (ucred->cr_uid != shmseg->shm_perm.uid) &&
(ucred->cr_uid != shmseg->shm_perm.cuid))
return EPERM;
if (error = copyin((caddr_t) uap->ubuf, (caddr_t)&inbuf,
sizeof(inbuf)))
return error;
shmseg->shm_perm.uid = inbuf.shm_perm.uid;
shmseg->shm_perm.gid = inbuf.shm_perm.gid;
shmseg->shm_perm.mode = inbuf.shm_perm.mode & SHMSEG_PERM_MASK;
break;
case IPC_RMID:
if (ucred->cr_uid && (ucred->cr_uid != shmseg->shm_perm.uid) &&
(ucred->cr_uid != shmseg->shm_perm.cuid))
return EPERM;
if (shmseg->shm_nattch)
shmseg->shm_perm.mode |= SHMSEG_REMOVED;
else {
struct shm_handle *shm_handle = shmseg->shm_internal;
(void) vm_deallocate(sysvshm_map,
shm_handle->kva,
ctob(clrnd(btoc(shmseg->shm_segsz))));
free((caddr_t) shm_handle, M_SHM);
shmseg->shm_internal = NULL;
shm_committed -= clrnd(btoc(shmseg->shm_segsz));
free((caddr_t) shmseg->shm_internal, M_SHM);
shmseg->shm_perm.mode = SHMSEG_FREE;
shm_last_free = segnum;
}
break;
#if 0
case SHM_LOCK:
case SHM_UNLOCK:
#endif
default:
return EINVAL;
}
shmseg->shm_ctime = time.tv_sec;
return 0;
}
static int shmget_existing(p, uap, mode, segnum, retval)
struct proc *p;
struct shmget_args *uap;
int mode;
int segnum;
int *retval;
{
int error;
struct ucred *ucred = p->p_ucred;
struct shmid_ds *shmseg;
shmseg = &shmsegs[segnum];
if ((uap->shmflg & IPC_CREAT) || (uap->shmflg & IPC_EXCL)) /* XXX */
return EEXIST;
if (error = ipcperm(ucred, shmseg->shm_perm, mode))
return error;
if (uap->size && (uap->size > shmseg->shm_segsz))
return EINVAL;
*retval = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
return 0;
}
static int shmget(p, uap, retval)
struct proc *p;
struct shmget_args *uap;
int *retval;
{
int segnum, mode, error;
size_t size;
struct shmid_ds *shmseg;
if ((uap->size < shminfo.shmmin) || (uap->size > shminfo.shmmax))
return EINVAL;
mode = uap->shmflg & SHMSEG_PERM_MASK;
if (uap->key != IPC_PRIVATE) {
segnum = shmseg_find_key(uap->key);
if (segnum >=0)
return shmget_existing(p, uap, mode, segnum, retval);
}
if ((uap->shmflg & IPC_CREAT) == 0)
return ENOENT;
size = clrnd(btoc(uap->size));
if (size + shm_committed > shminfo.shmall)
return ENOMEM;
return shmseg_alloc(p, uap->key, uap->size, mode, retval);
}
int shmsys(p, uap, retval)
struct proc *p;
struct shmsys_args *uap;
int *retval;
{
int result;
/*
* pass whole uap to avoid structure alignment problems
*/
/* sub-syscall # not exported in any header file */
switch(uap->shm_syscall) {
case 0:
result = shmat(p, (struct shmat_args *) uap, retval);
break;
case 1:
result = shmctl(p, (struct shmctl_args *) uap, retval);
break;
case 2:
result = shmdt(p, (struct shmdt_args *) uap, retval);
break;
case 3:
result = shmget(p, (struct shmget_args *) uap, retval);
break;
default:
result = EINVAL;
break;
}
return result;
}
void shmfork(p1, p2, isvfork)
struct proc *p1, *p2;
int isvfork;
{
struct shmmap_state *shmmap_s;
int i;
shmmap_s = malloc(sizeof(struct shmmap_state) * shminfo.shmseg,
M_SHM, M_WAITOK);
p2->p_vmspace->vm_shm = (caddr_t) shmmap_s;
bcopy((caddr_t) p1->p_vmspace->vm_shm, (caddr_t) shmmap_s,
sizeof(struct shmmap_state) * shminfo.shmseg);
for (i=0; i < shminfo.shmseg; i++, shmmap_s++)
if (shmmap_s->va != NULL)
shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
}
void shmexit(p)
struct proc *p;
{
int i;
struct shmid_ds *shmseg;
struct shmmap_state *shmmap_s;
shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
for (i=0; i < shminfo.shmseg; i++, shmmap_s++) {
if (shmmap_s->va != 0) continue;
shmseg = shmseg_find_shmid(shmmap_s->shmid, NULL);
(void) shmdt_seg(p, shmseg, shmmap_s);
}
free(p->p_vmspace->vm_shm, M_SHM);
p->p_vmspace->vm_shm = NULL;
}
void shminit()
{
int i;
vm_offset_t garbage1, garbage2;
/* actually this *should* be pageable. SHM_{LOCK,UNLOCK} */
sysvshm_map = kmem_suballoc(kernel_map, &garbage1, &garbage2,
shminfo.shmall * NBPG, FALSE);
for (i = 0; i < shminfo.shmmni; i++) {
shmsegs[i].shm_perm.mode = SHMSEG_FREE;
shmsegs[i].shm_perm.seq = 0;
}
shm_last_free = 0;
shm_nused = 0;
shm_committed = 0;
}