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