xref: /netbsd-src/sys/compat/linux/common/linux_ipc.c (revision 9573504567626934c7ee01c7dce0c4bb1dfe7403)
1 /*	$NetBSD: linux_ipc.c,v 1.9 1995/10/08 22:49:29 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_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 		SCARG(&bsa, buf) = NULL;
699 		return sys_shmctl(p, &bsa, retval);
700 	case LINUX_IPC_INFO:
701 	case LINUX_SHM_STAT:
702 	case LINUX_SHM_INFO:
703 	default:
704 		return EINVAL;
705 	}
706 }
707 #endif /* SYSVSHM */
708