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