Home | History | Annotate | Line # | Download | only in common
linux_ipc.c revision 1.15
      1 /*	$NetBSD: linux_ipc.c,v 1.15 1998/10/03 20:17:41 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Eric Haszlakiewicz.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the NetBSD
     21  *	Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 /*
     40  * Copyright (c) 1995 Frank van der Linden
     41  * All rights reserved.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  * 3. All advertising materials mentioning features or use of this software
     52  *    must display the following acknowledgement:
     53  *      This product includes software developed for the NetBSD Project
     54  *      by Frank van der Linden
     55  * 4. The name of the author may not be used to endorse or promote products
     56  *    derived from this software without specific prior written permission
     57  *
     58  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     59  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     60  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     61  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     62  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     63  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     64  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     65  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     66  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     67  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     68  */
     69 
     70 #include <sys/types.h>
     71 #include <sys/param.h>
     72 #include <sys/shm.h>
     73 #include <sys/sem.h>
     74 #include <sys/msg.h>
     75 #include <sys/proc.h>
     76 #include <sys/systm.h>
     77 
     78 #include <sys/mount.h>
     79 #include <sys/syscallargs.h>
     80 
     81 #include <compat/linux/common/linux_types.h>
     82 #include <compat/linux/common/linux_signal.h>
     83 #include <compat/linux/common/linux_util.h>
     84 
     85 #include <compat/linux/linux_syscallargs.h>
     86 #include <compat/linux/linux_syscall.h>
     87 
     88 #include <compat/linux/common/linux_ipc.h>
     89 #include <compat/linux/common/linux_msg.h>
     90 #include <compat/linux/common/linux_shm.h>
     91 #include <compat/linux/common/linux_sem.h>
     92 #include <compat/linux/common/linux_ipccall.h>
     93 
     94 /*
     95  * Note: Not all linux architechtures have explicit versions
     96  *	of the SYSV* syscalls.  On the ones that don't
     97  *	we pretend that they are defined anyway.  *_args and
     98  *	prototypes are defined in individual headers;
     99  *	syscalls.master lists those syscalls as NOARGS.
    100  *
    101  *	The functions in multiarch are the ones that just need
    102  *	the arguments shuffled around and then use the
    103  *	normal NetBSD syscall.
    104  *
    105  * Function in multiarch:
    106  *	linux_sys_ipc		: linux_ipccall.c
    107  *	liunx_semop		: linux_ipccall.c
    108  *	linux_semget		: linux_ipccall.c
    109  *	linux_msgsnd		: linux_ipccall.c
    110  *	linux_msgrcv		: linux_ipccall.c
    111  *	linux_msgget		: linux_ipccall.c
    112  *	linux_shmdt		: linux_ipccall.c
    113  *	linux_shmget		: linux_ipccall.c
    114  */
    115 
    116 #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG)
    117 /*
    118  * Convert between Linux and NetBSD ipc_perm structures. Only the
    119  * order of the fields is different.
    120  */
    121 void
    122 linux_to_bsd_ipc_perm(lpp, bpp)
    123 	struct linux_ipc_perm *lpp;
    124 	struct ipc_perm *bpp;
    125 {
    126 
    127 	bpp->key = lpp->l_key;
    128 	bpp->uid = lpp->l_uid;
    129 	bpp->gid = lpp->l_gid;
    130 	bpp->cuid = lpp->l_cuid;
    131 	bpp->cgid = lpp->l_cgid;
    132 	bpp->mode = lpp->l_mode;
    133 	bpp->seq = lpp->l_seq;
    134 }
    135 
    136 void
    137 bsd_to_linux_ipc_perm(bpp, lpp)
    138 	struct ipc_perm *bpp;
    139 	struct linux_ipc_perm *lpp;
    140 {
    141 
    142 	lpp->l_key = bpp->key;
    143 	lpp->l_uid = bpp->uid;
    144 	lpp->l_gid = bpp->gid;
    145 	lpp->l_cuid = bpp->cuid;
    146 	lpp->l_cgid = bpp->cgid;
    147 	lpp->l_mode = bpp->mode;
    148 	lpp->l_seq = bpp->seq;
    149 }
    150 #endif
    151 
    152 #ifdef SYSVSEM
    153 /*
    154  * Semaphore operations. Most constants and structures are the same on
    155  * both systems. Only semctl() needs some extra work.
    156  */
    157 
    158 /*
    159  * Convert between Linux and NetBSD semid_ds structures.
    160  */
    161 void
    162 bsd_to_linux_semid_ds(bs, ls)
    163 	struct semid_ds *bs;
    164 	struct linux_semid_ds *ls;
    165 {
    166 
    167 	bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm);
    168 	ls->l_sem_otime = bs->sem_otime;
    169 	ls->l_sem_ctime = bs->sem_ctime;
    170 	ls->l_sem_nsems = bs->sem_nsems;
    171 	ls->l_sem_base = bs->sem_base;
    172 }
    173 
    174 void
    175 linux_to_bsd_semid_ds(ls, bs)
    176 	struct linux_semid_ds *ls;
    177 	struct semid_ds *bs;
    178 {
    179 
    180 	linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm);
    181 	bs->sem_otime = ls->l_sem_otime;
    182 	bs->sem_ctime = ls->l_sem_ctime;
    183 	bs->sem_nsems = ls->l_sem_nsems;
    184 	bs->sem_base = ls->l_sem_base;
    185 }
    186 
    187 /*
    188  * Most of this can be handled by directly passing the arguments on,
    189  * but IPC_* require a lot of copy{in,out} because of the extra indirection
    190  * (we need to pass a pointer to a union cointaining a pointer to a semid_ds
    191  * structure.  Linux actually handles this better than we do.)
    192  */
    193 int
    194 linux_sys_semctl(p, v, retval)
    195 	struct proc *p;
    196 	void *v;
    197 	register_t *retval;
    198 {
    199 	struct linux_sys_semctl_args /* {
    200 		syscallarg(int) semid;
    201 		syscallarg(int) semnum;
    202 		syscallarg(int) cmd;
    203 		syscallarg(union linux_semun) arg;
    204 	} */ *uap = v;
    205 	caddr_t sg;
    206 	struct sys___semctl_args nua;
    207 	struct semid_ds *bmp, bm;
    208 	struct linux_semid_ds lm;
    209 	union semun *bup;
    210 	int error;
    211 
    212 	SCARG(&nua, semid) = SCARG(uap, semid);
    213 	SCARG(&nua, semnum) = SCARG(uap, semnum);
    214 	switch (SCARG(uap, cmd)) {
    215 	case LINUX_IPC_STAT:
    216 		sg = stackgap_init(p->p_emul);
    217 		bup = stackgap_alloc(&sg, sizeof (union semun));
    218 		bmp = stackgap_alloc(&sg, sizeof (struct semid_ds));
    219 		if ((error = copyout(&bmp, bup, sizeof bmp)))
    220 			return error;
    221 		SCARG(&nua, cmd) = IPC_STAT;
    222 		SCARG(&nua, arg) = bup;
    223 		if ((error = sys___semctl(p, &nua, retval)))
    224 			return error;
    225 		if ((error = copyin(bmp, &bm, sizeof bm)))
    226 			return error;
    227 		bsd_to_linux_semid_ds(&bm, &lm);
    228 		return copyout(&lm, SCARG(uap, arg).l_buf, sizeof lm);
    229 	case LINUX_IPC_SET:
    230 		if ((error = copyin(SCARG(uap, arg).l_buf, &lm, sizeof lm)))
    231 			return error;
    232 		linux_to_bsd_semid_ds(&lm, &bm);
    233 		sg = stackgap_init(p->p_emul);
    234 		bup = stackgap_alloc(&sg, sizeof (union semun));
    235 		bmp = stackgap_alloc(&sg, sizeof (struct semid_ds));
    236 		if ((error = copyout(&bm, bmp, sizeof bm)))
    237 			return error;
    238 		if ((error = copyout(&bmp, bup, sizeof bmp)))
    239 			return error;
    240 		SCARG(&nua, cmd) = IPC_SET;
    241 		SCARG(&nua, arg) = bup;
    242 		break;
    243 	case LINUX_IPC_RMID:
    244 		SCARG(&nua, cmd) = IPC_RMID;
    245 		break;
    246 	case LINUX_GETVAL:
    247 		SCARG(&nua, cmd) = GETVAL;
    248 		break;
    249 	case LINUX_GETPID:
    250 		SCARG(&nua, cmd) = GETPID;
    251 		break;
    252 	case LINUX_GETNCNT:
    253 		SCARG(&nua, cmd) = GETNCNT;
    254 		break;
    255 	case LINUX_GETZCNT:
    256 		SCARG(&nua, cmd) = GETZCNT;
    257 		break;
    258 	case LINUX_SETVAL:
    259 		SCARG(&nua, cmd) = SETVAL;
    260 		break;
    261 	default:
    262 		return EINVAL;
    263 	}
    264 	return sys___semctl(p, &nua, retval);
    265 }
    266 #endif /* SYSVSEM */
    267 
    268 #ifdef SYSVMSG
    269 
    270 void
    271 linux_to_bsd_msqid_ds(lmp, bmp)
    272 	struct linux_msqid_ds *lmp;
    273 	struct msqid_ds *bmp;
    274 {
    275 
    276 	linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm);
    277 	bmp->msg_first = lmp->l_msg_first;
    278 	bmp->msg_last = lmp->l_msg_last;
    279 	bmp->msg_cbytes = lmp->l_msg_cbytes;
    280 	bmp->msg_qnum = lmp->l_msg_qnum;
    281 	bmp->msg_qbytes = lmp->l_msg_qbytes;
    282 	bmp->msg_lspid = lmp->l_msg_lspid;
    283 	bmp->msg_lrpid = lmp->l_msg_lrpid;
    284 	bmp->msg_stime = lmp->l_msg_stime;
    285 	bmp->msg_rtime = lmp->l_msg_rtime;
    286 	bmp->msg_ctime = lmp->l_msg_ctime;
    287 }
    288 
    289 void
    290 bsd_to_linux_msqid_ds(bmp, lmp)
    291 	struct msqid_ds *bmp;
    292 	struct linux_msqid_ds *lmp;
    293 {
    294 
    295 	bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm);
    296 	lmp->l_msg_first = bmp->msg_first;
    297 	lmp->l_msg_last = bmp->msg_last;
    298 	lmp->l_msg_cbytes = bmp->msg_cbytes;
    299 	lmp->l_msg_qnum = bmp->msg_qnum;
    300 	lmp->l_msg_qbytes = bmp->msg_qbytes;
    301 	lmp->l_msg_lspid = bmp->msg_lspid;
    302 	lmp->l_msg_lrpid = bmp->msg_lrpid;
    303 	lmp->l_msg_stime = bmp->msg_stime;
    304 	lmp->l_msg_rtime = bmp->msg_rtime;
    305 	lmp->l_msg_ctime = bmp->msg_ctime;
    306 }
    307 
    308 int
    309 linux_sys_msgctl(p, v, retval)
    310 	struct proc *p;
    311 	void *v;
    312 	register_t *retval;
    313 {
    314 	struct linux_sys_msgctl_args /* {
    315 		syscallarg(int) msqid;
    316 		syscallarg(int) cmd;
    317 		syscallarg(struct linux_msqid_ds *) buf;
    318 	} */ *uap = v;
    319 	caddr_t sg;
    320 	struct sys_msgctl_args nua;
    321 	struct msqid_ds *bmp, bm;
    322 	struct linux_msqid_ds lm;
    323 	int error;
    324 
    325 	SCARG(&nua, msqid) = SCARG(uap, msqid);
    326 	switch (SCARG(uap, cmd)) {
    327 	case LINUX_IPC_STAT:
    328 		sg = stackgap_init(p->p_emul);
    329 		bmp = stackgap_alloc(&sg, sizeof (struct msqid_ds));
    330 		SCARG(&nua, cmd) = IPC_STAT;
    331 		SCARG(&nua, buf) = bmp;
    332 		if ((error = sys_msgctl(p, &nua, retval)))
    333 			return error;
    334 		if ((error = copyin(bmp, &bm, sizeof bm)))
    335 			return error;
    336 		bsd_to_linux_msqid_ds(&bm, &lm);
    337 		return copyout(&lm, SCARG(uap, buf), sizeof lm);
    338 	case LINUX_IPC_SET:
    339 		if ((error = copyin(SCARG(uap, buf), &lm, sizeof lm)))
    340 			return error;
    341 		linux_to_bsd_msqid_ds(&lm, &bm);
    342 		sg = stackgap_init(p->p_emul);
    343 		bmp = stackgap_alloc(&sg, sizeof bm);
    344 		if ((error = copyout(&bm, bmp, sizeof bm)))
    345 			return error;
    346 		SCARG(&nua, cmd) = IPC_SET;
    347 		SCARG(&nua, buf) = bmp;
    348 		break;
    349 	case LINUX_IPC_RMID:
    350 		SCARG(&nua, cmd) = IPC_RMID;
    351 		SCARG(&nua, buf) = NULL;
    352 		break;
    353 	default:
    354 		return EINVAL;
    355 	}
    356 	return sys_msgctl(p, &nua, retval);
    357 }
    358 #endif /* SYSVMSG */
    359 
    360 #ifdef SYSVSHM
    361 /*
    362  * shmat(2). Very straightforward, except that Linux passes a pointer
    363  * in which the return value is to be passed. This is subsequently
    364  * handled by libc, apparently.
    365  */
    366 int
    367 linux_sys_shmat(p, v, retval)
    368 	struct proc *p;
    369 	void *v;
    370 	register_t *retval;
    371 {
    372 	struct linux_sys_shmat_args /* {
    373 		syscallarg(int) shmid;
    374 		syscallarg(void *) shmaddr;
    375 		syscallarg(int) shmflg;
    376 		syscallarg(u_long *) raddr;
    377 	} */ *uap = v;
    378 	int error;
    379 
    380 	if ((error = sys_shmat(p, uap, retval)))
    381 		return error;
    382 
    383 	if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, raddr),
    384 	     sizeof retval[0])))
    385 		return error;
    386 
    387 	retval[0] = 0;
    388 	return 0;
    389 }
    390 
    391 /*
    392  * Convert between Linux and NetBSD shmid_ds structures.
    393  * The order of the fields is once again the difference, and
    394  * we also need a place to store the internal data pointer
    395  * in, which is unfortunately stored in this structure.
    396  *
    397  * We abuse a Linux internal field for that.
    398  */
    399 void
    400 linux_to_bsd_shmid_ds(lsp, bsp)
    401 	struct linux_shmid_ds *lsp;
    402 	struct shmid_ds *bsp;
    403 {
    404 
    405 	linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm);
    406 	bsp->shm_segsz = lsp->l_shm_segsz;
    407 	bsp->shm_lpid = lsp->l_shm_lpid;
    408 	bsp->shm_cpid = lsp->l_shm_cpid;
    409 	bsp->shm_nattch = lsp->l_shm_nattch;
    410 	bsp->shm_atime = lsp->l_shm_atime;
    411 	bsp->shm_dtime = lsp->l_shm_dtime;
    412 	bsp->shm_ctime = lsp->l_shm_ctime;
    413 	bsp->shm_internal = lsp->l_private2;	/* XXX Oh well. */
    414 }
    415 
    416 void
    417 bsd_to_linux_shmid_ds(bsp, lsp)
    418 	struct shmid_ds *bsp;
    419 	struct linux_shmid_ds *lsp;
    420 {
    421 
    422 	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm);
    423 	lsp->l_shm_segsz = bsp->shm_segsz;
    424 	lsp->l_shm_lpid = bsp->shm_lpid;
    425 	lsp->l_shm_cpid = bsp->shm_cpid;
    426 	lsp->l_shm_nattch = bsp->shm_nattch;
    427 	lsp->l_shm_atime = bsp->shm_atime;
    428 	lsp->l_shm_dtime = bsp->shm_dtime;
    429 	lsp->l_shm_ctime = bsp->shm_ctime;
    430 	lsp->l_private2 = bsp->shm_internal;	/* XXX */
    431 }
    432 
    433 /*
    434  * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT
    435  * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented
    436  * by NetBSD itself.
    437  *
    438  * The usual structure conversion and massaging is done.
    439  */
    440 int
    441 linux_sys_shmctl(p, v, retval)
    442 	struct proc *p;
    443 	void *v;
    444 	register_t *retval;
    445 {
    446 	struct linux_sys_shmctl_args /* {
    447 		syscallarg(int) shmid;
    448 		syscallarg(int) cmd;
    449 		syscallarg(struct linux_shmid_ds *) buf;
    450 	} */ *uap = v;
    451 	caddr_t sg;
    452 	struct sys_shmctl_args nua;
    453 	struct shmid_ds *bsp, bs;
    454 	struct linux_shmid_ds ls;
    455 	int error;
    456 
    457 	SCARG(&nua, shmid) = SCARG(uap, shmid);
    458 	switch (SCARG(uap, cmd)) {
    459 	case LINUX_IPC_STAT:
    460 		sg = stackgap_init(p->p_emul);
    461 		bsp = stackgap_alloc(&sg, sizeof(struct shmid_ds));
    462 		SCARG(&nua, cmd) = IPC_STAT;
    463 		SCARG(&nua, buf) = bsp;
    464 		if ((error = sys_shmctl(p, &nua, retval)))
    465 			return error;
    466 		if ((error = copyin(SCARG(&nua, buf), &bs, sizeof bs)))
    467 			return error;
    468 		bsd_to_linux_shmid_ds(&bs, &ls);
    469 		return copyout(&ls, SCARG(uap, buf), sizeof ls);
    470 	case LINUX_IPC_SET:
    471 		if ((error = copyin(SCARG(uap, buf), &ls, sizeof ls)))
    472 			return error;
    473 		linux_to_bsd_shmid_ds(&ls, &bs);
    474 		sg = stackgap_init(p->p_emul);
    475 		bsp = stackgap_alloc(&sg, sizeof bs);
    476 		if ((error = copyout(&bs, bsp, sizeof bs)))
    477 			return error;
    478 		SCARG(&nua, cmd) = IPC_SET;
    479 		SCARG(&nua, buf) = bsp;
    480 		break;
    481 	case LINUX_IPC_RMID:
    482 		SCARG(&nua, cmd) = IPC_RMID;
    483 		SCARG(&nua, buf) = NULL;
    484 		break;
    485 	case LINUX_SHM_LOCK:
    486 		SCARG(&nua, cmd) = SHM_LOCK;
    487 		SCARG(&nua, buf) = NULL;
    488 		break;
    489 	case LINUX_SHM_UNLOCK:
    490 		SCARG(&nua, cmd) = SHM_UNLOCK;
    491 		SCARG(&nua, buf) = NULL;
    492 		break;
    493 	case LINUX_IPC_INFO:
    494 	case LINUX_SHM_STAT:
    495 	case LINUX_SHM_INFO:
    496 	default:
    497 		return EINVAL;
    498 	}
    499 	return sys_shmctl(p, &nua, retval);
    500 }
    501 #endif /* SYSVSHM */
    502