Home | History | Annotate | Line # | Download | only in common
linux_ipc.c revision 1.14
      1 /*	$NetBSD: linux_ipc.c,v 1.14 1998/10/01 03:27:38 erh 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/linux_types.h>
     82 #include <compat/linux/linux_signal.h>
     83 #include <compat/linux/linux_syscallargs.h>
     84 #include <compat/linux/linux_syscall.h>
     85 #include <compat/linux/linux_util.h>
     86 #include <compat/linux/linux_ipc.h>
     87 #include <compat/linux/linux_msg.h>
     88 #include <compat/linux/linux_shm.h>
     89 #include <compat/linux/linux_sem.h>
     90 #include <compat/linux/linux_ipccall.h>
     91 
     92 /*
     93  * Note: Not all linux architechtures have explicit versions
     94  *	of the SYSV* syscalls.  On the ones that don't
     95  *	we pretend that they are defined anyway.  *_args and
     96  *	prototypes are defined in individual headers;
     97  *	syscalls.master lists those syscalls as NOARGS.
     98  *
     99  *	The functions in multiarch are the ones that just need
    100  *	the arguments shuffled around and then use the
    101  *	normal NetBSD syscall.
    102  *
    103  * Function in multiarch:
    104  *	linux_sys_ipc		: linux_ipccall.c
    105  *	liunx_semop		: linux_ipccall.c
    106  *	linux_semget		: linux_ipccall.c
    107  *	linux_msgsnd		: linux_ipccall.c
    108  *	linux_msgrcv		: linux_ipccall.c
    109  *	linux_msgget		: linux_ipccall.c
    110  *	linux_shmdt		: linux_ipccall.c
    111  *	linux_shmget		: linux_ipccall.c
    112  */
    113 
    114 #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG)
    115 /*
    116  * Convert between Linux and NetBSD ipc_perm structures. Only the
    117  * order of the fields is different.
    118  */
    119 void
    120 linux_to_bsd_ipc_perm(lpp, bpp)
    121 	struct linux_ipc_perm *lpp;
    122 	struct ipc_perm *bpp;
    123 {
    124 
    125 	bpp->key = lpp->l_key;
    126 	bpp->uid = lpp->l_uid;
    127 	bpp->gid = lpp->l_gid;
    128 	bpp->cuid = lpp->l_cuid;
    129 	bpp->cgid = lpp->l_cgid;
    130 	bpp->mode = lpp->l_mode;
    131 	bpp->seq = lpp->l_seq;
    132 }
    133 
    134 void
    135 bsd_to_linux_ipc_perm(bpp, lpp)
    136 	struct ipc_perm *bpp;
    137 	struct linux_ipc_perm *lpp;
    138 {
    139 
    140 	lpp->l_key = bpp->key;
    141 	lpp->l_uid = bpp->uid;
    142 	lpp->l_gid = bpp->gid;
    143 	lpp->l_cuid = bpp->cuid;
    144 	lpp->l_cgid = bpp->cgid;
    145 	lpp->l_mode = bpp->mode;
    146 	lpp->l_seq = bpp->seq;
    147 }
    148 #endif
    149 
    150 #ifdef SYSVSEM
    151 /*
    152  * Semaphore operations. Most constants and structures are the same on
    153  * both systems. Only semctl() needs some extra work.
    154  */
    155 
    156 /*
    157  * Convert between Linux and NetBSD semid_ds structures.
    158  */
    159 void
    160 bsd_to_linux_semid_ds(bs, ls)
    161 	struct semid_ds *bs;
    162 	struct linux_semid_ds *ls;
    163 {
    164 
    165 	bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm);
    166 	ls->l_sem_otime = bs->sem_otime;
    167 	ls->l_sem_ctime = bs->sem_ctime;
    168 	ls->l_sem_nsems = bs->sem_nsems;
    169 	ls->l_sem_base = bs->sem_base;
    170 }
    171 
    172 void
    173 linux_to_bsd_semid_ds(ls, bs)
    174 	struct linux_semid_ds *ls;
    175 	struct semid_ds *bs;
    176 {
    177 
    178 	linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm);
    179 	bs->sem_otime = ls->l_sem_otime;
    180 	bs->sem_ctime = ls->l_sem_ctime;
    181 	bs->sem_nsems = ls->l_sem_nsems;
    182 	bs->sem_base = ls->l_sem_base;
    183 }
    184 
    185 /*
    186  * Most of this can be handled by directly passing the arguments on,
    187  * but IPC_* require a lot of copy{in,out} because of the extra indirection
    188  * (we need to pass a pointer to a union cointaining a pointer to a semid_ds
    189  * structure.  Linux actually handles this better than we do.)
    190  */
    191 int
    192 linux_sys_semctl(p, v, retval)
    193 	struct proc *p;
    194 	void *v;
    195 	register_t *retval;
    196 {
    197 	struct linux_sys_semctl_args /* {
    198 		syscallarg(int) semid;
    199 		syscallarg(int) semnum;
    200 		syscallarg(int) cmd;
    201 		syscallarg(union linux_semun) arg;
    202 	} */ *uap = v;
    203 	caddr_t sg;
    204 	struct sys___semctl_args nua;
    205 	struct semid_ds *bmp, bm;
    206 	struct linux_semid_ds lm;
    207 	union semun *bup;
    208 	int error;
    209 
    210 	SCARG(&nua, semid) = SCARG(uap, semid);
    211 	SCARG(&nua, semnum) = SCARG(uap, semnum);
    212 	switch (SCARG(uap, cmd)) {
    213 	case LINUX_IPC_STAT:
    214 		sg = stackgap_init(p->p_emul);
    215 		bup = stackgap_alloc(&sg, sizeof (union semun));
    216 		bmp = stackgap_alloc(&sg, sizeof (struct semid_ds));
    217 		if ((error = copyout(&bmp, bup, sizeof bmp)))
    218 			return error;
    219 		SCARG(&nua, cmd) = IPC_STAT;
    220 		SCARG(&nua, arg) = bup;
    221 		if ((error = sys___semctl(p, &nua, retval)))
    222 			return error;
    223 		if ((error = copyin(bmp, &bm, sizeof bm)))
    224 			return error;
    225 		bsd_to_linux_semid_ds(&bm, &lm);
    226 		return copyout(&lm, SCARG(uap, arg).l_buf, sizeof lm);
    227 	case LINUX_IPC_SET:
    228 		if ((error = copyin(SCARG(uap, arg).l_buf, &lm, sizeof lm)))
    229 			return error;
    230 		linux_to_bsd_semid_ds(&lm, &bm);
    231 		sg = stackgap_init(p->p_emul);
    232 		bup = stackgap_alloc(&sg, sizeof (union semun));
    233 		bmp = stackgap_alloc(&sg, sizeof (struct semid_ds));
    234 		if ((error = copyout(&bm, bmp, sizeof bm)))
    235 			return error;
    236 		if ((error = copyout(&bmp, bup, sizeof bmp)))
    237 			return error;
    238 		SCARG(&nua, cmd) = IPC_SET;
    239 		SCARG(&nua, arg) = bup;
    240 		break;
    241 	case LINUX_IPC_RMID:
    242 		SCARG(&nua, cmd) = IPC_RMID;
    243 		break;
    244 	case LINUX_GETVAL:
    245 		SCARG(&nua, cmd) = GETVAL;
    246 		break;
    247 	case LINUX_GETPID:
    248 		SCARG(&nua, cmd) = GETPID;
    249 		break;
    250 	case LINUX_GETNCNT:
    251 		SCARG(&nua, cmd) = GETNCNT;
    252 		break;
    253 	case LINUX_GETZCNT:
    254 		SCARG(&nua, cmd) = GETZCNT;
    255 		break;
    256 	case LINUX_SETVAL:
    257 		SCARG(&nua, cmd) = SETVAL;
    258 		break;
    259 	default:
    260 		return EINVAL;
    261 	}
    262 	return sys___semctl(p, &nua, retval);
    263 }
    264 #endif /* SYSVSEM */
    265 
    266 #ifdef SYSVMSG
    267 
    268 void
    269 linux_to_bsd_msqid_ds(lmp, bmp)
    270 	struct linux_msqid_ds *lmp;
    271 	struct msqid_ds *bmp;
    272 {
    273 
    274 	linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm);
    275 	bmp->msg_first = lmp->l_msg_first;
    276 	bmp->msg_last = lmp->l_msg_last;
    277 	bmp->msg_cbytes = lmp->l_msg_cbytes;
    278 	bmp->msg_qnum = lmp->l_msg_qnum;
    279 	bmp->msg_qbytes = lmp->l_msg_qbytes;
    280 	bmp->msg_lspid = lmp->l_msg_lspid;
    281 	bmp->msg_lrpid = lmp->l_msg_lrpid;
    282 	bmp->msg_stime = lmp->l_msg_stime;
    283 	bmp->msg_rtime = lmp->l_msg_rtime;
    284 	bmp->msg_ctime = lmp->l_msg_ctime;
    285 }
    286 
    287 void
    288 bsd_to_linux_msqid_ds(bmp, lmp)
    289 	struct msqid_ds *bmp;
    290 	struct linux_msqid_ds *lmp;
    291 {
    292 
    293 	bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm);
    294 	lmp->l_msg_first = bmp->msg_first;
    295 	lmp->l_msg_last = bmp->msg_last;
    296 	lmp->l_msg_cbytes = bmp->msg_cbytes;
    297 	lmp->l_msg_qnum = bmp->msg_qnum;
    298 	lmp->l_msg_qbytes = bmp->msg_qbytes;
    299 	lmp->l_msg_lspid = bmp->msg_lspid;
    300 	lmp->l_msg_lrpid = bmp->msg_lrpid;
    301 	lmp->l_msg_stime = bmp->msg_stime;
    302 	lmp->l_msg_rtime = bmp->msg_rtime;
    303 	lmp->l_msg_ctime = bmp->msg_ctime;
    304 }
    305 
    306 int
    307 linux_sys_msgctl(p, v, retval)
    308 	struct proc *p;
    309 	void *v;
    310 	register_t *retval;
    311 {
    312 	struct linux_sys_msgctl_args /* {
    313 		syscallarg(int) msqid;
    314 		syscallarg(int) cmd;
    315 		syscallarg(struct linux_msqid_ds *) buf;
    316 	} */ *uap = v;
    317 	caddr_t sg;
    318 	struct sys_msgctl_args nua;
    319 	struct msqid_ds *bmp, bm;
    320 	struct linux_msqid_ds lm;
    321 	int error;
    322 
    323 	SCARG(&nua, msqid) = SCARG(uap, msqid);
    324 	switch (SCARG(uap, cmd)) {
    325 	case LINUX_IPC_STAT:
    326 		sg = stackgap_init(p->p_emul);
    327 		bmp = stackgap_alloc(&sg, sizeof (struct msqid_ds));
    328 		SCARG(&nua, cmd) = IPC_STAT;
    329 		SCARG(&nua, buf) = bmp;
    330 		if ((error = sys_msgctl(p, &nua, retval)))
    331 			return error;
    332 		if ((error = copyin(bmp, &bm, sizeof bm)))
    333 			return error;
    334 		bsd_to_linux_msqid_ds(&bm, &lm);
    335 		return copyout(&lm, SCARG(uap, buf), sizeof lm);
    336 	case LINUX_IPC_SET:
    337 		if ((error = copyin(SCARG(uap, buf), &lm, sizeof lm)))
    338 			return error;
    339 		linux_to_bsd_msqid_ds(&lm, &bm);
    340 		sg = stackgap_init(p->p_emul);
    341 		bmp = stackgap_alloc(&sg, sizeof bm);
    342 		if ((error = copyout(&bm, bmp, sizeof bm)))
    343 			return error;
    344 		SCARG(&nua, cmd) = IPC_SET;
    345 		SCARG(&nua, buf) = bmp;
    346 		break;
    347 	case LINUX_IPC_RMID:
    348 		SCARG(&nua, cmd) = IPC_RMID;
    349 		SCARG(&nua, buf) = NULL;
    350 		break;
    351 	default:
    352 		return EINVAL;
    353 	}
    354 	return sys_msgctl(p, &nua, retval);
    355 }
    356 #endif /* SYSVMSG */
    357 
    358 #ifdef SYSVSHM
    359 /*
    360  * shmat(2). Very straightforward, except that Linux passes a pointer
    361  * in which the return value is to be passed. This is subsequently
    362  * handled by libc, apparently.
    363  */
    364 int
    365 linux_sys_shmat(p, v, retval)
    366 	struct proc *p;
    367 	void *v;
    368 	register_t *retval;
    369 {
    370 	struct linux_sys_shmat_args /* {
    371 		syscallarg(int) shmid;
    372 		syscallarg(void *) shmaddr;
    373 		syscallarg(int) shmflg;
    374 		syscallarg(u_long *) raddr;
    375 	} */ *uap = v;
    376 	int error;
    377 
    378 	if ((error = sys_shmat(p, uap, retval)))
    379 		return error;
    380 
    381 	if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, raddr),
    382 	     sizeof retval[0])))
    383 		return error;
    384 
    385 	retval[0] = 0;
    386 	return 0;
    387 }
    388 
    389 /*
    390  * Convert between Linux and NetBSD shmid_ds structures.
    391  * The order of the fields is once again the difference, and
    392  * we also need a place to store the internal data pointer
    393  * in, which is unfortunately stored in this structure.
    394  *
    395  * We abuse a Linux internal field for that.
    396  */
    397 void
    398 linux_to_bsd_shmid_ds(lsp, bsp)
    399 	struct linux_shmid_ds *lsp;
    400 	struct shmid_ds *bsp;
    401 {
    402 
    403 	linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm);
    404 	bsp->shm_segsz = lsp->l_shm_segsz;
    405 	bsp->shm_lpid = lsp->l_shm_lpid;
    406 	bsp->shm_cpid = lsp->l_shm_cpid;
    407 	bsp->shm_nattch = lsp->l_shm_nattch;
    408 	bsp->shm_atime = lsp->l_shm_atime;
    409 	bsp->shm_dtime = lsp->l_shm_dtime;
    410 	bsp->shm_ctime = lsp->l_shm_ctime;
    411 	bsp->shm_internal = lsp->l_private2;	/* XXX Oh well. */
    412 }
    413 
    414 void
    415 bsd_to_linux_shmid_ds(bsp, lsp)
    416 	struct shmid_ds *bsp;
    417 	struct linux_shmid_ds *lsp;
    418 {
    419 
    420 	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm);
    421 	lsp->l_shm_segsz = bsp->shm_segsz;
    422 	lsp->l_shm_lpid = bsp->shm_lpid;
    423 	lsp->l_shm_cpid = bsp->shm_cpid;
    424 	lsp->l_shm_nattch = bsp->shm_nattch;
    425 	lsp->l_shm_atime = bsp->shm_atime;
    426 	lsp->l_shm_dtime = bsp->shm_dtime;
    427 	lsp->l_shm_ctime = bsp->shm_ctime;
    428 	lsp->l_private2 = bsp->shm_internal;	/* XXX */
    429 }
    430 
    431 /*
    432  * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT
    433  * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented
    434  * by NetBSD itself.
    435  *
    436  * The usual structure conversion and massaging is done.
    437  */
    438 int
    439 linux_sys_shmctl(p, v, retval)
    440 	struct proc *p;
    441 	void *v;
    442 	register_t *retval;
    443 {
    444 	struct linux_sys_shmctl_args /* {
    445 		syscallarg(int) shmid;
    446 		syscallarg(int) cmd;
    447 		syscallarg(struct linux_shmid_ds *) buf;
    448 	} */ *uap = v;
    449 	caddr_t sg;
    450 	struct sys_shmctl_args nua;
    451 	struct shmid_ds *bsp, bs;
    452 	struct linux_shmid_ds ls;
    453 	int error;
    454 
    455 	SCARG(&nua, shmid) = SCARG(uap, shmid);
    456 	switch (SCARG(uap, cmd)) {
    457 	case LINUX_IPC_STAT:
    458 		sg = stackgap_init(p->p_emul);
    459 		bsp = stackgap_alloc(&sg, sizeof(struct shmid_ds));
    460 		SCARG(&nua, cmd) = IPC_STAT;
    461 		SCARG(&nua, buf) = bsp;
    462 		if ((error = sys_shmctl(p, &nua, retval)))
    463 			return error;
    464 		if ((error = copyin(SCARG(&nua, buf), &bs, sizeof bs)))
    465 			return error;
    466 		bsd_to_linux_shmid_ds(&bs, &ls);
    467 		return copyout(&ls, SCARG(uap, buf), sizeof ls);
    468 	case LINUX_IPC_SET:
    469 		if ((error = copyin(SCARG(uap, buf), &ls, sizeof ls)))
    470 			return error;
    471 		linux_to_bsd_shmid_ds(&ls, &bs);
    472 		sg = stackgap_init(p->p_emul);
    473 		bsp = stackgap_alloc(&sg, sizeof bs);
    474 		if ((error = copyout(&bs, bsp, sizeof bs)))
    475 			return error;
    476 		SCARG(&nua, cmd) = IPC_SET;
    477 		SCARG(&nua, buf) = bsp;
    478 		break;
    479 	case LINUX_IPC_RMID:
    480 		SCARG(&nua, cmd) = IPC_RMID;
    481 		SCARG(&nua, buf) = NULL;
    482 		break;
    483 	case LINUX_SHM_LOCK:
    484 		SCARG(&nua, cmd) = SHM_LOCK;
    485 		SCARG(&nua, buf) = NULL;
    486 		break;
    487 	case LINUX_SHM_UNLOCK:
    488 		SCARG(&nua, cmd) = SHM_UNLOCK;
    489 		SCARG(&nua, buf) = NULL;
    490 		break;
    491 	case LINUX_IPC_INFO:
    492 	case LINUX_SHM_STAT:
    493 	case LINUX_SHM_INFO:
    494 	default:
    495 		return EINVAL;
    496 	}
    497 	return sys_shmctl(p, &nua, retval);
    498 }
    499 #endif /* SYSVSHM */
    500