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