Home | History | Annotate | Line # | Download | only in common
linux_ipc.c revision 1.10
      1 /*	$NetBSD: linux_ipc.c,v 1.10 1996/04/05 00:01:44 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Frank van der Linden
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *      This product includes software developed for the NetBSD Project
     18  *      by Frank van der Linden
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/types.h>
     35 #include <sys/param.h>
     36 #include <sys/kernel.h>
     37 #include <sys/shm.h>
     38 #include <sys/sem.h>
     39 #include <sys/msg.h>
     40 #include <sys/proc.h>
     41 #include <sys/uio.h>
     42 #include <sys/time.h>
     43 #include <sys/malloc.h>
     44 #include <sys/mman.h>
     45 #include <sys/systm.h>
     46 #include <sys/stat.h>
     47 
     48 #include <sys/mount.h>
     49 #include <sys/syscallargs.h>
     50 
     51 #include <compat/linux/linux_types.h>
     52 #include <compat/linux/linux_signal.h>
     53 #include <compat/linux/linux_syscallargs.h>
     54 #include <compat/linux/linux_util.h>
     55 #include <compat/linux/linux_ipc.h>
     56 #include <compat/linux/linux_msg.h>
     57 #include <compat/linux/linux_shm.h>
     58 #include <compat/linux/linux_sem.h>
     59 #include <compat/linux/linux_ipccall.h>
     60 
     61 /*
     62  * Stuff to deal with the SysV ipc/shm/semaphore interface in Linux.
     63  * The main difference is, that Linux handles it all via one
     64  * system call, which has the usual maximum amount of 5 arguments.
     65  * This results in a kludge for calls that take 6 of them.
     66  *
     67  * The SYSVXXXX options have to be enabled to get the appropriate
     68  * functions to work.
     69  */
     70 
     71 #ifdef SYSVSEM
     72 static int linux_semop __P((struct proc *, struct linux_sys_ipc_args *,
     73 				register_t *));
     74 static int linux_semget __P((struct proc *, struct linux_sys_ipc_args *,
     75 				register_t *));
     76 static int linux_semctl __P((struct proc *, struct linux_sys_ipc_args *,
     77 				register_t *));
     78 static void bsd_to_linux_semid_ds __P((struct semid_ds *,
     79 				       struct linux_semid_ds *));
     80 static void linux_to_bsd_semid_ds __P((struct linux_semid_ds *,
     81 				       struct semid_ds *));
     82 #endif
     83 
     84 #ifdef SYSVMSG
     85 static int linux_msgsnd __P((struct proc *, struct linux_sys_ipc_args *,
     86 				register_t *));
     87 static int linux_msgrcv __P((struct proc *, struct linux_sys_ipc_args *,
     88 				register_t *));
     89 static int linux_msgget __P((struct proc *, struct linux_sys_ipc_args *,
     90 				register_t *));
     91 static int linux_msgctl __P((struct proc *, struct linux_sys_ipc_args *,
     92 				register_t *));
     93 static void linux_to_bsd_msqid_ds __P((struct linux_msqid_ds *,
     94 				       struct msqid_ds *));
     95 static void bsd_to_linux_msqid_ds __P((struct msqid_ds *,
     96 				       struct linux_msqid_ds *));
     97 #endif
     98 
     99 #ifdef SYSVSHM
    100 static int linux_shmat __P((struct proc *, struct linux_sys_ipc_args *,
    101 				register_t *));
    102 static int linux_shmdt __P((struct proc *, struct linux_sys_ipc_args *,
    103 				register_t *));
    104 static int linux_shmget __P((struct proc *, struct linux_sys_ipc_args *,
    105 				register_t *));
    106 static int linux_shmctl __P((struct proc *, struct linux_sys_ipc_args *,
    107 				register_t *));
    108 static void linux_to_bsd_shmid_ds __P((struct linux_shmid_ds *,
    109 				       struct shmid_ds *));
    110 static void bsd_to_linux_shmid_ds __P((struct shmid_ds *,
    111 				       struct linux_shmid_ds *));
    112 #endif
    113 
    114 
    115 static void linux_to_bsd_ipc_perm __P((struct linux_ipc_perm *,
    116 				       struct ipc_perm *));
    117 static void bsd_to_linux_ipc_perm __P((struct ipc_perm *,
    118 				       struct linux_ipc_perm *));
    119 
    120 int
    121 linux_sys_ipc(p, v, retval)
    122 	struct proc *p;
    123 	void *v;
    124 	register_t *retval;
    125 {
    126 	struct linux_sys_ipc_args /* {
    127 		syscallarg(int) what;
    128 		syscallarg(int) a1;
    129 		syscallarg(int) a2;
    130 		syscallarg(int) a3;
    131 		syscallarg(caddr_t) ptr;
    132 	} */ *uap = v;
    133 
    134 	switch (SCARG(uap, what)) {
    135 #ifdef SYSVSEM
    136 	case LINUX_SYS_semop:
    137 		return linux_semop(p, uap, retval);
    138 	case LINUX_SYS_semget:
    139 		return linux_semget(p, uap, retval);
    140 	case LINUX_SYS_semctl:
    141 		return linux_semctl(p, uap, retval);
    142 #endif
    143 #ifdef SYSVMSG
    144 	case LINUX_SYS_msgsnd:
    145 		return linux_msgsnd(p, uap, retval);
    146 	case LINUX_SYS_msgrcv:
    147 		return linux_msgrcv(p, uap, retval);
    148 	case LINUX_SYS_msgget:
    149 		return linux_msgget(p, uap, retval);
    150 	case LINUX_SYS_msgctl:
    151 		return linux_msgctl(p, uap, retval);
    152 #endif
    153 #ifdef SYSVSHM
    154 	case LINUX_SYS_shmat:
    155 		return linux_shmat(p, uap, retval);
    156 	case LINUX_SYS_shmdt:
    157 		return linux_shmdt(p, uap, retval);
    158 	case LINUX_SYS_shmget:
    159 		return linux_shmget(p, uap, retval);
    160 	case LINUX_SYS_shmctl:
    161 		return linux_shmctl(p, uap, retval);
    162 #endif
    163 	default:
    164 		return ENOSYS;
    165 	}
    166 }
    167 
    168 /*
    169  * Convert between Linux and NetBSD ipc_perm structures. Only the
    170  * order of the fields is different.
    171  */
    172 static void
    173 linux_to_bsd_ipc_perm(lpp, bpp)
    174 	struct linux_ipc_perm *lpp;
    175 	struct ipc_perm *bpp;
    176 {
    177 
    178 	bpp->key = lpp->l_key;
    179 	bpp->uid = lpp->l_uid;
    180 	bpp->gid = lpp->l_gid;
    181 	bpp->cuid = lpp->l_cuid;
    182 	bpp->cgid = lpp->l_cgid;
    183 	bpp->mode = lpp->l_mode;
    184 	bpp->seq = lpp->l_seq;
    185 }
    186 
    187 static void
    188 bsd_to_linux_ipc_perm(bpp, lpp)
    189 	struct ipc_perm *bpp;
    190 	struct linux_ipc_perm *lpp;
    191 {
    192 
    193 	lpp->l_key = bpp->key;
    194 	lpp->l_uid = bpp->uid;
    195 	lpp->l_gid = bpp->gid;
    196 	lpp->l_cuid = bpp->cuid;
    197 	lpp->l_cgid = bpp->cgid;
    198 	lpp->l_mode = bpp->mode;
    199 	lpp->l_seq = bpp->seq;
    200 }
    201 
    202 #ifdef SYSVSEM
    203 /*
    204  * Semaphore operations. Most constants and structures are the same on
    205  * both systems. Only semctl() needs some extra work.
    206  */
    207 
    208 /*
    209  * Convert between Linux and NetBSD semid_ds structures.
    210  */
    211 static void
    212 bsd_to_linux_semid_ds(bs, ls)
    213 	struct semid_ds *bs;
    214 	struct linux_semid_ds *ls;
    215 {
    216 
    217 	bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm);
    218 	ls->l_sem_otime = bs->sem_otime;
    219 	ls->l_sem_ctime = bs->sem_ctime;
    220 	ls->l_sem_nsems = bs->sem_nsems;
    221 	ls->l_sem_base = bs->sem_base;
    222 }
    223 
    224 static void
    225 linux_to_bsd_semid_ds(ls, bs)
    226 	struct linux_semid_ds *ls;
    227 	struct semid_ds *bs;
    228 {
    229 
    230 	linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm);
    231 	bs->sem_otime = ls->l_sem_otime;
    232 	bs->sem_ctime = ls->l_sem_ctime;
    233 	bs->sem_nsems = ls->l_sem_nsems;
    234 	bs->sem_base = ls->l_sem_base;
    235 }
    236 
    237 int
    238 linux_semop(p, uap, retval)
    239 	struct proc *p;
    240 	struct linux_sys_ipc_args /* {
    241 		syscallarg(int) what;
    242 		syscallarg(int) a1;
    243 		syscallarg(int) a2;
    244 		syscallarg(int) a3;
    245 		syscallarg(caddr_t) ptr;
    246 	} */ *uap;
    247 	register_t *retval;
    248 {
    249 	struct sys_semop_args bsa;
    250 
    251 	SCARG(&bsa, semid) = SCARG(uap, a1);
    252 	SCARG(&bsa, sops) = (struct sembuf *)SCARG(uap, ptr);
    253 	SCARG(&bsa, nsops) = SCARG(uap, a2);
    254 
    255 	return sys_semop(p, &bsa, retval);
    256 }
    257 
    258 int
    259 linux_semget(p, uap, retval)
    260 	struct proc *p;
    261 	struct linux_sys_ipc_args /* {
    262 		syscallarg(int) what;
    263 		syscallarg(int) a1;
    264 		syscallarg(int) a2;
    265 		syscallarg(int) a3;
    266 		syscallarg(caddr_t) ptr;
    267 	} */ *uap;
    268 	register_t *retval;
    269 {
    270 	struct sys_semget_args bsa;
    271 
    272 	SCARG(&bsa, key) = (key_t)SCARG(uap, a1);
    273 	SCARG(&bsa, nsems) = SCARG(uap, a2);
    274 	SCARG(&bsa, semflg) = SCARG(uap, a3);
    275 
    276 	return sys_semget(p, &bsa, retval);
    277 }
    278 
    279 /*
    280  * Most of this can be handled by directly passing the arguments on,
    281  * buf IPC_* require a lot of copy{in,out} because of the extra indirection
    282  * (we are passed a pointer to a union cointaining a pointer to a semid_ds
    283  * structure.
    284  */
    285 int
    286 linux_semctl(p, uap, retval)
    287 	struct proc *p;
    288 	struct linux_sys_ipc_args /* {
    289 		syscallarg(int) what;
    290 		syscallarg(int) a1;
    291 		syscallarg(int) a2;
    292 		syscallarg(int) a3;
    293 		syscallarg(caddr_t) ptr;
    294 	} */ *uap;
    295 	register_t *retval;
    296 {
    297 	caddr_t sg, unptr, dsp, ldsp;
    298 	int error, cmd;
    299 	struct sys___semctl_args bsa;
    300 	struct linux_semid_ds lm;
    301 	struct semid_ds bm;
    302 
    303 	SCARG(&bsa, semid) = SCARG(uap, a1);
    304 	SCARG(&bsa, semnum) = SCARG(uap, a2);
    305 	SCARG(&bsa, cmd) = SCARG(uap, a3);
    306 	SCARG(&bsa, arg) = (union semun *)SCARG(uap, ptr);
    307 	switch(SCARG(uap, a3)) {
    308 	case LINUX_GETVAL:
    309 		cmd = GETVAL;
    310 		break;
    311 	case LINUX_GETPID:
    312 		cmd = GETPID;
    313 		break;
    314 	case LINUX_GETNCNT:
    315 		cmd = GETNCNT;
    316 		break;
    317 	case LINUX_GETZCNT:
    318 		cmd = GETZCNT;
    319 		break;
    320 	case LINUX_SETVAL:
    321 		cmd = SETVAL;
    322 		break;
    323 	case LINUX_IPC_RMID:
    324 		cmd = IPC_RMID;
    325 		break;
    326 	case LINUX_IPC_SET:
    327 		if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp)))
    328 			return error;
    329 		if ((error = copyin(ldsp, (caddr_t)&lm, sizeof lm)))
    330 			return error;
    331 		linux_to_bsd_semid_ds(&lm, &bm);
    332 		sg = stackgap_init(p->p_emul);
    333 		unptr = stackgap_alloc(&sg, sizeof (union semun));
    334 		dsp = stackgap_alloc(&sg, sizeof (struct semid_ds));
    335 		if ((error = copyout((caddr_t)&bm, dsp, sizeof bm)))
    336 			return error;
    337 		if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp)))
    338 			return error;
    339 		SCARG(&bsa, arg) = (union semun *)unptr;
    340 		return sys___semctl(p, &bsa, retval);
    341 	case LINUX_IPC_STAT:
    342 		sg = stackgap_init(p->p_emul);
    343 		unptr = stackgap_alloc(&sg, sizeof (union semun *));
    344 		dsp = stackgap_alloc(&sg, sizeof (struct semid_ds));
    345 		if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp)))
    346 			return error;
    347 		SCARG(&bsa, arg) = (union semun *)unptr;
    348 		if ((error = sys___semctl(p, &bsa, retval)))
    349 			return error;
    350 		if ((error = copyin(dsp, (caddr_t)&bm, sizeof bm)))
    351 			return error;
    352 		bsd_to_linux_semid_ds(&bm, &lm);
    353 		if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp)))
    354 			return error;
    355 		return copyout((caddr_t)&lm, ldsp, sizeof lm);
    356 	default:
    357 		return EINVAL;
    358 	}
    359 	SCARG(&bsa, cmd) = cmd;
    360 
    361 	return sys___semctl(p, &bsa, retval);
    362 }
    363 #endif /* SYSVSEM */
    364 
    365 #ifdef SYSVMSG
    366 
    367 static void
    368 linux_to_bsd_msqid_ds(lmp, bmp)
    369 	struct linux_msqid_ds *lmp;
    370 	struct msqid_ds *bmp;
    371 {
    372 
    373 	linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm);
    374 	bmp->msg_first = lmp->l_msg_first;
    375 	bmp->msg_last = lmp->l_msg_last;
    376 	bmp->msg_cbytes = lmp->l_msg_cbytes;
    377 	bmp->msg_qnum = lmp->l_msg_qnum;
    378 	bmp->msg_qbytes = lmp->l_msg_qbytes;
    379 	bmp->msg_lspid = lmp->l_msg_lspid;
    380 	bmp->msg_lrpid = lmp->l_msg_lrpid;
    381 	bmp->msg_stime = lmp->l_msg_stime;
    382 	bmp->msg_rtime = lmp->l_msg_rtime;
    383 	bmp->msg_ctime = lmp->l_msg_ctime;
    384 }
    385 
    386 static void
    387 bsd_to_linux_msqid_ds(bmp, lmp)
    388 	struct msqid_ds *bmp;
    389 	struct linux_msqid_ds *lmp;
    390 {
    391 
    392 	bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm);
    393 	lmp->l_msg_first = bmp->msg_first;
    394 	lmp->l_msg_last = bmp->msg_last;
    395 	lmp->l_msg_cbytes = bmp->msg_cbytes;
    396 	lmp->l_msg_qnum = bmp->msg_qnum;
    397 	lmp->l_msg_qbytes = bmp->msg_qbytes;
    398 	lmp->l_msg_lspid = bmp->msg_lspid;
    399 	lmp->l_msg_lrpid = bmp->msg_lrpid;
    400 	lmp->l_msg_stime = bmp->msg_stime;
    401 	lmp->l_msg_rtime = bmp->msg_rtime;
    402 	lmp->l_msg_ctime = bmp->msg_ctime;
    403 }
    404 
    405 static int
    406 linux_msgsnd(p, uap, retval)
    407 	struct proc *p;
    408 	struct linux_sys_ipc_args /* {
    409 		syscallarg(int) what;
    410 		syscallarg(int) a1;
    411 		syscallarg(int) a2;
    412 		syscallarg(int) a3;
    413 		syscallarg(caddr_t) ptr;
    414 	} */ *uap;
    415 	register_t *retval;
    416 {
    417 	struct sys_msgsnd_args bma;
    418 
    419 	SCARG(&bma, msqid) = SCARG(uap, a1);
    420 	SCARG(&bma, msgp) = SCARG(uap, ptr);
    421 	SCARG(&bma, msgsz) = SCARG(uap, a2);
    422 	SCARG(&bma, msgflg) = SCARG(uap, a3);
    423 
    424 	return sys_msgsnd(p, &bma, retval);
    425 }
    426 
    427 static int
    428 linux_msgrcv(p, uap, retval)
    429 	struct proc *p;
    430 	struct linux_sys_ipc_args /* {
    431 		syscallarg(int) what;
    432 		syscallarg(int) a1;
    433 		syscallarg(int) a2;
    434 		syscallarg(int) a3;
    435 		syscallarg(caddr_t) ptr;
    436 	} */ *uap;
    437 	register_t *retval;
    438 {
    439 	struct sys_msgrcv_args bma;
    440 	struct linux_msgrcv_msgarg kluge;
    441 	int error;
    442 
    443 	if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge)))
    444 		return error;
    445 
    446 	SCARG(&bma, msqid) = SCARG(uap, a1);
    447 	SCARG(&bma, msgp) = kluge.msg;
    448 	SCARG(&bma, msgsz) = SCARG(uap, a2);
    449 	SCARG(&bma, msgtyp) = kluge.type;
    450 	SCARG(&bma, msgflg) = SCARG(uap, a3);
    451 
    452 	return sys_msgrcv(p, &bma, retval);
    453 }
    454 
    455 static int
    456 linux_msgget(p, uap, retval)
    457 	struct proc *p;
    458 	struct linux_sys_ipc_args /* {
    459 		syscallarg(int) what;
    460 		syscallarg(int) a1;
    461 		syscallarg(int) a2;
    462 		syscallarg(int) a3;
    463 		syscallarg(caddr_t) ptr;
    464 	} */ *uap;
    465 	register_t *retval;
    466 {
    467 	struct sys_msgget_args bma;
    468 
    469 	SCARG(&bma, key) = (key_t)SCARG(uap, a1);
    470 	SCARG(&bma, msgflg) = SCARG(uap, a2);
    471 
    472 	return sys_msgget(p, &bma, retval);
    473 }
    474 
    475 static int
    476 linux_msgctl(p, uap, retval)
    477 	struct proc *p;
    478 	struct linux_sys_ipc_args /* {
    479 		syscallarg(int) what;
    480 		syscallarg(int) a1;
    481 		syscallarg(int) a2;
    482 		syscallarg(int) a3;
    483 		syscallarg(caddr_t) ptr;
    484 	} */ *uap;
    485 	register_t *retval;
    486 {
    487 	struct sys_msgctl_args bma;
    488 	caddr_t umsgptr, sg;
    489 	struct linux_msqid_ds lm;
    490 	struct msqid_ds bm;
    491 	int error;
    492 
    493 	SCARG(&bma, msqid) = SCARG(uap, a1);
    494 	SCARG(&bma, cmd) = SCARG(uap, a2);
    495 	switch (SCARG(uap, a2)) {
    496 	case LINUX_IPC_RMID:
    497 		return sys_msgctl(p, &bma, retval);
    498 	case LINUX_IPC_SET:
    499 		if ((error = copyin(SCARG(uap, ptr), (caddr_t)&lm, sizeof lm)))
    500 			return error;
    501 		linux_to_bsd_msqid_ds(&lm, &bm);
    502 		sg = stackgap_init(p->p_emul);
    503 		umsgptr = stackgap_alloc(&sg, sizeof bm);
    504 		if ((error = copyout((caddr_t)&bm, umsgptr, sizeof bm)))
    505 			return error;
    506 		SCARG(&bma, buf) = (struct msqid_ds *)umsgptr;
    507 		return sys_msgctl(p, &bma, retval);
    508 	case LINUX_IPC_STAT:
    509 		sg = stackgap_init(p->p_emul);
    510 		umsgptr = stackgap_alloc(&sg, sizeof (struct msqid_ds));
    511 		SCARG(&bma, buf) = (struct msqid_ds *)umsgptr;
    512 		if ((error = sys_msgctl(p, &bma, retval)))
    513 			return error;
    514 		if ((error = copyin(umsgptr, (caddr_t)&bm, sizeof bm)))
    515 			return error;
    516 		bsd_to_linux_msqid_ds(&bm, &lm);
    517 		return copyout((caddr_t)&lm, SCARG(uap, ptr), sizeof lm);
    518 	}
    519 	return EINVAL;
    520 }
    521 #endif /* SYSVMSG */
    522 
    523 #ifdef SYSVSHM
    524 /*
    525  * shmat(2). Very straightforward, except that Linux passes a pointer
    526  * in which the return value is to be passed. This is subsequently
    527  * handled by libc, apparently.
    528  */
    529 static int
    530 linux_shmat(p, uap, retval)
    531 	struct proc *p;
    532 	struct linux_sys_ipc_args /* {
    533 		syscallarg(int) what;
    534 		syscallarg(int) a1;
    535 		syscallarg(int) a2;
    536 		syscallarg(int) a3;
    537 		syscallarg(caddr_t) ptr;
    538 	} */ *uap;
    539 	register_t *retval;
    540 {
    541 	struct sys_shmat_args bsa;
    542 	int error;
    543 
    544 	SCARG(&bsa, shmid) = SCARG(uap, a1);
    545 	SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
    546 	SCARG(&bsa, shmflg) = SCARG(uap, a2);
    547 
    548 	if ((error = sys_shmat(p, &bsa, retval)))
    549 		return error;
    550 
    551 	if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3),
    552 	     sizeof retval[0])))
    553 		return error;
    554 
    555 	retval[0] = 0;
    556 	return 0;
    557 }
    558 
    559 /*
    560  * shmdt(): this could have been mapped directly, if it wasn't for
    561  * the extra indirection by the linux_ipc system call.
    562  */
    563 static int
    564 linux_shmdt(p, uap, retval)
    565 	struct proc *p;
    566 	struct linux_sys_ipc_args /* {
    567 		syscallarg(int) what;
    568 		syscallarg(int) a1;
    569 		syscallarg(int) a2;
    570 		syscallarg(int) a3;
    571 		syscallarg(caddr_t) ptr;
    572 	} */ *uap;
    573 	register_t *retval;
    574 {
    575 	struct sys_shmdt_args bsa;
    576 
    577 	SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
    578 
    579 	return sys_shmdt(p, &bsa, retval);
    580 }
    581 
    582 /*
    583  * Same story as shmdt.
    584  */
    585 static int
    586 linux_shmget(p, uap, retval)
    587 	struct proc *p;
    588 	struct linux_sys_ipc_args /* {
    589 		syscallarg(int) what;
    590 		syscallarg(int) a1;
    591 		syscallarg(int) a2;
    592 		syscallarg(int) a3;
    593 		syscallarg(caddr_t) ptr;
    594 	} */ *uap;
    595 	register_t *retval;
    596 {
    597 	struct sys_shmget_args bsa;
    598 
    599 	SCARG(&bsa, key) = SCARG(uap, a1);
    600 	SCARG(&bsa, size) = SCARG(uap, a2);
    601 	SCARG(&bsa, shmflg) = SCARG(uap, a3);
    602 
    603 	return sys_shmget(p, &bsa, retval);
    604 }
    605 
    606 /*
    607  * Convert between Linux and NetBSD shmid_ds structures.
    608  * The order of the fields is once again the difference, and
    609  * we also need a place to store the internal data pointer
    610  * in, which is unfortunately stored in this structure.
    611  *
    612  * We abuse a Linux internal field for that.
    613  */
    614 static void
    615 linux_to_bsd_shmid_ds(lsp, bsp)
    616 	struct linux_shmid_ds *lsp;
    617 	struct shmid_ds *bsp;
    618 {
    619 
    620 	linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm);
    621 	bsp->shm_segsz = lsp->l_shm_segsz;
    622 	bsp->shm_lpid = lsp->l_shm_lpid;
    623 	bsp->shm_cpid = lsp->l_shm_cpid;
    624 	bsp->shm_nattch = lsp->l_shm_nattch;
    625 	bsp->shm_atime = lsp->l_shm_atime;
    626 	bsp->shm_dtime = lsp->l_shm_dtime;
    627 	bsp->shm_ctime = lsp->l_shm_ctime;
    628 	bsp->shm_internal = lsp->l_private2;	/* XXX Oh well. */
    629 }
    630 
    631 static void
    632 bsd_to_linux_shmid_ds(bsp, lsp)
    633 	struct shmid_ds *bsp;
    634 	struct linux_shmid_ds *lsp;
    635 {
    636 
    637 	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm);
    638 	lsp->l_shm_segsz = bsp->shm_segsz;
    639 	lsp->l_shm_lpid = bsp->shm_lpid;
    640 	lsp->l_shm_cpid = bsp->shm_cpid;
    641 	lsp->l_shm_nattch = bsp->shm_nattch;
    642 	lsp->l_shm_atime = bsp->shm_atime;
    643 	lsp->l_shm_dtime = bsp->shm_dtime;
    644 	lsp->l_shm_ctime = bsp->shm_ctime;
    645 	lsp->l_private2 = bsp->shm_internal;	/* XXX */
    646 }
    647 
    648 /*
    649  * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT
    650  * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented
    651  * by NetBSD itself.
    652  *
    653  * The usual structure conversion and massaging is done.
    654  */
    655 static int
    656 linux_shmctl(p, uap, retval)
    657 	struct proc *p;
    658 	struct linux_sys_ipc_args /* {
    659 		syscallarg(int) what;
    660 		syscallarg(int) a1;
    661 		syscallarg(int) a2;
    662 		syscallarg(int) a3;
    663 		syscallarg(caddr_t) ptr;
    664 	} */ *uap;
    665 	register_t *retval;
    666 {
    667 	int error;
    668 	caddr_t sg;
    669 	struct sys_shmctl_args bsa;
    670 	struct shmid_ds *bsp, bs;
    671 	struct linux_shmid_ds lseg;
    672 
    673 	switch (SCARG(uap, a2)) {
    674 	case LINUX_IPC_STAT:
    675 		sg = stackgap_init(p->p_emul);
    676 		bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
    677 		SCARG(&bsa, shmid) = SCARG(uap, a1);
    678 		SCARG(&bsa, cmd) = IPC_STAT;
    679 		SCARG(&bsa, buf) = bsp;
    680 		if ((error = sys_shmctl(p, &bsa, retval)))
    681 			return error;
    682 		if ((error = copyin((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
    683 			return error;
    684 		bsd_to_linux_shmid_ds(&bs, &lseg);
    685 		return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg);
    686 	case LINUX_IPC_SET:
    687 		if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg,
    688 		     sizeof lseg)))
    689 			return error;
    690 		linux_to_bsd_shmid_ds(&lseg, &bs);
    691 		sg = stackgap_init(p->p_emul);
    692 		bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
    693 		if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
    694 			return error;
    695 		SCARG(&bsa, shmid) = SCARG(uap, a1);
    696 		SCARG(&bsa, cmd) = IPC_SET;
    697 		SCARG(&bsa, buf) = bsp;
    698 		return sys_shmctl(p, &bsa, retval);
    699 	case LINUX_IPC_RMID:
    700 	case LINUX_SHM_LOCK:
    701 	case LINUX_SHM_UNLOCK:
    702 		SCARG(&bsa, shmid) = SCARG(uap, a1);
    703 		switch (SCARG(uap, a2)) {
    704 		case LINUX_IPC_RMID:
    705 			SCARG(&bsa, cmd) = IPC_RMID;
    706 			break;
    707 		case LINUX_SHM_LOCK:
    708 			SCARG(&bsa, cmd) = SHM_LOCK;
    709 			break;
    710 		case LINUX_SHM_UNLOCK:
    711 			SCARG(&bsa, cmd) = SHM_UNLOCK;
    712 			break;
    713 		}
    714 		SCARG(&bsa, buf) = NULL;
    715 		return sys_shmctl(p, &bsa, retval);
    716 	case LINUX_IPC_INFO:
    717 	case LINUX_SHM_STAT:
    718 	case LINUX_SHM_INFO:
    719 	default:
    720 		return EINVAL;
    721 	}
    722 }
    723 #endif /* SYSVSHM */
    724