linux_ipccall.c revision 1.8 1 /* $NetBSD: linux_ipccall.c,v 1.8 1995/10/07 06:27:09 mycroft 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 #endif
79
80 #ifdef SYSVMSG
81 static int linux_msgsnd __P((struct proc *, struct linux_sys_ipc_args *,
82 register_t *));
83 static int linux_msgrcv __P((struct proc *, struct linux_sys_ipc_args *,
84 register_t *));
85 static int linux_msgop __P((struct proc *, struct linux_sys_ipc_args *,
86 register_t *));
87 static int linux_msgctl __P((struct proc *, struct linux_sys_ipc_args *,
88 register_t *));
89 #endif
90
91 #ifdef SYSVSHM
92 static int linux_shmat __P((struct proc *, struct linux_sys_ipc_args *,
93 register_t *));
94 static int linux_shmdt __P((struct proc *, struct linux_sys_ipc_args *,
95 register_t *));
96 static int linux_shmget __P((struct proc *, struct linux_sys_ipc_args *,
97 register_t *));
98 static int linux_shmctl __P((struct proc *, struct linux_sys_ipc_args *,
99 register_t *));
100 #endif
101
102
103 int
104 linux_sys_ipc(p, v, retval)
105 struct proc *p;
106 void *v;
107 register_t *retval;
108 {
109 struct linux_sys_ipc_args /* {
110 syscallarg(int) what;
111 syscallarg(int) a1;
112 syscallarg(int) a2;
113 syscallarg(int) a3;
114 syscallarg(caddr_t) ptr;
115 } */ *uap = v;
116 int what, error;
117
118 switch (SCARG(uap, what)) {
119 #ifdef SYSVSEM
120 case LINUX_SYS_semop:
121 return linux_semop(p, uap, retval);
122 case LINUX_SYS_semget:
123 return linux_semget(p, uap, retval);
124 case LINUX_SYS_semctl:
125 return linux_semctl(p, uap, retval);
126 #endif
127 #ifdef SYSVMSG
128 case LINUX_SYS_msgsnd:
129 return linux_msgsnd(p, uap, retval);
130 case LINUX_SYS_msgrcv:
131 return linux_msgrcv(p, uap, retval);
132 case LINUX_SYS_msgget:
133 return linux_msgget(p, uap, retval);
134 case LINUX_SYS_msgctl:
135 return linux_msgctl(p, uap, retval);
136 #endif
137 #ifdef SYSVSHM
138 case LINUX_SYS_shmat:
139 return linux_shmat(p, uap, retval);
140 case LINUX_SYS_shmdt:
141 return linux_shmdt(p, uap, retval);
142 case LINUX_SYS_shmget:
143 return linux_shmget(p, uap, retval);
144 case LINUX_SYS_shmctl:
145 return linux_shmctl(p, uap, retval);
146 #endif
147 default:
148 return ENOSYS;
149 }
150 }
151
152 /*
153 * Convert between Linux and NetBSD ipc_perm structures. Only the
154 * order of the fields is different.
155 */
156 static void
157 linux_to_bsd_ipc_perm(lpp, bpp)
158 struct linux_ipc_perm *lpp;
159 struct ipc_perm *bpp;
160 {
161
162 bpp->key = lpp->l_key;
163 bpp->uid = lpp->l_uid;
164 bpp->gid = lpp->l_gid;
165 bpp->cuid = lpp->l_cuid;
166 bpp->cgid = lpp->l_cgid;
167 bpp->mode = lpp->l_mode;
168 bpp->seq = lpp->l_seq;
169 }
170
171 static void
172 bsd_to_linux_ipc_perm(bpp, lpp)
173 struct ipc_perm *bpp;
174 struct linux_ipc_perm *lpp;
175 {
176
177 lpp->l_key = bpp->key;
178 lpp->l_uid = bpp->uid;
179 lpp->l_gid = bpp->gid;
180 lpp->l_cuid = bpp->cuid;
181 lpp->l_cgid = bpp->cgid;
182 lpp->l_mode = bpp->mode;
183 lpp->l_seq = bpp->seq;
184 }
185
186 #ifdef SYSVSEM
187 /*
188 * Semaphore operations. Most constants and structures are the same on
189 * both systems. Only semctl() needs some extra work.
190 */
191
192 /*
193 * Convert between Linux and NetBSD semid_ds structures.
194 */
195 static void
196 bsd_to_linux_semid_ds(bs, ls)
197 struct semid_ds *bs;
198 struct linux_semid_ds *ls;
199 {
200
201 bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm);
202 ls->l_sem_otime = bs->sem_otime;
203 ls->l_sem_ctime = bs->sem_ctime;
204 ls->l_sem_nsems = bs->sem_nsems;
205 ls->l_sem_base = bs->sem_base;
206 }
207
208 static void
209 linux_to_bsd_semid_ds(ls, bs)
210 struct linux_semid_ds *ls;
211 struct semid_ds *bs;
212 {
213
214 linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm);
215 bs->sem_otime = ls->l_sem_otime;
216 bs->sem_ctime = ls->l_sem_ctime;
217 bs->sem_nsems = ls->l_sem_nsems;
218 bs->sem_base = ls->l_sem_base;
219 }
220
221 int
222 linux_semop(p, uap, retval)
223 struct proc *p;
224 struct linux_sys_ipc_args /* {
225 syscallarg(int) what;
226 syscallarg(int) a1;
227 syscallarg(int) a2;
228 syscallarg(int) a3;
229 syscallarg(caddr_t) ptr;
230 } */ *uap;
231 register_t *retval;
232 {
233 struct sys_semop_args bsa;
234
235 SCARG(&bsa, semid) = SCARG(uap, a1);
236 SCARG(&bsa, sops) = (struct sembuf *)SCARG(uap, ptr);
237 SCARG(&bsa, nsops) = SCARG(uap, a2);
238
239 return sys_semop(p, &bsa, retval);
240 }
241
242 int
243 linux_semget(p, uap, retval)
244 struct proc *p;
245 struct linux_sys_ipc_args /* {
246 syscallarg(int) what;
247 syscallarg(int) a1;
248 syscallarg(int) a2;
249 syscallarg(int) a3;
250 syscallarg(caddr_t) ptr;
251 } */ *uap;
252 register_t *retval;
253 {
254 struct sys_semget_args bsa;
255
256 SCARG(&bsa, key) = (key_t)SCARG(uap, a1);
257 SCARG(&bsa, nsems) = SCARG(uap, a2);
258 SCARG(&bsa, semflg) = SCARG(uap, a3);
259
260 return sys_semget(p, &bsa, retval);
261 }
262
263 /*
264 * Most of this can be handled by directly passing the arguments on,
265 * buf IPC_* require a lot of copy{in,out} because of the extra indirection
266 * (we are passed a pointer to a union cointaining a pointer to a semid_ds
267 * structure.
268 */
269 int
270 linux_semctl(p, uap, retval)
271 struct proc *p;
272 struct linux_sys_ipc_args /* {
273 syscallarg(int) what;
274 syscallarg(int) a1;
275 syscallarg(int) a2;
276 syscallarg(int) a3;
277 syscallarg(caddr_t) ptr;
278 } */ *uap;
279 register_t *retval;
280 {
281 caddr_t sg, unptr, dsp, ldsp;
282 int error, cmd;
283 struct sys___semctl_args bsa;
284 struct linux_semid_ds lm;
285 struct semid_ds bm;
286
287 SCARG(&bsa, semid) = SCARG(uap, a1);
288 SCARG(&bsa, semnum) = SCARG(uap, a2);
289 SCARG(&bsa, cmd) = SCARG(uap, a3);
290 SCARG(&bsa, arg) = (union semun *)SCARG(uap, ptr);
291 switch(SCARG(uap, a3)) {
292 case LINUX_GETVAL:
293 cmd = GETVAL;
294 break;
295 case LINUX_GETPID:
296 cmd = GETPID;
297 break;
298 case LINUX_GETNCNT:
299 cmd = GETNCNT;
300 break;
301 case LINUX_GETZCNT:
302 cmd = GETZCNT;
303 break;
304 case LINUX_SETVAL:
305 cmd = SETVAL;
306 break;
307 case LINUX_IPC_RMID:
308 cmd = IPC_RMID;
309 break;
310 case LINUX_IPC_SET:
311 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp)))
312 return error;
313 if ((error = copyin(ldsp, (caddr_t)&lm, sizeof lm)))
314 return error;
315 linux_to_bsd_semid_ds(&lm, &bm);
316 sg = stackgap_init(p->p_emul);
317 unptr = stackgap_alloc(&sg, sizeof (union semun));
318 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds));
319 if ((error = copyout((caddr_t)&bm, dsp, sizeof bm)))
320 return error;
321 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp)))
322 return error;
323 SCARG(&bsa, arg) = (union semun *)unptr;
324 return sys___semctl(p, &bsa, retval);
325 case LINUX_IPC_STAT:
326 sg = stackgap_init(p->p_emul);
327 unptr = stackgap_alloc(&sg, sizeof (union semun *));
328 dsp = stackgap_alloc(&sg, sizeof (struct semid_ds));
329 if ((error = copyout((caddr_t)&dsp, unptr, sizeof dsp)))
330 return error;
331 SCARG(&bsa, arg) = (union semun *)unptr;
332 if ((error = sys___semctl(p, &bsa, retval)))
333 return error;
334 if ((error = copyin(dsp, (caddr_t)&bm, sizeof bm)))
335 return error;
336 bsd_to_linux_semid_ds(&bm, &lm);
337 if ((error = copyin(SCARG(uap, ptr), &ldsp, sizeof ldsp)))
338 return error;
339 return copyout((caddr_t)&lm, ldsp, sizeof lm);
340 default:
341 return EINVAL;
342 }
343 SCARG(&bsa, cmd) = cmd;
344
345 return sys___semctl(p, &bsa, retval);
346 }
347 #endif /* SYSVSEM */
348
349 #ifdef SYSVMSG
350
351 static void
352 linux_to_bsd_msqid_ds(lmp, bmp)
353 struct linux_msqid_ds *lmp;
354 struct msqid_ds *bmp;
355 {
356
357 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm);
358 bmp->msg_first = lmp->l_msg_first;
359 bmp->msg_last = lmp->l_msg_last;
360 bmp->msg_cbytes = lmp->l_msg_cbytes;
361 bmp->msg_qnum = lmp->l_msg_qnum;
362 bmp->msg_qbytes = lmp->l_msg_qbytes;
363 bmp->msg_lspid = lmp->l_msg_lspid;
364 bmp->msg_lrpid = lmp->l_msg_lrpid;
365 bmp->msg_stime = lmp->l_msg_stime;
366 bmp->msg_rtime = lmp->l_msg_rtime;
367 bmp->msg_ctime = lmp->l_msg_ctime;
368 }
369
370 static void
371 bsd_to_linux_msqid_ds(bmp, lmp)
372 struct msqid_ds *bmp;
373 struct linux_msqid_ds *lmp;
374 {
375
376 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm);
377 lmp->l_msg_first = bmp->msg_first;
378 lmp->l_msg_last = bmp->msg_last;
379 lmp->l_msg_cbytes = bmp->msg_cbytes;
380 lmp->l_msg_qnum = bmp->msg_qnum;
381 lmp->l_msg_qbytes = bmp->msg_qbytes;
382 lmp->l_msg_lspid = bmp->msg_lspid;
383 lmp->l_msg_lrpid = bmp->msg_lrpid;
384 lmp->l_msg_stime = bmp->msg_stime;
385 lmp->l_msg_rtime = bmp->msg_rtime;
386 lmp->l_msg_ctime = bmp->msg_ctime;
387 }
388
389 int
390 linux_msgsnd(p, uap, retval)
391 struct proc *p;
392 struct linux_sys_ipc_args /* {
393 syscallarg(int) what;
394 syscallarg(int) a1;
395 syscallarg(int) a2;
396 syscallarg(int) a3;
397 syscallarg(caddr_t) ptr;
398 } */ *uap;
399 register_t *retval;
400 {
401 struct sys_msgsnd_args bma;
402
403 SCARG(&bma, msqid) = SCARG(uap, a1);
404 SCARG(&bma, msgp) = SCARG(uap, ptr);
405 SCARG(&bma, msgsz) = SCARG(uap, a2);
406 SCARG(&bma, msgflg) = SCARG(uap, a3);
407
408 return sys_msgsnd(p, &bma, retval);
409 }
410
411 int
412 linux_msgrcv(p, uap, retval)
413 struct proc *p;
414 struct linux_sys_ipc_args /* {
415 syscallarg(int) what;
416 syscallarg(int) a1;
417 syscallarg(int) a2;
418 syscallarg(int) a3;
419 syscallarg(caddr_t) ptr;
420 } */ *uap;
421 register_t *retval;
422 {
423 struct sys_msgrcv_args bma;
424 struct linux_msgrcv_msgarg kluge;
425 int error;
426
427 if ((error = copyin(SCARG(uap, ptr), &kluge, sizeof kluge)))
428 return error;
429
430 SCARG(&bma, msqid) = SCARG(uap, a1);
431 SCARG(&bma, msgp) = kluge.msg;
432 SCARG(&bma, msgsz) = SCARG(uap, a2);
433 SCARG(&bma, msgtyp) = kluge.type;
434 SCARG(&bma, msgflg) = SCARG(uap, a3);
435
436 return sys_msgrcv(p, &bma, retval);
437 }
438
439 int
440 linux_msgget(p, uap, retval)
441 struct proc *p;
442 struct linux_sys_ipc_args /* {
443 syscallarg(int) what;
444 syscallarg(int) a1;
445 syscallarg(int) a2;
446 syscallarg(int) a3;
447 syscallarg(caddr_t) ptr;
448 } */ *uap;
449 register_t *retval;
450 {
451 struct sys_msgget_args bma;
452
453 SCARG(&bma, key) = (key_t)SCARG(uap, a1);
454 SCARG(&bma, msgflg) = SCARG(uap, a2);
455
456 return sys_msgget(p, &bma, retval);
457 }
458
459 int
460 linux_msgctl(p, uap, retval)
461 struct proc *p;
462 struct linux_sys_ipc_args /* {
463 syscallarg(int) what;
464 syscallarg(int) a1;
465 syscallarg(int) a2;
466 syscallarg(int) a3;
467 syscallarg(caddr_t) ptr;
468 } */ *uap;
469 register_t *retval;
470 {
471 struct sys_msgctl_args bma;
472 caddr_t umsgptr, sg;
473 struct linux_msqid_ds lm;
474 struct msqid_ds bm;
475 int error;
476
477 SCARG(&bma, msqid) = SCARG(uap, a1);
478 SCARG(&bma, cmd) = SCARG(uap, a2);
479 switch (SCARG(uap, a2)) {
480 case LINUX_IPC_RMID:
481 return sys_msgctl(p, &bma, retval);
482 case LINUX_IPC_SET:
483 if ((error = copyin(SCARG(uap, ptr), (caddr_t)&lm, sizeof lm)))
484 return error;
485 linux_to_bsd_msqid_ds(&lm, &bm);
486 sg = stackgap_init(p->p_emul);
487 umsgptr = stackgap_alloc(&sg, sizeof bm);
488 if ((error = copyout((caddr_t)&bm, umsgptr, sizeof bm)))
489 return error;
490 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr;
491 return sys_msgctl(p, &bma, retval);
492 case LINUX_IPC_STAT:
493 sg = stackgap_init(p->p_emul);
494 umsgptr = stackgap_alloc(&sg, sizeof (struct msqid_ds));
495 SCARG(&bma, buf) = (struct msqid_ds *)umsgptr;
496 if ((error = sys_msgctl(p, &bma, retval)))
497 return error;
498 if ((error = copyin(umsgptr, (caddr_t)&bm, sizeof bm)))
499 return error;
500 bsd_to_linux_msqid_ds(&bm, &lm);
501 return copyout((caddr_t)&lm, SCARG(uap, ptr), sizeof lm);
502 }
503 return EINVAL;
504 }
505 #endif /* SYSVMSG */
506
507 #ifdef SYSVSHM
508 /*
509 * shmat(2). Very straightforward, except that Linux passes a pointer
510 * in which the return value is to be passed. This is subsequently
511 * handled by libc, apparently.
512 */
513 int
514 linux_shmat(p, uap, retval)
515 struct proc *p;
516 struct linux_sys_ipc_args /* {
517 syscallarg(int) what;
518 syscallarg(int) a1;
519 syscallarg(int) a2;
520 syscallarg(int) a3;
521 syscallarg(caddr_t) ptr;
522 } */ *uap;
523 register_t *retval;
524 {
525 struct sys_shmat_args bsa;
526 int error;
527
528 SCARG(&bsa, shmid) = SCARG(uap, a1);
529 SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
530 SCARG(&bsa, shmflg) = SCARG(uap, a2);
531
532 if ((error = sys_shmat(p, &bsa, retval)))
533 return error;
534
535 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3),
536 sizeof retval[0])))
537 return error;
538
539 retval[0] = 0;
540 return 0;
541 }
542
543 /*
544 * shmdt(): this could have been mapped directly, if it wasn't for
545 * the extra indirection by the linux_ipc system call.
546 */
547 int
548 linux_shmdt(p, uap, retval)
549 struct proc *p;
550 struct linux_sys_ipc_args /* {
551 syscallarg(int) what;
552 syscallarg(int) a1;
553 syscallarg(int) a2;
554 syscallarg(int) a3;
555 syscallarg(caddr_t) ptr;
556 } */ *uap;
557 register_t *retval;
558 {
559 struct sys_shmdt_args bsa;
560
561 SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
562
563 return sys_shmdt(p, &bsa, retval);
564 }
565
566 /*
567 * Same story as shmdt.
568 */
569 int
570 linux_shmget(p, uap, retval)
571 struct proc *p;
572 struct linux_sys_ipc_args /* {
573 syscallarg(int) what;
574 syscallarg(int) a1;
575 syscallarg(int) a2;
576 syscallarg(int) a3;
577 syscallarg(caddr_t) ptr;
578 } */ *uap;
579 register_t *retval;
580 {
581 struct sys_shmget_args bsa;
582
583 SCARG(&bsa, key) = SCARG(uap, a1);
584 SCARG(&bsa, size) = SCARG(uap, a2);
585 SCARG(&bsa, shmflg) = SCARG(uap, a3);
586
587 return sys_shmget(p, &bsa, retval);
588 }
589
590 /*
591 * Convert between Linux and NetBSD shmid_ds structures.
592 * The order of the fields is once again the difference, and
593 * we also need a place to store the internal data pointer
594 * in, which is unfortunately stored in this structure.
595 *
596 * We abuse a Linux internal field for that.
597 */
598 static void
599 linux_to_bsd_shmid_ds(lsp, bsp)
600 struct linux_shmid_ds *lsp;
601 struct shmid_ds *bsp;
602 {
603
604 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm);
605 bsp->shm_segsz = lsp->l_shm_segsz;
606 bsp->shm_lpid = lsp->l_shm_lpid;
607 bsp->shm_cpid = lsp->l_shm_cpid;
608 bsp->shm_nattch = lsp->l_shm_nattch;
609 bsp->shm_atime = lsp->l_shm_atime;
610 bsp->shm_dtime = lsp->l_shm_dtime;
611 bsp->shm_ctime = lsp->l_shm_ctime;
612 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */
613 }
614
615 static void
616 bsd_to_linux_shmid_ds(bsp, lsp)
617 struct shmid_ds *bsp;
618 struct linux_shmid_ds *lsp;
619 {
620
621 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm);
622 lsp->l_shm_segsz = bsp->shm_segsz;
623 lsp->l_shm_lpid = bsp->shm_lpid;
624 lsp->l_shm_cpid = bsp->shm_cpid;
625 lsp->l_shm_nattch = bsp->shm_nattch;
626 lsp->l_shm_atime = bsp->shm_atime;
627 lsp->l_shm_dtime = bsp->shm_dtime;
628 lsp->l_shm_ctime = bsp->shm_ctime;
629 lsp->l_private2 = bsp->shm_internal; /* XXX */
630 }
631
632 /*
633 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT
634 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented
635 * by NetBSD itself.
636 *
637 * The usual structure conversion and massaging is done.
638 */
639 int
640 linux_shmctl(p, uap, retval)
641 struct proc *p;
642 struct linux_sys_ipc_args /* {
643 syscallarg(int) what;
644 syscallarg(int) a1;
645 syscallarg(int) a2;
646 syscallarg(int) a3;
647 syscallarg(caddr_t) ptr;
648 } */ *uap;
649 register_t *retval;
650 {
651 int error;
652 caddr_t sg;
653 struct sys_shmctl_args bsa;
654 struct shmid_ds *bsp, bs;
655 struct linux_shmid_ds lseg;
656
657 switch (SCARG(uap, a2)) {
658 case LINUX_IPC_STAT:
659 sg = stackgap_init(p->p_emul);
660 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
661 SCARG(&bsa, shmid) = SCARG(uap, a1);
662 SCARG(&bsa, cmd) = IPC_STAT;
663 SCARG(&bsa, buf) = bsp;
664 if ((error = sys_shmctl(p, &bsa, retval)))
665 return error;
666 if ((error = copyin((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
667 return error;
668 bsd_to_linux_shmid_ds(&bs, &lseg);
669 return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg);
670 case LINUX_IPC_SET:
671 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg,
672 sizeof lseg)))
673 return error;
674 linux_to_bsd_shmid_ds(&lseg, &bs);
675 sg = stackgap_init(p->p_emul);
676 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
677 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
678 return error;
679 SCARG(&bsa, shmid) = SCARG(uap, a1);
680 SCARG(&bsa, cmd) = IPC_SET;
681 SCARG(&bsa, buf) = bsp;
682 return sys_shmctl(p, &bsa, retval);
683 case LINUX_IPC_RMID:
684 case LINUX_SHM_LOCK:
685 case LINUX_SHM_UNLOCK:
686 SCARG(&bsa, shmid) = SCARG(uap, a1);
687 switch (SCARG(uap, a2)) {
688 case LINUX_IPC_RMID:
689 SCARG(&bsa, cmd) = IPC_RMID;
690 break;
691 case LINUX_SHM_LOCK:
692 SCARG(&bsa, cmd) = SHM_LOCK;
693 break;
694 case LINUX_SHM_UNLOCK:
695 SCARG(&bsa, cmd) = SHM_UNLOCK;
696 break;
697 }
698 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg,
699 sizeof lseg)))
700 return error;
701 linux_to_bsd_shmid_ds(&lseg, &bs);
702 sg = stackgap_init(p->p_emul);
703 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
704 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
705 return error;
706 SCARG(&bsa, buf) = bsp;
707 return sys_shmctl(p, &bsa, retval);
708 case LINUX_IPC_INFO:
709 case LINUX_SHM_STAT:
710 case LINUX_SHM_INFO:
711 default:
712 return EINVAL;
713 }
714 }
715 #endif /* SYSVSHM */
716