xref: /netbsd-src/sys/compat/linux/common/linux_ipc.c (revision 542f82ceb455d80102956ba8a1f98b1ab8f7e6ee)
1*542f82ceSmaxv /*	$NetBSD: linux_ipc.c,v 1.57 2019/08/23 10:22:15 maxv Exp $	*/
2d4649701Serh 
3d4649701Serh /*-
48096c25aSfvdl  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5d4649701Serh  * All rights reserved.
6d4649701Serh  *
7d4649701Serh  * This code is derived from software contributed to The NetBSD Foundation
88096c25aSfvdl  * by Frank van der Linden and Eric Haszlakiewicz.
9d4649701Serh  *
10d4649701Serh  * Redistribution and use in source and binary forms, with or without
11d4649701Serh  * modification, are permitted provided that the following conditions
12d4649701Serh  * are met:
13d4649701Serh  * 1. Redistributions of source code must retain the above copyright
14d4649701Serh  *    notice, this list of conditions and the following disclaimer.
15d4649701Serh  * 2. Redistributions in binary form must reproduce the above copyright
16d4649701Serh  *    notice, this list of conditions and the following disclaimer in the
17d4649701Serh  *    documentation and/or other materials provided with the distribution.
18d4649701Serh  *
19d4649701Serh  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d4649701Serh  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d4649701Serh  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d4649701Serh  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d4649701Serh  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d4649701Serh  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d4649701Serh  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d4649701Serh  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d4649701Serh  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d4649701Serh  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d4649701Serh  * POSSIBILITY OF SUCH DAMAGE.
30d4649701Serh  */
313bf459f3Sfvdl 
32dab6ef8bSlukem #include <sys/cdefs.h>
33*542f82ceSmaxv __KERNEL_RCSID(0, "$NetBSD: linux_ipc.c,v 1.57 2019/08/23 10:22:15 maxv Exp $");
34dab6ef8bSlukem 
356a89288aSmrg #if defined(_KERNEL_OPT)
36d9a22c58Serh #include "opt_sysv.h"
37011229ffSjdolecek #endif
38d9a22c58Serh 
393bf459f3Sfvdl #include <sys/param.h>
403bf459f3Sfvdl #include <sys/shm.h>
4102b3c95bSfvdl #include <sys/sem.h>
423bf459f3Sfvdl #include <sys/msg.h>
433bf459f3Sfvdl #include <sys/proc.h>
443bf459f3Sfvdl #include <sys/systm.h>
4529158b16Snjoly #include <sys/vnode.h>
463bf459f3Sfvdl 
473bf459f3Sfvdl #include <sys/mount.h>
483bf459f3Sfvdl #include <sys/syscallargs.h>
493bf459f3Sfvdl 
50908291d2Schristos #include <compat/linux/common/linux_types.h>
51908291d2Schristos #include <compat/linux/common/linux_signal.h>
52908291d2Schristos #include <compat/linux/common/linux_util.h>
53908291d2Schristos #include <compat/linux/common/linux_ipc.h>
54908291d2Schristos #include <compat/linux/common/linux_msg.h>
55908291d2Schristos #include <compat/linux/common/linux_shm.h>
56908291d2Schristos #include <compat/linux/common/linux_sem.h>
573bf459f3Sfvdl 
58ee0c5b44Smanu #include <compat/linux/linux_syscallargs.h>
59ee0c5b44Smanu #include <compat/linux/linux_syscall.h>
60ee0c5b44Smanu 
61663b29bbSdogcow #include <compat/linux/common/linux_ipccall.h>
624eecf433Snjoly #include <compat/linux/common/linux_machdep.h>
63663b29bbSdogcow 
643bf459f3Sfvdl /*
65d4649701Serh  * Note: Not all linux architechtures have explicit versions
66d4649701Serh  *	of the SYSV* syscalls.  On the ones that don't
67d4649701Serh  *	we pretend that they are defined anyway.  *_args and
68d4649701Serh  *	prototypes are defined in individual headers;
69d4649701Serh  *	syscalls.master lists those syscalls as NOARGS.
703bf459f3Sfvdl  *
71d4649701Serh  *	The functions in multiarch are the ones that just need
72d4649701Serh  *	the arguments shuffled around and then use the
73d4649701Serh  *	normal NetBSD syscall.
74d4649701Serh  *
75d4649701Serh  * Function in multiarch:
76d4649701Serh  *	linux_sys_ipc		: linux_ipccall.c
771ff2a8d0Salnsn  *	linux_semop		: linux_ipccall.c
78d4649701Serh  *	linux_semget		: linux_ipccall.c
79d4649701Serh  *	linux_msgsnd		: linux_ipccall.c
80d4649701Serh  *	linux_msgrcv		: linux_ipccall.c
81d4649701Serh  *	linux_msgget		: linux_ipccall.c
82d4649701Serh  *	linux_shmdt		: linux_ipccall.c
83d4649701Serh  *	linux_shmget		: linux_ipccall.c
843bf459f3Sfvdl  */
853bf459f3Sfvdl 
862452eadcSfvdl #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG)
873bf459f3Sfvdl /*
883bf459f3Sfvdl  * Convert between Linux and NetBSD ipc_perm structures. Only the
893bf459f3Sfvdl  * order of the fields is different.
903bf459f3Sfvdl  */
91d4649701Serh void
linux_to_bsd_ipc_perm(struct linux_ipc_perm * lpp,struct ipc_perm * bpp)9228bae79bSdsl linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp)
933bf459f3Sfvdl {
94245f292fSmycroft 
952c358fcaSthorpej 	bpp->_key = lpp->l_key;
963bf459f3Sfvdl 	bpp->uid = lpp->l_uid;
973bf459f3Sfvdl 	bpp->gid = lpp->l_gid;
983bf459f3Sfvdl 	bpp->cuid = lpp->l_cuid;
993bf459f3Sfvdl 	bpp->cgid = lpp->l_cgid;
1003bf459f3Sfvdl 	bpp->mode = lpp->l_mode;
1012c358fcaSthorpej 	bpp->_seq = lpp->l_seq;
1023bf459f3Sfvdl }
1033bf459f3Sfvdl 
104d4649701Serh void
linux_to_bsd_ipc64_perm(struct linux_ipc64_perm * lpp,struct ipc_perm * bpp)10528bae79bSdsl linux_to_bsd_ipc64_perm(struct linux_ipc64_perm *lpp, struct ipc_perm *bpp)
10665de380aSchristos {
10765de380aSchristos 	bpp->_key = lpp->l_key;
10865de380aSchristos 	bpp->uid = lpp->l_uid;
10965de380aSchristos 	bpp->gid = lpp->l_gid;
11065de380aSchristos 	bpp->cuid = lpp->l_cuid;
11165de380aSchristos 	bpp->cgid = lpp->l_cgid;
11265de380aSchristos 	bpp->mode = lpp->l_mode;
11365de380aSchristos 	bpp->_seq = lpp->l_seq;
11465de380aSchristos }
11565de380aSchristos 
11665de380aSchristos void
bsd_to_linux_ipc_perm(struct ipc_perm * bpp,struct linux_ipc_perm * lpp)11728bae79bSdsl bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp)
1183bf459f3Sfvdl {
119245f292fSmycroft 
12039e3203eSmrg 	memset(lpp, 0, sizeof *lpp);
1212c358fcaSthorpej 	lpp->l_key = bpp->_key;
1223bf459f3Sfvdl 	lpp->l_uid = bpp->uid;
1233bf459f3Sfvdl 	lpp->l_gid = bpp->gid;
1243bf459f3Sfvdl 	lpp->l_cuid = bpp->cuid;
1253bf459f3Sfvdl 	lpp->l_cgid = bpp->cgid;
1263bf459f3Sfvdl 	lpp->l_mode = bpp->mode;
1272c358fcaSthorpej 	lpp->l_seq = bpp->_seq;
1283bf459f3Sfvdl }
12965de380aSchristos 
13065de380aSchristos void
bsd_to_linux_ipc64_perm(struct ipc_perm * bpp,struct linux_ipc64_perm * lpp)13128bae79bSdsl bsd_to_linux_ipc64_perm(struct ipc_perm *bpp, struct linux_ipc64_perm *lpp)
13265de380aSchristos {
13339e3203eSmrg 
13439e3203eSmrg 	memset(lpp, 0, sizeof *lpp);
13565de380aSchristos 	lpp->l_key = bpp->_key;
13665de380aSchristos 	lpp->l_uid = bpp->uid;
13765de380aSchristos 	lpp->l_gid = bpp->gid;
13865de380aSchristos 	lpp->l_cuid = bpp->cuid;
13965de380aSchristos 	lpp->l_cgid = bpp->cgid;
14065de380aSchristos 	lpp->l_mode = bpp->mode;
14165de380aSchristos 	lpp->l_seq = bpp->_seq;
14265de380aSchristos }
14365de380aSchristos 
1442452eadcSfvdl #endif
1453bf459f3Sfvdl 
1463bf459f3Sfvdl #ifdef SYSVSEM
1473bf459f3Sfvdl /*
14802b3c95bSfvdl  * Semaphore operations. Most constants and structures are the same on
14902b3c95bSfvdl  * both systems. Only semctl() needs some extra work.
1503bf459f3Sfvdl  */
15102b3c95bSfvdl 
15202b3c95bSfvdl /*
15302b3c95bSfvdl  * Convert between Linux and NetBSD semid_ds structures.
15402b3c95bSfvdl  */
155d4649701Serh void
bsd_to_linux_semid_ds(struct semid_ds * bs,struct linux_semid_ds * ls)15628bae79bSdsl bsd_to_linux_semid_ds(struct semid_ds *bs, struct linux_semid_ds *ls)
15702b3c95bSfvdl {
15839e3203eSmrg 
15939e3203eSmrg 	memset(ls, 0, sizeof *ls);
16002b3c95bSfvdl 	bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm);
16102b3c95bSfvdl 	ls->l_sem_otime = bs->sem_otime;
16202b3c95bSfvdl 	ls->l_sem_ctime = bs->sem_ctime;
16302b3c95bSfvdl 	ls->l_sem_nsems = bs->sem_nsems;
16402b3c95bSfvdl }
16502b3c95bSfvdl 
166d4649701Serh void
bsd_to_linux_semid64_ds(struct semid_ds * bs,struct linux_semid64_ds * ls)167436fa0efSnjoly bsd_to_linux_semid64_ds(struct semid_ds *bs, struct linux_semid64_ds *ls)
168436fa0efSnjoly {
16939e3203eSmrg 
17039e3203eSmrg 	memset(ls, 0, sizeof *ls);
171436fa0efSnjoly 	bsd_to_linux_ipc64_perm(&bs->sem_perm, &ls->l_sem_perm);
172436fa0efSnjoly 	ls->l_sem_otime = bs->sem_otime;
173436fa0efSnjoly 	ls->l_sem_ctime = bs->sem_ctime;
174436fa0efSnjoly 	ls->l_sem_nsems = bs->sem_nsems;
175436fa0efSnjoly }
176436fa0efSnjoly 
177436fa0efSnjoly void
linux_to_bsd_semid_ds(struct linux_semid_ds * ls,struct semid_ds * bs)17828bae79bSdsl linux_to_bsd_semid_ds(struct linux_semid_ds *ls, struct semid_ds *bs)
17902b3c95bSfvdl {
18039e3203eSmrg 
18102b3c95bSfvdl 	linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm);
18202b3c95bSfvdl 	bs->sem_otime = ls->l_sem_otime;
18302b3c95bSfvdl 	bs->sem_ctime = ls->l_sem_ctime;
18402b3c95bSfvdl 	bs->sem_nsems = ls->l_sem_nsems;
18502b3c95bSfvdl }
18602b3c95bSfvdl 
187436fa0efSnjoly void
linux_to_bsd_semid64_ds(struct linux_semid64_ds * ls,struct semid_ds * bs)188436fa0efSnjoly linux_to_bsd_semid64_ds(struct linux_semid64_ds *ls, struct semid_ds *bs)
189436fa0efSnjoly {
19039e3203eSmrg 
191436fa0efSnjoly 	linux_to_bsd_ipc64_perm(&ls->l_sem_perm, &bs->sem_perm);
192436fa0efSnjoly 	bs->sem_otime = ls->l_sem_otime;
193436fa0efSnjoly 	bs->sem_ctime = ls->l_sem_ctime;
194436fa0efSnjoly 	bs->sem_nsems = ls->l_sem_nsems;
195436fa0efSnjoly }
196436fa0efSnjoly 
19702b3c95bSfvdl /*
1982c358fcaSthorpej  * Most of this can be handled by directly passing the arguments on; we
1992c358fcaSthorpej  * just need to frob the `cmd' and convert the semid_ds and semun.
20002b3c95bSfvdl  */
2013bf459f3Sfvdl int
linux_sys_semctl(struct lwp * l,const struct linux_sys_semctl_args * uap,register_t * retval)2027e2790cfSdsl linux_sys_semctl(struct lwp *l, const struct linux_sys_semctl_args *uap, register_t *retval)
2033bf459f3Sfvdl {
2047e2790cfSdsl 	/* {
205d4649701Serh 		syscallarg(int) semid;
206d4649701Serh 		syscallarg(int) semnum;
207d4649701Serh 		syscallarg(int) cmd;
208d4649701Serh 		syscallarg(union linux_semun) arg;
2097e2790cfSdsl 	} */
2102c358fcaSthorpej 	struct semid_ds sembuf;
2112c358fcaSthorpej 	struct linux_semid_ds lsembuf;
212436fa0efSnjoly 	struct linux_semid64_ds lsembuf64;
2132c358fcaSthorpej 	union __semun semun;
214436fa0efSnjoly 	int cmd, lcmd, error;
2152c358fcaSthorpej 	void *pass_arg = NULL;
21602b3c95bSfvdl 
217436fa0efSnjoly 	lcmd = SCARG(uap, cmd);
218436fa0efSnjoly #ifdef LINUX_IPC_FORCE64
219436fa0efSnjoly 	lcmd |= LINUX_IPC_64;
220436fa0efSnjoly #endif
2212c358fcaSthorpej 
222d3dabe12Snjoly 	switch (lcmd & ~LINUX_IPC_64) {
223769c9d47Smycroft 	case LINUX_IPC_SET:
224d3dabe12Snjoly 		if (lcmd & LINUX_IPC_64) {
225436fa0efSnjoly 			error = copyin(SCARG(uap, arg).l_buf, &lsembuf64,
226436fa0efSnjoly 		    	    sizeof(lsembuf64));
227d3dabe12Snjoly 			linux_to_bsd_semid64_ds(&lsembuf64, &sembuf);
228d3dabe12Snjoly 		} else {
229d3dabe12Snjoly 			error = copyin(SCARG(uap, arg).l_buf, &lsembuf,
230d3dabe12Snjoly 		    	   sizeof(lsembuf));
231d3dabe12Snjoly 			linux_to_bsd_semid_ds(&lsembuf, &sembuf);
232d3dabe12Snjoly 		}
233436fa0efSnjoly 		if (error)
234436fa0efSnjoly 			return (error);
2352c358fcaSthorpej 		pass_arg = &sembuf;
2362c358fcaSthorpej 		cmd = IPC_SET;
237d4649701Serh 		break;
2382c358fcaSthorpej 
2392c358fcaSthorpej 	case LINUX_IPC_STAT:
2402c358fcaSthorpej 		pass_arg = &sembuf;
2412c358fcaSthorpej 		cmd = IPC_STAT;
2422c358fcaSthorpej 		break;
2432c358fcaSthorpej 
244769c9d47Smycroft 	case LINUX_IPC_RMID:
2452c358fcaSthorpej 		cmd = IPC_RMID;
246769c9d47Smycroft 		break;
2472c358fcaSthorpej 
248769c9d47Smycroft 	case LINUX_GETVAL:
2492c358fcaSthorpej 		cmd = GETVAL;
250769c9d47Smycroft 		break;
2512c358fcaSthorpej 
252769c9d47Smycroft 	case LINUX_GETPID:
2532c358fcaSthorpej 		cmd = GETPID;
254769c9d47Smycroft 		break;
2552c358fcaSthorpej 
256769c9d47Smycroft 	case LINUX_GETNCNT:
2572c358fcaSthorpej 		cmd = GETNCNT;
258769c9d47Smycroft 		break;
2592c358fcaSthorpej 
260769c9d47Smycroft 	case LINUX_GETZCNT:
2612c358fcaSthorpej 		cmd = GETZCNT;
262769c9d47Smycroft 		break;
2632c358fcaSthorpej 
264c0567a6bStron 	case LINUX_GETALL:
2652c358fcaSthorpej 		pass_arg = &semun;
2662c358fcaSthorpej 		semun.array = SCARG(uap, arg).l_array;
2672c358fcaSthorpej 		cmd = GETALL;
268c0567a6bStron 		break;
2692c358fcaSthorpej 
2702c358fcaSthorpej 	case LINUX_SETVAL:
2712c358fcaSthorpej 		pass_arg = &semun;
2722c358fcaSthorpej 		semun.val = SCARG(uap, arg).l_val;
2732c358fcaSthorpej 		cmd = SETVAL;
2742c358fcaSthorpej 		break;
2752c358fcaSthorpej 
276c0567a6bStron 	case LINUX_SETALL:
2772c358fcaSthorpej 		pass_arg = &semun;
2782c358fcaSthorpej 		semun.array = SCARG(uap, arg).l_array;
2792c358fcaSthorpej 		cmd = SETALL;
280769c9d47Smycroft 		break;
2812c358fcaSthorpej 
28202b3c95bSfvdl 	default:
2832c358fcaSthorpej 		return (EINVAL);
28402b3c95bSfvdl 	}
2852c358fcaSthorpej 
286f474dcebSad 	error = semctl1(l, SCARG(uap, semid), SCARG(uap, semnum), cmd,
2872c358fcaSthorpej 	    pass_arg, retval);
288436fa0efSnjoly 	if (error)
289436fa0efSnjoly 		return error;
2902c358fcaSthorpej 
291436fa0efSnjoly 	switch (lcmd) {
292436fa0efSnjoly 	case LINUX_IPC_STAT:
2932c358fcaSthorpej 		bsd_to_linux_semid_ds(&sembuf, &lsembuf);
2942c358fcaSthorpej 		error = copyout(&lsembuf, SCARG(uap, arg).l_buf,
2952c358fcaSthorpej 		    sizeof(lsembuf));
296436fa0efSnjoly 		break;
297436fa0efSnjoly 	case LINUX_IPC_STAT | LINUX_IPC_64:
298436fa0efSnjoly 		bsd_to_linux_semid64_ds(&sembuf, &lsembuf64);
299436fa0efSnjoly 		error = copyout(&lsembuf64, SCARG(uap, arg).l_buf,
300436fa0efSnjoly 		    sizeof(lsembuf64));
301436fa0efSnjoly 		break;
302436fa0efSnjoly 	default:
303436fa0efSnjoly 		break;
3042c358fcaSthorpej 	}
3052c358fcaSthorpej 
3062c358fcaSthorpej 	return (error);
3073bf459f3Sfvdl }
3083bf459f3Sfvdl #endif /* SYSVSEM */
3093bf459f3Sfvdl 
3103bf459f3Sfvdl #ifdef SYSVMSG
31102b3c95bSfvdl 
312d4649701Serh void
linux_to_bsd_msqid_ds(struct linux_msqid_ds * lmp,struct msqid_ds * bmp)31328bae79bSdsl linux_to_bsd_msqid_ds(struct linux_msqid_ds *lmp, struct msqid_ds *bmp)
31402b3c95bSfvdl {
315245f292fSmycroft 
316bf54b26cSjoerg 	memset(bmp, 0, sizeof(*bmp));
31702b3c95bSfvdl 	linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm);
3182c358fcaSthorpej 	bmp->_msg_cbytes = lmp->l_msg_cbytes;
31902b3c95bSfvdl 	bmp->msg_qnum = lmp->l_msg_qnum;
32002b3c95bSfvdl 	bmp->msg_qbytes = lmp->l_msg_qbytes;
32102b3c95bSfvdl 	bmp->msg_lspid = lmp->l_msg_lspid;
32202b3c95bSfvdl 	bmp->msg_lrpid = lmp->l_msg_lrpid;
32302b3c95bSfvdl 	bmp->msg_stime = lmp->l_msg_stime;
32402b3c95bSfvdl 	bmp->msg_rtime = lmp->l_msg_rtime;
32502b3c95bSfvdl 	bmp->msg_ctime = lmp->l_msg_ctime;
32602b3c95bSfvdl }
32702b3c95bSfvdl 
328d4649701Serh void
linux_to_bsd_msqid64_ds(struct linux_msqid64_ds * lmp,struct msqid_ds * bmp)329e82000b5Snjoly linux_to_bsd_msqid64_ds(struct linux_msqid64_ds *lmp, struct msqid_ds *bmp)
330e82000b5Snjoly {
331bf54b26cSjoerg 
332bf54b26cSjoerg 	memset(bmp, 0, sizeof(*bmp));
333e82000b5Snjoly 	linux_to_bsd_ipc64_perm(&lmp->l_msg_perm, &bmp->msg_perm);
33439e3203eSmrg 	bmp->_msg_cbytes = lmp->l_msg_cbytes;
335e82000b5Snjoly 	bmp->msg_stime = lmp->l_msg_stime;
336e82000b5Snjoly 	bmp->msg_rtime = lmp->l_msg_rtime;
337e82000b5Snjoly 	bmp->msg_ctime = lmp->l_msg_ctime;
338e82000b5Snjoly 	bmp->msg_qnum = lmp->l_msg_qnum;
339e82000b5Snjoly 	bmp->msg_qbytes = lmp->l_msg_qbytes;
340e82000b5Snjoly 	bmp->msg_lspid = lmp->l_msg_lspid;
341e82000b5Snjoly 	bmp->msg_lrpid = lmp->l_msg_lrpid;
342e82000b5Snjoly }
343e82000b5Snjoly 
344e82000b5Snjoly void
bsd_to_linux_msqid_ds(struct msqid_ds * bmp,struct linux_msqid_ds * lmp)34528bae79bSdsl bsd_to_linux_msqid_ds(struct msqid_ds *bmp, struct linux_msqid_ds *lmp)
34602b3c95bSfvdl {
347245f292fSmycroft 
348bf54b26cSjoerg 	memset(lmp, 0, sizeof(*lmp));
34902b3c95bSfvdl 	bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm);
3502c358fcaSthorpej 	lmp->l_msg_cbytes = bmp->_msg_cbytes;
35102b3c95bSfvdl 	lmp->l_msg_qnum = bmp->msg_qnum;
35202b3c95bSfvdl 	lmp->l_msg_qbytes = bmp->msg_qbytes;
35302b3c95bSfvdl 	lmp->l_msg_lspid = bmp->msg_lspid;
35402b3c95bSfvdl 	lmp->l_msg_lrpid = bmp->msg_lrpid;
35502b3c95bSfvdl 	lmp->l_msg_stime = bmp->msg_stime;
35602b3c95bSfvdl 	lmp->l_msg_rtime = bmp->msg_rtime;
35702b3c95bSfvdl 	lmp->l_msg_ctime = bmp->msg_ctime;
35802b3c95bSfvdl }
35902b3c95bSfvdl 
360e82000b5Snjoly void
bsd_to_linux_msqid64_ds(struct msqid_ds * bmp,struct linux_msqid64_ds * lmp)361e82000b5Snjoly bsd_to_linux_msqid64_ds(struct msqid_ds *bmp, struct linux_msqid64_ds *lmp)
362e82000b5Snjoly {
363bf54b26cSjoerg 
364bf54b26cSjoerg 	memset(lmp, 0, sizeof(*lmp));
365e82000b5Snjoly 	bsd_to_linux_ipc64_perm(&bmp->msg_perm, &lmp->l_msg_perm);
36639e3203eSmrg 	lmp->l_msg_cbytes = bmp->_msg_cbytes;
367e82000b5Snjoly 	lmp->l_msg_stime = bmp->msg_stime;
368e82000b5Snjoly 	lmp->l_msg_rtime = bmp->msg_rtime;
369e82000b5Snjoly 	lmp->l_msg_ctime = bmp->msg_ctime;
370e82000b5Snjoly 	lmp->l_msg_cbytes = bmp->_msg_cbytes;
371e82000b5Snjoly 	lmp->l_msg_qnum = bmp->msg_qnum;
372e82000b5Snjoly 	lmp->l_msg_qbytes = bmp->msg_qbytes;
373e82000b5Snjoly 	lmp->l_msg_lspid = bmp->msg_lspid;
374e82000b5Snjoly 	lmp->l_msg_lrpid = bmp->msg_lrpid;
375e82000b5Snjoly }
376e82000b5Snjoly 
377d4649701Serh int
linux_sys_msgctl(struct lwp * l,const struct linux_sys_msgctl_args * uap,register_t * retval)3787e2790cfSdsl linux_sys_msgctl(struct lwp *l, const struct linux_sys_msgctl_args *uap, register_t *retval)
3793bf459f3Sfvdl {
3807e2790cfSdsl 	/* {
381d4649701Serh 		syscallarg(int) msqid;
382d4649701Serh 		syscallarg(int) cmd;
383d4649701Serh 		syscallarg(struct linux_msqid_ds *) buf;
3847e2790cfSdsl 	} */
385e82000b5Snjoly 	struct msqid_ds bm, *bmp = NULL;
38602b3c95bSfvdl 	struct linux_msqid_ds lm;
387e82000b5Snjoly 	struct linux_msqid64_ds lm64;
388e82000b5Snjoly 	int cmd, lcmd, error;
38902b3c95bSfvdl 
390e82000b5Snjoly 	lcmd = SCARG(uap, cmd);
391e82000b5Snjoly #ifdef LINUX_IPC_FORCE64
392e82000b5Snjoly 	lcmd |= LINUX_IPC_64;
393e82000b5Snjoly #endif
394e82000b5Snjoly 
395d3dabe12Snjoly 	switch (lcmd & ~LINUX_IPC_64) {
396769c9d47Smycroft 	case LINUX_IPC_STAT:
397e82000b5Snjoly 		cmd = IPC_STAT;
398e82000b5Snjoly 		bmp = &bm;
399e82000b5Snjoly 		break;
40002b3c95bSfvdl 	case LINUX_IPC_SET:
401d3dabe12Snjoly 		if (lcmd & LINUX_IPC_64) {
402d3dabe12Snjoly 			error = copyin(SCARG(uap, buf), &lm64, sizeof lm64);
403e82000b5Snjoly 			linux_to_bsd_msqid64_ds(&lm64, &bm);
404d3dabe12Snjoly 		} else {
405d3dabe12Snjoly 			error = copyin(SCARG(uap, buf), &lm, sizeof lm);
406d3dabe12Snjoly 			linux_to_bsd_msqid_ds(&lm, &bm);
407d3dabe12Snjoly 		}
408d3dabe12Snjoly 		if (error)
409d3dabe12Snjoly 			return error;
410e82000b5Snjoly 		cmd = IPC_SET;
411e82000b5Snjoly 		bmp = &bm;
412e82000b5Snjoly 		break;
413769c9d47Smycroft 	case LINUX_IPC_RMID:
414e82000b5Snjoly 		cmd = IPC_RMID;
415769c9d47Smycroft 		break;
416769c9d47Smycroft 	default:
41702b3c95bSfvdl 		return EINVAL;
4183bf459f3Sfvdl 	}
419e82000b5Snjoly 
420e82000b5Snjoly 	if ((error = msgctl1(l, SCARG(uap, msqid), cmd, bmp)))
421e82000b5Snjoly 		return error;
422e82000b5Snjoly 
423e82000b5Snjoly 	switch (lcmd) {
424e82000b5Snjoly 	case LINUX_IPC_STAT:
425e82000b5Snjoly 		bsd_to_linux_msqid_ds(&bm, &lm);
426e82000b5Snjoly 		error = copyout(&lm, SCARG(uap, buf), sizeof lm);
427e82000b5Snjoly 		break;
428e82000b5Snjoly 	case LINUX_IPC_STAT|LINUX_IPC_64:
429e82000b5Snjoly 		bsd_to_linux_msqid64_ds(&bm, &lm64);
430e82000b5Snjoly 		error = copyout(&lm64, SCARG(uap, buf), sizeof lm64);
431e82000b5Snjoly 		break;
432e82000b5Snjoly 	default:
433e82000b5Snjoly 		break;
434e82000b5Snjoly 	}
435e82000b5Snjoly 
436e82000b5Snjoly 	return error;
437769c9d47Smycroft }
4383bf459f3Sfvdl #endif /* SYSVMSG */
4393bf459f3Sfvdl 
4403bf459f3Sfvdl #ifdef SYSVSHM
4413bf459f3Sfvdl /*
442f64366a2Sjdolecek  * shmget(2). Just make sure the Linux-compatible shmat() semantics
443f64366a2Sjdolecek  * is enabled for the segment, so that shmat() succeeds even when
444f64366a2Sjdolecek  * the segment would be removed.
445f64366a2Sjdolecek  */
446f64366a2Sjdolecek int
linux_sys_shmget(struct lwp * l,const struct linux_sys_shmget_args * uap,register_t * retval)4477e2790cfSdsl linux_sys_shmget(struct lwp *l, const struct linux_sys_shmget_args *uap, register_t *retval)
448f64366a2Sjdolecek {
4497e2790cfSdsl 	/* {
450f64366a2Sjdolecek 		syscallarg(key_t) key;
451f64366a2Sjdolecek 		syscallarg(size_t) size;
452f64366a2Sjdolecek 		syscallarg(int) shmflg;
4537e2790cfSdsl 	} */
4547e2790cfSdsl 	struct sys_shmget_args bsd_ua;
455f64366a2Sjdolecek 
4567e2790cfSdsl 	SCARG(&bsd_ua, key) = SCARG(uap, key);
4577e2790cfSdsl 	SCARG(&bsd_ua, size) = SCARG(uap, size);
4587e2790cfSdsl 	SCARG(&bsd_ua, shmflg) = SCARG(uap, shmflg) | _SHM_RMLINGER;
4597e2790cfSdsl 
4607e2790cfSdsl 	return sys_shmget(l, &bsd_ua, retval);
461f64366a2Sjdolecek }
462f64366a2Sjdolecek 
463f64366a2Sjdolecek /*
4643bf459f3Sfvdl  * shmat(2). Very straightforward, except that Linux passes a pointer
4653bf459f3Sfvdl  * in which the return value is to be passed. This is subsequently
4663bf459f3Sfvdl  * handled by libc, apparently.
4673bf459f3Sfvdl  */
468432f035fSmanu #ifndef __amd64__
469d4649701Serh int
linux_sys_shmat(struct lwp * l,const struct linux_sys_shmat_args * uap,register_t * retval)4707e2790cfSdsl linux_sys_shmat(struct lwp *l, const struct linux_sys_shmat_args *uap, register_t *retval)
4713bf459f3Sfvdl {
4727e2790cfSdsl 	/* {
473d4649701Serh 		syscallarg(int) shmid;
474d4649701Serh 		syscallarg(void *) shmaddr;
475d4649701Serh 		syscallarg(int) shmflg;
476d4649701Serh 		syscallarg(u_long *) raddr;
4777e2790cfSdsl 	} */
4783bf459f3Sfvdl 	int error;
4793bf459f3Sfvdl 
4807e2790cfSdsl 	if ((error = sys_shmat(l, (const void *)uap, retval)))
4813bf459f3Sfvdl 		return error;
4823bf459f3Sfvdl 
4837e2790cfSdsl 	if ((error = copyout(&retval[0], SCARG(uap, raddr), sizeof retval[0])))
4843bf459f3Sfvdl 		return error;
4853bf459f3Sfvdl 
4863bf459f3Sfvdl 	retval[0] = 0;
4873bf459f3Sfvdl 	return 0;
4883bf459f3Sfvdl }
489432f035fSmanu #endif /* __amd64__ */
4903bf459f3Sfvdl 
4913bf459f3Sfvdl /*
4923bf459f3Sfvdl  * Convert between Linux and NetBSD shmid_ds structures.
4933bf459f3Sfvdl  * The order of the fields is once again the difference, and
4943bf459f3Sfvdl  * we also need a place to store the internal data pointer
4953bf459f3Sfvdl  * in, which is unfortunately stored in this structure.
4963bf459f3Sfvdl  *
4973bf459f3Sfvdl  * We abuse a Linux internal field for that.
4983bf459f3Sfvdl  */
499d4649701Serh void
linux_to_bsd_shmid_ds(struct linux_shmid_ds * lsp,struct shmid_ds * bsp)50028bae79bSdsl linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp)
5013bf459f3Sfvdl {
502245f292fSmycroft 
5033bf459f3Sfvdl 	linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm);
5043bf459f3Sfvdl 	bsp->shm_segsz = lsp->l_shm_segsz;
5053bf459f3Sfvdl 	bsp->shm_lpid = lsp->l_shm_lpid;
5063bf459f3Sfvdl 	bsp->shm_cpid = lsp->l_shm_cpid;
5073bf459f3Sfvdl 	bsp->shm_nattch = lsp->l_shm_nattch;
5083bf459f3Sfvdl 	bsp->shm_atime = lsp->l_shm_atime;
5093bf459f3Sfvdl 	bsp->shm_dtime = lsp->l_shm_dtime;
5103bf459f3Sfvdl 	bsp->shm_ctime = lsp->l_shm_ctime;
5113bf459f3Sfvdl }
5123bf459f3Sfvdl 
513d4649701Serh void
linux_to_bsd_shmid64_ds(struct linux_shmid64_ds * lsp,struct shmid_ds * bsp)51428bae79bSdsl linux_to_bsd_shmid64_ds(struct linux_shmid64_ds *lsp, struct shmid_ds *bsp)
51565de380aSchristos {
51665de380aSchristos 
51765de380aSchristos 	linux_to_bsd_ipc64_perm(&lsp->l_shm_perm, &bsp->shm_perm);
51865de380aSchristos 	bsp->shm_segsz = lsp->l_shm_segsz;
51965de380aSchristos 	bsp->shm_lpid = lsp->l_shm_lpid;
52065de380aSchristos 	bsp->shm_cpid = lsp->l_shm_cpid;
52165de380aSchristos 	bsp->shm_nattch = lsp->l_shm_nattch;
52265de380aSchristos 	bsp->shm_atime = lsp->l_shm_atime;
52365de380aSchristos 	bsp->shm_dtime = lsp->l_shm_dtime;
52465de380aSchristos 	bsp->shm_ctime = lsp->l_shm_ctime;
52565de380aSchristos }
52665de380aSchristos 
52765de380aSchristos void
bsd_to_linux_shmid_ds(struct shmid_ds * bsp,struct linux_shmid_ds * lsp)52828bae79bSdsl bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp)
5293bf459f3Sfvdl {
530245f292fSmycroft 
53139e3203eSmrg 	memset(lsp, 0, sizeof *lsp);
5323bf459f3Sfvdl 	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm);
5333bf459f3Sfvdl 	lsp->l_shm_segsz = bsp->shm_segsz;
5343bf459f3Sfvdl 	lsp->l_shm_lpid = bsp->shm_lpid;
5353bf459f3Sfvdl 	lsp->l_shm_cpid = bsp->shm_cpid;
5363bf459f3Sfvdl 	lsp->l_shm_nattch = bsp->shm_nattch;
5373bf459f3Sfvdl 	lsp->l_shm_atime = bsp->shm_atime;
5383bf459f3Sfvdl 	lsp->l_shm_dtime = bsp->shm_dtime;
5393bf459f3Sfvdl 	lsp->l_shm_ctime = bsp->shm_ctime;
5403bf459f3Sfvdl }
5413bf459f3Sfvdl 
54265de380aSchristos void
bsd_to_linux_shmid64_ds(struct shmid_ds * bsp,struct linux_shmid64_ds * lsp)54328bae79bSdsl bsd_to_linux_shmid64_ds(struct shmid_ds *bsp, struct linux_shmid64_ds *lsp)
54465de380aSchristos {
54539e3203eSmrg 
54639e3203eSmrg 	memset(lsp, 0, sizeof *lsp);
54765de380aSchristos 	bsd_to_linux_ipc64_perm(&bsp->shm_perm, &lsp->l_shm_perm);
54865de380aSchristos 	lsp->l_shm_segsz = bsp->shm_segsz;
54965de380aSchristos 	lsp->l_shm_lpid = bsp->shm_lpid;
55065de380aSchristos 	lsp->l_shm_cpid = bsp->shm_cpid;
55165de380aSchristos 	lsp->l_shm_nattch = bsp->shm_nattch;
55265de380aSchristos 	lsp->l_shm_atime = bsp->shm_atime;
55365de380aSchristos 	lsp->l_shm_dtime = bsp->shm_dtime;
55465de380aSchristos 	lsp->l_shm_ctime = bsp->shm_ctime;
55565de380aSchristos }
55665de380aSchristos 
5573bf459f3Sfvdl /*
55869614dfeSnjoly  * shmctl.
5593bf459f3Sfvdl  *
5603bf459f3Sfvdl  * The usual structure conversion and massaging is done.
5613bf459f3Sfvdl  */
562d4649701Serh int
linux_sys_shmctl(struct lwp * l,const struct linux_sys_shmctl_args * uap,register_t * retval)5637e2790cfSdsl linux_sys_shmctl(struct lwp *l, const struct linux_sys_shmctl_args *uap, register_t *retval)
5643bf459f3Sfvdl {
5657e2790cfSdsl 	/* {
566d4649701Serh 		syscallarg(int) shmid;
567d4649701Serh 		syscallarg(int) cmd;
568d4649701Serh 		syscallarg(struct linux_shmid_ds *) buf;
5697e2790cfSdsl 	} */
570c271f319Sdsl 	struct shmid_ds bs;
571*542f82ceSmaxv 	struct ipc_perm perm;
572769c9d47Smycroft 	struct linux_shmid_ds ls;
57365de380aSchristos 	struct linux_shmid64_ds ls64;
57465de380aSchristos 	struct linux_shminfo64 lsi64;
57565de380aSchristos 	struct linux_shm_info lsi;
57629158b16Snjoly 	int error, i, cmd, shmid;
5773bf459f3Sfvdl 
57829158b16Snjoly 	shmid = SCARG(uap, shmid);
57965de380aSchristos 	cmd = SCARG(uap, cmd);
580f1bd64daSnjoly #ifdef LINUX_IPC_FORCE64
5814eecf433Snjoly 	cmd |= LINUX_IPC_64;
5824eecf433Snjoly #endif
58329158b16Snjoly 
584a1cf1f2eSnjoly 	switch (cmd & ~LINUX_IPC_64) {
58565de380aSchristos 	case LINUX_SHM_STAT:
586*542f82ceSmaxv 		error = shm_find_segment_perm_by_index(shmid, &perm);
587*542f82ceSmaxv 		if (error)
588*542f82ceSmaxv 			return error;
589*542f82ceSmaxv 		shmid = IXSEQ_TO_IPCID(shmid, perm);
59029158b16Snjoly 		retval[0] = shmid;
591a1cf1f2eSnjoly 		/*FALLTHROUGH*/
59265de380aSchristos 
593a1cf1f2eSnjoly 	case LINUX_IPC_STAT:
59429158b16Snjoly 		error = shmctl1(l, shmid, IPC_STAT, &bs);
595c271f319Sdsl 		if (error != 0)
59665de380aSchristos 			return error;
597a1cf1f2eSnjoly 		if (cmd & LINUX_IPC_64) {
59865de380aSchristos 			bsd_to_linux_shmid64_ds(&bs, &ls64);
599a1cf1f2eSnjoly 			error = copyout(&ls64, SCARG(uap, buf), sizeof ls64);
600a1cf1f2eSnjoly 		} else {
601a1cf1f2eSnjoly 			bsd_to_linux_shmid_ds(&bs, &ls);
602a1cf1f2eSnjoly 			error = copyout(&ls, SCARG(uap, buf), sizeof ls);
603a1cf1f2eSnjoly 		}
604a1cf1f2eSnjoly 		return error;
60565de380aSchristos 
6063bf459f3Sfvdl 	case LINUX_IPC_SET:
607a1cf1f2eSnjoly 		if (cmd & LINUX_IPC_64) {
608a1cf1f2eSnjoly 			error = copyin(SCARG(uap, buf), &ls64, sizeof ls64);
609d8f89665Snjoly 			linux_to_bsd_shmid64_ds(&ls64, &bs);
610a1cf1f2eSnjoly 		} else {
611a1cf1f2eSnjoly 			error = copyin(SCARG(uap, buf), &ls, sizeof ls);
612a1cf1f2eSnjoly 			linux_to_bsd_shmid_ds(&ls, &bs);
613a1cf1f2eSnjoly 		}
614a1cf1f2eSnjoly 		if (error != 0)
615a1cf1f2eSnjoly 			return error;
616d8f89665Snjoly 		return shmctl1(l, shmid, IPC_SET, &bs);
617d8f89665Snjoly 
6183bf459f3Sfvdl 	case LINUX_IPC_RMID:
61929158b16Snjoly 		return shmctl1(l, shmid, IPC_RMID, NULL);
62065de380aSchristos 
6213bf459f3Sfvdl 	case LINUX_SHM_LOCK:
62229158b16Snjoly 		return shmctl1(l, shmid, SHM_LOCK, NULL);
62365de380aSchristos 
6243bf459f3Sfvdl 	case LINUX_SHM_UNLOCK:
62529158b16Snjoly 		return shmctl1(l, shmid, SHM_UNLOCK, NULL);
62665de380aSchristos 
6273bf459f3Sfvdl 	case LINUX_IPC_INFO:
62865de380aSchristos 		memset(&lsi64, 0, sizeof lsi64);
62965de380aSchristos 		lsi64.l_shmmax = shminfo.shmmax;
63065de380aSchristos 		lsi64.l_shmmin = shminfo.shmmin;
63165de380aSchristos 		lsi64.l_shmmni = shminfo.shmmni;
63265de380aSchristos 		lsi64.l_shmseg = shminfo.shmseg;
63365de380aSchristos 		lsi64.l_shmall = shminfo.shmall;
63429158b16Snjoly 		for (i = shminfo.shmmni - 1; i > 0; i--)
63529158b16Snjoly 			if (shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED)
63629158b16Snjoly 				break;
63729158b16Snjoly 		retval[0] = i;
63865de380aSchristos 		return copyout(&lsi64, SCARG(uap, buf), sizeof lsi64);
63965de380aSchristos 
6403bf459f3Sfvdl 	case LINUX_SHM_INFO:
64165de380aSchristos 		(void)memset(&lsi, 0, sizeof lsi);
64265de380aSchristos 		lsi.l_used_ids = shm_nused;
64365de380aSchristos 		for (i = 0; i < shminfo.shmmni; i++)
64465de380aSchristos 			if (shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED)
64529158b16Snjoly 				lsi.l_shm_tot +=
64629158b16Snjoly 				    round_page(shmsegs[i].shm_segsz) /
64729158b16Snjoly 				    uvmexp.pagesize;
64865de380aSchristos 		lsi.l_shm_rss = 0;
64965de380aSchristos 		lsi.l_shm_swp = 0;
65065de380aSchristos 		lsi.l_swap_attempts = 0;
65165de380aSchristos 		lsi.l_swap_successes = 0;
65229158b16Snjoly 		for (i = shminfo.shmmni - 1; i > 0; i--)
65329158b16Snjoly 			if (shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED)
65429158b16Snjoly 				break;
65529158b16Snjoly 		retval[0] = i;
65665de380aSchristos 		return copyout(&lsi, SCARG(uap, buf), sizeof lsi);
65765de380aSchristos 
6583bf459f3Sfvdl 	default:
65965de380aSchristos #ifdef DEBUG
66065de380aSchristos 		printf("linux_sys_shmctl cmd %d\n", SCARG(uap, cmd));
66165de380aSchristos #endif
6623bf459f3Sfvdl 		return EINVAL;
6633bf459f3Sfvdl 	}
6643bf459f3Sfvdl }
6653bf459f3Sfvdl #endif /* SYSVSHM */
666