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