/*-
* Copyright (c) 1998, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Values in support of System V compatible semaphores.
*/
#ifdef SYSVSEM
struct seminfo seminfo = {
SEMMAP, /* # of entries in semaphore map */
SEMMNI, /* # of semaphore identifiers */
SEMMNS, /* # of semaphores in system */
SEMMNU, /* # of undo structures in system */
SEMMSL, /* max # of semaphores per id */
SEMOPM, /* max # of operations per semop call */
SEMUME, /* max # of undo entries per process */
SEMUSZ, /* size in bytes of undo structure */
SEMVMX, /* semaphore maximum value */
SEMAEM /* adjust on exit max value */
};
#endif
/*
* Values in support of System V compatible messages.
*/
#ifdef SYSVMSG
struct msginfo msginfo = {
MSGMAX, /* max chars in a message */
MSGMNI, /* # of message queue identifiers */
MSGMNB, /* max chars in a queue */
MSGTQL, /* max messages in system */
MSGSSZ, /* size of a message segment */
/* (must be small power of 2 greater than 4) */
MSGSEG /* number of message segments */
};
#endif
static int
sysv_ipc_modcmd(modcmd_t cmd, void *arg)
{
int error = 0;
switch (cmd) {
case MODULE_CMD_INIT:
/* Set up the kauth listener */
sysvipcinit();
/* Link the system calls */
error = syscall_establish(NULL, sysvipc_syscalls);
if (error) {
sysvipcfini();
return error;
}
/*
* Initialize each sub-component, including their
* sysctl data
*/
#ifdef SYSVSHM
error = shminit();
if (error != 0)
return error;
#endif
#ifdef SYSVSEM
error = seminit();
if (error != 0) {
#ifdef SYSVSHM
shmfini();
#endif
return error;
}
#endif
#ifdef SYSVMSG
error = msginit();
if (error != 0) {
#ifdef SYSVSEM
semfini();
#endif
#ifdef SYSVSHM
shmfini();
#endif
return error;
}
#endif
break;
case MODULE_CMD_FINI:
/*
* Make sure no subcomponents are active. Each one
* tells us if it is busy, and if it was _not_ busy,
* we assume it has already done its own clean-up.
* So we might need to re-init any components that
* are successfully fini'd if we find one that is
* still busy.
*/
#ifdef SYSVSHM
if (shmfini()) {
return EBUSY;
}
#endif
#ifdef SYSVSEM
if (semfini()) {
#ifdef SYSVSHM
shminit();
#endif
return EBUSY;
}
#endif
#ifdef SYSVMSG
if (msgfini()) {
#ifdef SYSVSEM
seminit();
#endif
#ifdef SYSVSHM
shminit();
#endif
return EBUSY;
}
#endif
/* Unlink the system calls. */
error = syscall_disestablish(NULL, sysvipc_syscalls);
if (error)
return error;
/*
* If present, call the compat sysctl() code. If it handles the request
* completely (either success or error), return. Otherwise fallthrough
* to the non-compat sysctl code.
*/
MODULE_HOOK_CALL(sysvipc_sysctl_50_hook, (SYSCTLFN_CALL(rnode)),
stub_sysvipc50_sysctl(SYSCTLFN_CALL(rnode)), error);
if (error != EPASSTHROUGH)
return error;
if (namelen != 1)
return EINVAL;
start = where;
buflen = *sizep;
switch (*name) {
case KERN_SYSVIPC_MSG_INFO:
#ifdef SYSVMSG
infosize = sizeof(msgsi->msginfo);
nds = msginfo.msgmni;
dssize = sizeof(msgsi->msgids[0]);
break;
#else
return EINVAL;
#endif
case KERN_SYSVIPC_SEM_INFO:
#ifdef SYSVSEM
infosize = sizeof(semsi->seminfo);
nds = seminfo.semmni;
dssize = sizeof(semsi->semids[0]);
break;
#else
return EINVAL;
#endif
case KERN_SYSVIPC_SHM_INFO:
#ifdef SYSVSHM
infosize = sizeof(shmsi->shminfo);
nds = shminfo.shmmni;
dssize = sizeof(shmsi->shmids[0]);
break;
#else
return EINVAL;
#endif
default:
return EINVAL;
}
/*
* Round infosize to 64 bit boundary if requesting more than just
* the info structure or getting the total data size.
*/
if (where == NULL || *sizep > infosize)
infosize = roundup(infosize, sizeof(quad_t));
tsize = infosize + nds * dssize;
/* Return just the total size required. */
if (where == NULL) {
*sizep = tsize;
return 0;
}
/* Not enough room for even the info struct. */
if (buflen < infosize) {
*sizep = 0;
return ENOMEM;
}
sz = uimin(tsize, buflen);
bf = kmem_zalloc(sz, KM_SLEEP);