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