sysv_ipc.c revision 9acbbeaf2a1ffe5c14b244867d427714fab43c5c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <errno.h>
#include <unistd.h>
#include <strings.h>
#include <rctl.h>
#include <alloca.h>
#include <values.h>
#include <sys/lx_debug.h>
#include <sys/lx_types.h>
#include <sys/lx_sysv_ipc.h>
#include <sys/lx_syscall.h>
#define SLOT_SEM 0
#define SLOT_SHM 1
#define SLOT_MSG 2
static int
{
rctl_qty_t r;
return (-errno);
r = rctlblk_get_value(rblk);
if (r > MAXINT)
return (-EOVERFLOW);
return (r);
}
/*
* Given a slot number and a maximum number of ids to extract from the
* kernel, return the msgid in the provided slot.
*/
static int
{
int r;
nids = 0;
for (;;) {
switch (type) {
case SLOT_SEM:
break;
case SLOT_SHM:
break;
case SLOT_MSG:
break;
}
if (r < 0)
return (-errno);
if (max == 0)
return (-EINVAL);
return (-ENOMEM);
}
}
/*
* Semaphore operations.
*/
static int
{
int sol_flag;
int r;
if (semflg & LX_IPC_CREAT)
if (semflg & LX_IPC_EXCL)
return ((r < 0) ? -errno : r);
}
static int
{
int r;
if (nsops == 0)
return (-EINVAL);
return ((r < 0) ? -errno : r);
}
static int
{
struct lx_semid_ds semds;
int r;
return (-errno);
return ((r < 0) ? -errno : r);
}
static int
{
struct lx_semid_ds semds;
return (-errno);
/* Linux only uses the bottom 9 bits */
return (-errno);
return (0);
}
static int
lx_semctl_ipcinfo(void *buf)
{
struct lx_seminfo i;
int rblksz;
int idbuf;
rblksz = rctlblk_size();
return (-ENOMEM);
bzero(&i, sizeof (i));
return (i.semmni);
return (i.semmsl);
return (i.semopm);
/*
* We don't have corresponding rctls for these fields. The values
* are taken from the formulas used to derive the defaults listed
* in the Linux header file. We're lying, but trying to be
* coherent about it.
*/
return (-errno);
return (-errno);
return (nids);
}
static int
{
int r, semid;
if (semid < 0)
return (semid);
return (r < 0 ? r : semid);
}
/*
* For the SETALL operation, we have to examine each of the semaphore
* values to be sure it is legal.
*/
static int
{
int i, sz, r;
/*
* Find out how many semaphores are involved, reserve enough
* memory for an internal copy of the array, and then copy it in
* from the process.
*/
return (-errno);
return (-ENOMEM);
return (-errno);
/* Validate each of the values. */
return (-ERANGE);
return ((r < 0) ? -errno : r);
}
static int
{
int rval;
int use_errno = 0;
/*
* The final arg to semctl() is a pointer to a union. For some
* commands we can hand that pointer directly to the kernel. For
* these commands, we need to extract an argument from the union
* before calling into the kernel.
*/
return (-errno);
switch (opt) {
case LX_GETVAL:
use_errno = 1;
break;
case LX_SETVAL:
break;
}
use_errno = 1;
break;
case LX_GETPID:
use_errno = 1;
break;
case LX_GETNCNT:
use_errno = 1;
break;
case LX_GETZCNT:
use_errno = 1;
break;
case LX_GETALL:
use_errno = 1;
break;
case LX_SETALL:
break;
case LX_IPC_RMID:
use_errno = 1;
break;
case LX_SEM_STAT:
break;
case LX_IPC_STAT:
break;
case LX_IPC_SET:
break;
case LX_IPC_INFO:
case LX_SEM_INFO:
break;
default:
}
return (-errno);
return (rval);
}
/*
* msg operations.
*/
static int
{
int sol_flag;
int r;
if (flag & LX_IPC_CREAT)
if (flag & LX_IPC_EXCL)
return (r < 0 ? -errno : r);
}
static int
{
int sol_flag = 0;
int r;
if (flag & LX_IPC_NOWAIT)
sol_flag |= IPC_NOWAIT;
return (-EINVAL);
return (r < 0 ? -errno : r);
}
static int
{
int sol_flag = 0;
struct {
void *msgp;
long msgtype;
} args;
int r;
/*
* Rather than passing 5 args into ipc(2) directly, glibc passes 4
* args and uses the buf argument to point to a structure
* containing two args: a pointer to the message and the message
* type.
*/
return (-errno);
lx_debug("\tlx_msgrcv(%d, 0x%p, %d, %d, %ld, %d)\n",
/*
* Check for a negative sz parameter.
*
* Unlike msgsnd(2), the Linux man page does not specify that
* msgrcv(2) should return EINVAL if (sz > MSGMAX), only if (sz < 0).
*/
return (-EINVAL);
if (flag & LX_MSG_NOERROR)
sol_flag |= MSG_NOERROR;
if (flag & LX_IPC_NOWAIT)
sol_flag |= IPC_NOWAIT;
return (r < 0 ? -errno : r);
}
static int
{
struct lx_msqid_ds msgids;
struct msqid_ds sol_msgids;
int r;
if (r < 0)
return (-errno);
/* Linux only uses the bottom 9 bits */
return (-errno);
return (0);
}
static int
{
struct lx_msginfo m;
int rval;
rblksz = rctlblk_size();
return (-ENOMEM);
bzero(&m, sizeof (m));
return (m.msgmni);
return (m.msgmnb);
if (cmd == LX_IPC_INFO) {
"process.max-msg-messages")) < 0)
return (maxmsgs);
rval = 0;
} else {
return (-errno);
/*
* For these fields, we can't even come up with a good fake
* approximation. These are listed as 'obsolete' or
* 'unused' in the header files, so hopefully nobody is
* relying on them anyway.
*/
}
/*
* We don't have corresponding rctls for these fields. The values
* are taken from the formulas used to derive the defaults listed
* in the Linux header file. We're lying, but trying to be
* coherent about it.
*/
m.msgssz = 16;
return (-errno);
return (rval);
}
static int
{
struct lx_msqid_ds msgids;
struct msqid_ds sol_msgids;
int r;
return (-errno);
/* Linux only uses the bottom 9 bits */
return (r < 0 ? -errno : r);
}
static int
{
int r, msgid;
if (msgid < 0)
return (msgid);
return (r < 0 ? r : msgid);
}
/*
* Split off the various msgctl's here
*/
static int
{
int r;
case LX_IPC_RMID:
if (r < 0)
r = -errno;
break;
case LX_IPC_SET:
break;
case LX_IPC_STAT:
break;
case LX_MSG_STAT:
break;
case LX_IPC_INFO:
case LX_MSG_INFO:
break;
default:
r = -EINVAL;
break;
}
return (r);
}
/*
* shm-related operations.
*/
static int
{
int sol_flag;
int r;
if (flag & LX_IPC_CREAT)
if (flag & LX_IPC_EXCL)
return (r < 0 ? -errno : r);
}
static int
{
int sol_flags;
void *ptr;
sol_flags = 0;
if (flags & LX_SHM_RDONLY)
sol_flags |= SHM_RDONLY;
if (flags & LX_SHM_RND)
return (-EINVAL);
if (ptr == (void *)-1)
return (-errno);
return (-errno);
return (0);
}
static int
lx_shmctl_ipcinfo(void *buf)
{
struct lx_shminfo s;
int rblksz;
rblksz = rctlblk_size();
return (-ENOMEM);
bzero(&s, sizeof (s));
return (s.shmmni);
return (s.shmmax);
/*
* We don't have corresponding rctls for these fields. The values
* are taken from the formulas used to derive the defaults listed
* in the Linux header file. We're lying, but trying to be
* coherent about it.
*/
s.shmmin = 1;
return (-errno);
return (0);
}
static int
{
struct lx_shmid_ds shmds;
return (-errno);
return (-errno);
return (0);
}
static int
{
struct lx_shmid_ds shmds;
int r;
return (-errno);
return (r < 0 ? -errno : r);
}
/*
* Build and return a shm_info structure. We only return the bare
* essentials required by ipcs. The rest of the info is not readily
* available.
*/
static int
lx_shmctl_shminfo(void *buf)
{
struct lx_shm_info shminfo;
int idbuf;
return (-errno);
return (-errno);
return (nids);
}
static int
{
int r, shmid;
if (shmid < 0)
return (shmid);
return (r < 0 ? r : shmid);
}
static int
{
int r;
int use_errno = 0;
case LX_IPC_RMID:
use_errno = 1;
break;
case LX_IPC_SET:
break;
case LX_IPC_STAT:
break;
case LX_IPC_INFO:
r = lx_shmctl_ipcinfo(buf);
break;
case LX_SHM_LOCK:
use_errno = 1;
break;
case LX_SHM_UNLOCK:
use_errno = 1;
break;
case LX_SHM_INFO:
r = lx_shmctl_shminfo(buf);
break;
case LX_SHM_STAT:
break;
default:
r = -EINVAL;
break;
}
if (use_errno == 1 && r < 0)
return (-errno);
return (r);
}
/*
* Under Linux, glibc funnels all of the sysv IPC operations into this
* single ipc(2) system call. We need to blow that up and filter the
* remnants into the proper Solaris system calls.
*/
int
{
int r;
lx_debug("lx_ipc(%d, %d, %d, %d, 0x%p, %d)\n",
switch (cmd) {
case LX_MSGGET:
break;
case LX_MSGSND:
break;
case LX_MSGRCV:
break;
case LX_MSGCTL:
break;
case LX_SEMCTL:
break;
case LX_SEMOP:
/*
* 'struct sembuf' is the same on Linux and Solaris, so we
* pass bufptr straight through.
*/
break;
case LX_SEMGET:
break;
case LX_SHMAT:
break;
case LX_SHMDT:
if (r < 0)
r = -errno;
break;
case LX_SHMGET:
break;
case LX_SHMCTL:
break;
default:
r = -EINVAL;
}
return (r);
}