summaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_ipc.c
diff options
context:
space:
mode:
authorcvs2svn <cvs2svn@FreeBSD.org>2000-08-23 11:54:11 +0000
committercvs2svn <cvs2svn@FreeBSD.org>2000-08-23 11:54:11 +0000
commit4cd12ae4adcc6f21e6e9f792cbbffbc84ca3c241 (patch)
treebe71fbbceeafa07b9e0d0479121f39af265e628c /sys/compat/linux/linux_ipc.c
parent897e9ff84512ffa962c10bc1731d5fbd3ac16f6a (diff)
Notes
Diffstat (limited to 'sys/compat/linux/linux_ipc.c')
-rw-r--r--sys/compat/linux/linux_ipc.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c
new file mode 100644
index 000000000000..48e13d578277
--- /dev/null
+++ b/sys/compat/linux/linux_ipc.c
@@ -0,0 +1,447 @@
+/*-
+ * Copyright (c) 1994-1995 Søren Schmidt
+ * 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
+ * in this position and unchanged.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/proc.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#include <compat/linux/linux_ipc.h>
+#include <compat/linux/linux_util.h>
+
+struct linux_ipc_perm {
+ linux_key_t key;
+ unsigned short uid;
+ unsigned short gid;
+ unsigned short cuid;
+ unsigned short cgid;
+ unsigned short mode;
+ unsigned short seq;
+};
+
+static void
+linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp)
+{
+ bpp->key = lpp->key;
+ bpp->uid = lpp->uid;
+ bpp->gid = lpp->gid;
+ bpp->cuid = lpp->cuid;
+ bpp->cgid = lpp->cgid;
+ bpp->mode = lpp->mode;
+ bpp->seq = lpp->seq;
+}
+
+
+static void
+bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp)
+{
+ lpp->key = bpp->key;
+ lpp->uid = bpp->uid;
+ lpp->gid = bpp->gid;
+ lpp->cuid = bpp->cuid;
+ lpp->cgid = bpp->cgid;
+ lpp->mode = bpp->mode;
+ lpp->seq = bpp->seq;
+}
+
+struct linux_semid_ds {
+ struct linux_ipc_perm sem_perm;
+ linux_time_t sem_otime;
+ linux_time_t sem_ctime;
+ void *sem_base;
+ void *sem_pending;
+ void *sem_pending_last;
+ void *undo;
+ ushort sem_nsems;
+};
+
+struct linux_shmid_ds {
+ struct linux_ipc_perm shm_perm;
+ int shm_segsz;
+ linux_time_t shm_atime;
+ linux_time_t shm_dtime;
+ linux_time_t shm_ctime;
+ ushort shm_cpid;
+ ushort shm_lpid;
+ short shm_nattch;
+ ushort private1;
+ void *private2;
+ void *private3;
+};
+
+static void
+linux_to_bsd_semid_ds(struct linux_semid_ds *lsp, struct semid_ds *bsp)
+{
+ linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
+ bsp->sem_otime = lsp->sem_otime;
+ bsp->sem_ctime = lsp->sem_ctime;
+ bsp->sem_nsems = lsp->sem_nsems;
+ bsp->sem_base = lsp->sem_base;
+}
+
+static void
+bsd_to_linux_semid_ds(struct semid_ds *bsp, struct linux_semid_ds *lsp)
+{
+ bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
+ lsp->sem_otime = bsp->sem_otime;
+ lsp->sem_ctime = bsp->sem_ctime;
+ lsp->sem_nsems = bsp->sem_nsems;
+ lsp->sem_base = bsp->sem_base;
+}
+
+static void
+linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp)
+{
+ linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
+ bsp->shm_segsz = lsp->shm_segsz;
+ bsp->shm_lpid = lsp->shm_lpid;
+ bsp->shm_cpid = lsp->shm_cpid;
+ bsp->shm_nattch = lsp->shm_nattch;
+ bsp->shm_atime = lsp->shm_atime;
+ bsp->shm_dtime = lsp->shm_dtime;
+ bsp->shm_ctime = lsp->shm_ctime;
+ bsp->shm_internal = lsp->private3; /* this goes (yet) SOS */
+}
+
+static void
+bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp)
+{
+ bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
+ lsp->shm_segsz = bsp->shm_segsz;
+ lsp->shm_lpid = bsp->shm_lpid;
+ lsp->shm_cpid = bsp->shm_cpid;
+ lsp->shm_nattch = bsp->shm_nattch;
+ lsp->shm_atime = bsp->shm_atime;
+ lsp->shm_dtime = bsp->shm_dtime;
+ lsp->shm_ctime = bsp->shm_ctime;
+ lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */
+}
+
+int
+linux_semop(struct proc *p, struct linux_ipc_args *args)
+{
+ struct semop_args /* {
+ int semid;
+ struct sembuf *sops;
+ int nsops;
+ } */ bsd_args;
+
+ bsd_args.semid = args->arg1;
+ bsd_args.sops = (struct sembuf *)args->ptr;
+ bsd_args.nsops = args->arg2;
+ return semop(p, &bsd_args);
+}
+
+int
+linux_semget(struct proc *p, struct linux_ipc_args *args)
+{
+ struct semget_args /* {
+ key_t key;
+ int nsems;
+ int semflg;
+ } */ bsd_args;
+
+ bsd_args.key = args->arg1;
+ bsd_args.nsems = args->arg2;
+ bsd_args.semflg = args->arg3;
+ return semget(p, &bsd_args);
+}
+
+int
+linux_semctl(struct proc *p, struct linux_ipc_args *args)
+{
+ struct linux_semid_ds linux_semid;
+ struct semid_ds bsd_semid;
+ struct __semctl_args /* {
+ int semid;
+ int semnum;
+ int cmd;
+ union semun *arg;
+ } */ bsd_args;
+ int error;
+ caddr_t sg, unptr, dsp, ldsp;
+
+ sg = stackgap_init();
+ bsd_args.semid = args->arg1;
+ bsd_args.semnum = args->arg2;
+ bsd_args.cmd = args->arg3;
+ bsd_args.arg = (union semun *)args->ptr;
+
+ switch (args->arg3) {
+ case LINUX_IPC_RMID:
+ bsd_args.cmd = IPC_RMID;
+ break;
+ case LINUX_GETNCNT:
+ bsd_args.cmd = GETNCNT;
+ break;
+ case LINUX_GETPID:
+ bsd_args.cmd = GETPID;
+ break;
+ case LINUX_GETVAL:
+ bsd_args.cmd = GETVAL;
+ break;
+ case LINUX_GETZCNT:
+ bsd_args.cmd = GETZCNT;
+ break;
+ case LINUX_SETVAL:
+ bsd_args.cmd = SETVAL;
+ break;
+ case LINUX_IPC_SET:
+ bsd_args.cmd = IPC_SET;
+ error = copyin(args->ptr, &ldsp, sizeof(ldsp));
+ if (error)
+ return error;
+ error = copyin(ldsp, (caddr_t)&linux_semid, sizeof(linux_semid));
+ if (error)
+ return error;
+ linux_to_bsd_semid_ds(&linux_semid, &bsd_semid);
+ unptr = stackgap_alloc(&sg, sizeof(union semun));
+ dsp = stackgap_alloc(&sg, sizeof(struct semid_ds));
+ error = copyout((caddr_t)&bsd_semid, dsp, sizeof(bsd_semid));
+ if (error)
+ return error;
+ error = copyout((caddr_t)&dsp, unptr, sizeof(dsp));
+ if (error)
+ return error;
+ bsd_args.arg = (union semun *)unptr;
+ return __semctl(p, &bsd_args);
+ case LINUX_IPC_STAT:
+ bsd_args.cmd = IPC_STAT;
+ unptr = stackgap_alloc(&sg, sizeof(union semun *));
+ dsp = stackgap_alloc(&sg, sizeof(struct semid_ds));
+ error = copyout((caddr_t)&dsp, unptr, sizeof(dsp));
+ if (error)
+ return error;
+ bsd_args.arg = (union semun *)unptr;
+ error = __semctl(p, &bsd_args);
+ if (error)
+ return error;
+ error = copyin(dsp, (caddr_t)&bsd_semid, sizeof(bsd_semid));
+ if (error)
+ return error;
+ bsd_to_linux_semid_ds(&bsd_semid, &linux_semid);
+ error = copyin(args->ptr, &ldsp, sizeof(ldsp));
+ if (error)
+ return error;
+ return copyout((caddr_t)&linux_semid, ldsp, sizeof(linux_semid));
+ case LINUX_GETALL:
+ /* FALLTHROUGH */
+ case LINUX_SETALL:
+ /* FALLTHROUGH */
+ default:
+ uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
+ return EINVAL;
+ }
+ return __semctl(p, &bsd_args);
+}
+
+int
+linux_msgsnd(struct proc *p, struct linux_ipc_args *args)
+{
+ struct msgsnd_args /* {
+ int msqid;
+ void *msgp;
+ size_t msgsz;
+ int msgflg;
+ } */ bsd_args;
+
+ bsd_args.msqid = args->arg1;
+ bsd_args.msgp = args->ptr;
+ bsd_args.msgsz = args->arg2;
+ bsd_args.msgflg = args->arg3;
+ return msgsnd(p, &bsd_args);
+}
+
+int
+linux_msgrcv(struct proc *p, struct linux_ipc_args *args)
+{
+ struct msgrcv_args /* {
+ int msqid;
+ void *msgp;
+ size_t msgsz;
+ long msgtyp;
+ int msgflg;
+ } */ bsd_args;
+
+ bsd_args.msqid = args->arg1;
+ bsd_args.msgp = args->ptr;
+ bsd_args.msgsz = args->arg2;
+ bsd_args.msgtyp = 0;
+ bsd_args.msgflg = args->arg3;
+ return msgrcv(p, &bsd_args);
+}
+
+int
+linux_msgget(struct proc *p, struct linux_ipc_args *args)
+{
+ struct msgget_args /* {
+ key_t key;
+ int msgflg;
+ } */ bsd_args;
+
+ bsd_args.key = args->arg1;
+ bsd_args.msgflg = args->arg2;
+ return msgget(p, &bsd_args);
+}
+
+int
+linux_msgctl(struct proc *p, struct linux_ipc_args *args)
+{
+ struct msgctl_args /* {
+ int msqid;
+ int cmd;
+ struct msqid_ds *buf;
+ } */ bsd_args;
+ int error;
+
+ bsd_args.msqid = args->arg1;
+ bsd_args.cmd = args->arg2;
+ bsd_args.buf = (struct msqid_ds *)args->ptr;
+ error = msgctl(p, &bsd_args);
+ return ((args->arg2 == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
+}
+
+int
+linux_shmat(struct proc *p, struct linux_ipc_args *args)
+{
+ struct shmat_args /* {
+ int shmid;
+ void *shmaddr;
+ int shmflg;
+ } */ bsd_args;
+ int error;
+
+ bsd_args.shmid = args->arg1;
+ bsd_args.shmaddr = args->ptr;
+ bsd_args.shmflg = args->arg2;
+ if ((error = shmat(p, &bsd_args)))
+ return error;
+ if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int))))
+ return error;
+ p->p_retval[0] = 0;
+ return 0;
+}
+
+int
+linux_shmdt(struct proc *p, struct linux_ipc_args *args)
+{
+ struct shmdt_args /* {
+ void *shmaddr;
+ } */ bsd_args;
+
+ bsd_args.shmaddr = args->ptr;
+ return shmdt(p, &bsd_args);
+}
+
+int
+linux_shmget(struct proc *p, struct linux_ipc_args *args)
+{
+ struct shmget_args /* {
+ key_t key;
+ int size;
+ int shmflg;
+ } */ bsd_args;
+
+ bsd_args.key = args->arg1;
+ bsd_args.size = args->arg2;
+ bsd_args.shmflg = args->arg3;
+ return shmget(p, &bsd_args);
+}
+
+int
+linux_shmctl(struct proc *p, struct linux_ipc_args *args)
+{
+ struct shmid_ds bsd_shmid;
+ struct linux_shmid_ds linux_shmid;
+ struct shmctl_args /* {
+ int shmid;
+ int cmd;
+ struct shmid_ds *buf;
+ } */ bsd_args;
+ int error;
+ caddr_t sg = stackgap_init();
+
+ switch (args->arg2) {
+ case LINUX_IPC_STAT:
+ bsd_args.shmid = args->arg1;
+ bsd_args.cmd = IPC_STAT;
+ bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
+ if ((error = shmctl(p, &bsd_args)))
+ return error;
+ if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid,
+ sizeof(struct shmid_ds))))
+ return error;
+ bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
+ return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid));
+
+ case LINUX_IPC_SET:
+ if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
+ sizeof(linux_shmid))))
+ return error;
+ linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
+ bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
+ if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
+ sizeof(struct shmid_ds))))
+ return error;
+ bsd_args.shmid = args->arg1;
+ bsd_args.cmd = IPC_SET;
+ return shmctl(p, &bsd_args);
+
+ case LINUX_IPC_RMID:
+ bsd_args.shmid = args->arg1;
+ bsd_args.cmd = IPC_RMID;
+ if (NULL == args->ptr)
+ bsd_args.buf = NULL;
+ else {
+ if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
+ sizeof(linux_shmid))))
+ return error;
+ linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
+ bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
+ if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
+ sizeof(struct shmid_ds))))
+ return error;
+ }
+ return shmctl(p, &bsd_args);
+
+ case LINUX_IPC_INFO:
+ case LINUX_SHM_STAT:
+ case LINUX_SHM_INFO:
+ case LINUX_SHM_LOCK:
+ case LINUX_SHM_UNLOCK:
+ default:
+ uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
+ return EINVAL;
+ }
+}