linux_ipccall.c revision 1.5 1 /* $NetBSD: linux_ipccall.c,v 1.5 1995/08/14 01:27:52 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/msg.h>
39 #include <sys/proc.h>
40 #include <sys/uio.h>
41 #include <sys/time.h>
42 #include <sys/malloc.h>
43 #include <sys/mman.h>
44 #include <sys/systm.h>
45 #include <sys/stat.h>
46
47 #include <sys/mount.h>
48 #include <sys/syscallargs.h>
49
50 #include <compat/linux/linux_types.h>
51 #include <compat/linux/linux_signal.h>
52 #include <compat/linux/linux_syscallargs.h>
53 #include <compat/linux/linux_util.h>
54 #include <compat/linux/linux_ipc.h>
55 #include <compat/linux/linux_msg.h>
56 #include <compat/linux/linux_shm.h>
57 #include <compat/linux/linux_ipccall.h>
58
59 /*
60 * Stuff to deal with the SysV ipc/shm/semaphore interface in Linux.
61 * The main difference is, that Linux handles it all via one
62 * system call, which has the usual maximum amount of 5 arguments.
63 * This results in a kludge for calls that take 6 of them.
64 *
65 * The SYSVXXXX options have to be enabled to get the appropriate
66 * functions to work.
67 */
68
69 #ifdef SYSVSEM
70 static int linux_semop __P((struct proc *, struct linux_ipc_args *,
71 register_t *));
72 static int linux_semget __P((struct proc *, struct linux_ipc_args *,
73 register_t *));
74 static int linux_semctl __P((struct proc *, struct linux_ipc_args *,
75 register_t *));
76 #endif
77
78 #ifdef SYSVMSG
79 static int linux_msgsnd __P((struct proc *, struct linux_ipc_args *,
80 register_t *));
81 static int linux_msgrcv __P((struct proc *, struct linux_ipc_args *,
82 register_t *));
83 static int linux_msgop __P((struct proc *, struct linux_ipc_args *,
84 register_t *));
85 static int linux_msgctl __P((struct proc *, struct linux_ipc_args *,
86 register_t *));
87 #endif
88
89 #ifdef SYSVSHM
90 static int linux_shmat __P((struct proc *, struct linux_ipc_args *,
91 register_t *));
92 static int linux_shmdt __P((struct proc *, struct linux_ipc_args *,
93 register_t *));
94 static int linux_shmget __P((struct proc *, struct linux_ipc_args *,
95 register_t *));
96 static int linux_shmctl __P((struct proc *, struct linux_ipc_args *,
97 register_t *));
98 #endif
99
100
101 int
102 linux_ipc(p, uap, retval)
103 struct proc *p;
104 struct linux_ipc_args /* {
105 syscallarg(int) what;
106 syscallarg(int) a1;
107 syscallarg(int) a2;
108 syscallarg(int) a3;
109 syscallarg(caddr_t) ptr;
110 } */ *uap;
111 register_t *retval;
112 {
113 int what, error;
114
115 switch (SCARG(uap, what)) {
116 #ifdef SYSVSEM
117 case LINUX_SYS_semop:
118 return linux_semop(p, uap, retval);
119 case LINUX_SYS_semget:
120 return linux_semget(p, uap, retval);
121 case LINUX_SYS_semctl:
122 return linux_semctl(p, uap, retval);
123 #endif
124 #ifdef SYSVMSG
125 case LINUX_SYS_msgsnd:
126 return linux_msgsnd(p, uap, retval);
127 case LINUX_SYS_msgrcv:
128 return linux_msgrcv(p, uap, retval);
129 case LINUX_SYS_msgget:
130 return linux_msgget(p, uap, retval);
131 case LINUX_SYS_msgctl:
132 return linux_msgctl(p, uap, retval);
133 #endif
134 #ifdef SYSVSHM
135 case LINUX_SYS_shmat:
136 return linux_shmat(p, uap, retval);
137 case LINUX_SYS_shmdt:
138 return linux_shmdt(p, uap, retval);
139 case LINUX_SYS_shmget:
140 return linux_shmget(p, uap, retval);
141 case LINUX_SYS_shmctl:
142 return linux_shmctl(p, uap, retval);
143 #endif
144 default:
145 return ENOSYS;
146 }
147 }
148
149 /*
150 * Convert between Linux and NetBSD ipc_perm structures. Only the
151 * order of the fields is different.
152 */
153 static void
154 linux_to_bsd_ipc_perm(lpp, bpp)
155 struct linux_ipc_perm *lpp;
156 struct ipc_perm *bpp;
157 {
158 bpp->key = lpp->l_key;
159 bpp->uid = lpp->l_uid;
160 bpp->gid = lpp->l_gid;
161 bpp->cuid = lpp->l_cuid;
162 bpp->cgid = lpp->l_cgid;
163 bpp->mode = lpp->l_mode;
164 bpp->seq = lpp->l_seq;
165 }
166
167
168 static void
169 bsd_to_linux_ipc_perm(bpp, lpp)
170 struct ipc_perm *bpp;
171 struct linux_ipc_perm *lpp;
172 {
173 lpp->l_key = bpp->key;
174 lpp->l_uid = bpp->uid;
175 lpp->l_gid = bpp->gid;
176 lpp->l_cuid = bpp->cuid;
177 lpp->l_cgid = bpp->cgid;
178 lpp->l_mode = bpp->mode;
179 lpp->l_seq = bpp->seq;
180 }
181
182 #ifdef SYSVSEM
183 /*
184 * Semaphore operations: not implemented yet.
185 */
186 int
187 linux_semop(p, uap, retval)
188 struct proc *p;
189 struct linux_ipc_args /* {
190 syscallarg(int) what;
191 syscallarg(int) a1;
192 syscallarg(int) a2;
193 syscallarg(int) a3;
194 syscallarg(caddr_t) ptr;
195 } */ *uap;
196 register_t *retval;
197 {
198 return ENOSYS;
199 }
200
201 int
202 linux_semget(p, uap, retval)
203 struct proc *p;
204 struct linux_ipc_args /* {
205 syscallarg(int) what;
206 syscallarg(int) a1;
207 syscallarg(int) a2;
208 syscallarg(int) a3;
209 syscallarg(caddr_t) ptr;
210 } */ *uap;
211 register_t *retval;
212 {
213 return ENOSYS;
214 }
215
216 int
217 linux_semctl(p, uap, retval)
218 struct proc *p;
219 struct linux_ipc_args /* {
220 syscallarg(int) what;
221 syscallarg(int) a1;
222 syscallarg(int) a2;
223 syscallarg(int) a3;
224 syscallarg(caddr_t) ptr;
225 } */ *uap;
226 register_t *retval;
227 {
228 return ENOSYS;
229 }
230 #endif /* SYSVSEM */
231
232 #ifdef SYSVMSG
233 /*
234 * Msg functions: not implemented yet.
235 */
236 int
237 linux_msgsnd(p, uap, retval)
238 struct proc *p;
239 struct linux_ipc_args /* {
240 syscallarg(int) what;
241 syscallarg(int) a1;
242 syscallarg(int) a2;
243 syscallarg(int) a3;
244 syscallarg(caddr_t) ptr;
245 } */ *uap;
246 register_t *retval;
247 {
248 return ENOSYS;
249 }
250
251 int
252 linux_msgrcv(p, uap, retval)
253 struct proc *p;
254 struct linux_ipc_args /* {
255 syscallarg(int) what;
256 syscallarg(int) a1;
257 syscallarg(int) a2;
258 syscallarg(int) a3;
259 syscallarg(caddr_t) ptr;
260 } */ *uap;
261 register_t *retval;
262 {
263 return ENOSYS;
264 }
265
266 int
267 linux_msgget(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 return ENOSYS;
279 }
280
281 int
282 linux_msgctl(p, uap, retval)
283 struct proc *p;
284 struct linux_ipc_args /* {
285 syscallarg(int) what;
286 syscallarg(int) a1;
287 syscallarg(int) a2;
288 syscallarg(int) a3;
289 syscallarg(caddr_t) ptr;
290 } */ *uap;
291 register_t *retval;
292 {
293 return ENOSYS;
294 }
295 #endif /* SYSVMSG */
296
297 #ifdef SYSVSHM
298 /*
299 * shmat(2). Very straightforward, except that Linux passes a pointer
300 * in which the return value is to be passed. This is subsequently
301 * handled by libc, apparently.
302 */
303 int
304 linux_shmat(p, uap, retval)
305 struct proc *p;
306 struct linux_ipc_args /* {
307 syscallarg(int) what;
308 syscallarg(int) a1;
309 syscallarg(int) a2;
310 syscallarg(int) a3;
311 syscallarg(caddr_t) ptr;
312 } */ *uap;
313 register_t *retval;
314 {
315 struct shmat_args bsa;
316 int error;
317
318 SCARG(&bsa, shmid) = SCARG(uap, a1);
319 SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
320 SCARG(&bsa, shmflg) = SCARG(uap, a2);
321
322 if ((error = shmat(p, &bsa, retval)))
323 return error;
324
325 if ((error = copyout(&retval[0], (caddr_t) SCARG(uap, a3),
326 sizeof retval[0])))
327 return error;
328
329 retval[0] = 0;
330
331 return 0;
332 }
333
334 /*
335 * shmdt(): this could have been mapped directly, if it wasn't for
336 * the extra indirection by the linux_ipc system call.
337 */
338 int
339 linux_shmdt(p, uap, retval)
340 struct proc *p;
341 struct linux_ipc_args /* {
342 syscallarg(int) what;
343 syscallarg(int) a1;
344 syscallarg(int) a2;
345 syscallarg(int) a3;
346 syscallarg(caddr_t) ptr;
347 } */ *uap;
348 register_t *retval;
349 {
350 struct shmdt_args bsa;
351
352 SCARG(&bsa, shmaddr) = SCARG(uap, ptr);
353 return shmdt(p, &bsa, retval);
354 }
355
356 /*
357 * Same story as shmdt.
358 */
359 int
360 linux_shmget(p, uap, retval)
361 struct proc *p;
362 struct linux_ipc_args /* {
363 syscallarg(int) what;
364 syscallarg(int) a1;
365 syscallarg(int) a2;
366 syscallarg(int) a3;
367 syscallarg(caddr_t) ptr;
368 } */ *uap;
369 register_t *retval;
370 {
371 struct shmget_args bsa;
372
373 SCARG(&bsa, key) = SCARG(uap, a1);
374 SCARG(&bsa, size) = SCARG(uap, a2);
375 SCARG(&bsa, shmflg) = SCARG(uap, a3);
376 return shmget(p, &bsa, retval);
377 }
378
379 /*
380 * Convert between Linux and NetBSD shmid_ds structures.
381 * The order of the fields is once again the difference, and
382 * we also need a place to store the internal data pointer
383 * in, which is unfortunately stored in this structure.
384 *
385 * We abuse a Linux internal field for that.
386 */
387 static void
388 linux_to_bsd_shmid_ds(lsp, bsp)
389 struct linux_shmid_ds *lsp;
390 struct shmid_ds *bsp;
391 {
392 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm);
393 bsp->shm_segsz = lsp->l_shm_segsz;
394 bsp->shm_lpid = lsp->l_shm_lpid;
395 bsp->shm_cpid = lsp->l_shm_cpid;
396 bsp->shm_nattch = lsp->l_shm_nattch;
397 bsp->shm_atime = lsp->l_shm_atime;
398 bsp->shm_dtime = lsp->l_shm_dtime;
399 bsp->shm_ctime = lsp->l_shm_ctime;
400 bsp->shm_internal = lsp->l_private2; /* XXX Oh well. */
401 }
402
403 static void
404 bsd_to_linux_shmid_ds(bsp, lsp)
405 struct shmid_ds *bsp;
406 struct linux_shmid_ds *lsp;
407 {
408 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm);
409 lsp->l_shm_segsz = bsp->shm_segsz;
410 lsp->l_shm_lpid = bsp->shm_lpid;
411 lsp->l_shm_cpid = bsp->shm_cpid;
412 lsp->l_shm_nattch = bsp->shm_nattch;
413 lsp->l_shm_atime = bsp->shm_atime;
414 lsp->l_shm_dtime = bsp->shm_dtime;
415 lsp->l_shm_ctime = bsp->shm_ctime;
416 lsp->l_private2 = bsp->shm_internal; /* XXX */
417 }
418
419 /*
420 * shmctl. Not implemented (for now): IPC_INFO, SHM_INFO, SHM_STAT
421 * SHM_LOCK and SHM_UNLOCK are passed on, but currently not implemented
422 * by NetBSD itself.
423 *
424 * The usual structure conversion and massaging is done.
425 */
426 int
427 linux_shmctl(p, uap, retval)
428 struct proc *p;
429 struct linux_ipc_args /* {
430 syscallarg(int) what;
431 syscallarg(int) a1;
432 syscallarg(int) a2;
433 syscallarg(int) a3;
434 syscallarg(caddr_t) ptr;
435 } */ *uap;
436 register_t *retval;
437 {
438 int error;
439 caddr_t sg;
440 struct shmctl_args bsa;
441 struct shmid_ds *bsp, bs;
442 struct linux_shmid_ds lseg;
443
444 switch (SCARG(uap, a2)) {
445 case LINUX_IPC_STAT:
446 sg = stackgap_init(p->p_emul);
447 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
448 SCARG(&bsa, shmid) = SCARG(uap, a1);
449 SCARG(&bsa, cmd) = IPC_STAT;
450 SCARG(&bsa, buf) = bsp;
451 if ((error = shmctl(p, &bsa, retval)))
452 return error;
453 if ((error = copyin((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
454 return error;
455 bsd_to_linux_shmid_ds(&bs, &lseg);
456 return copyout((caddr_t) &lseg, SCARG(uap, ptr), sizeof lseg);
457 case LINUX_IPC_SET:
458 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg,
459 sizeof lseg)))
460 return error;
461 linux_to_bsd_shmid_ds(&lseg, &bs);
462 sg = stackgap_init(p->p_emul);
463 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
464 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
465 return error;
466 SCARG(&bsa, shmid) = SCARG(uap, a1);
467 SCARG(&bsa, cmd) = IPC_SET;
468 SCARG(&bsa, buf) = bsp;
469 return shmctl(p, &bsa, retval);
470 case LINUX_IPC_RMID:
471 case LINUX_SHM_LOCK:
472 case LINUX_SHM_UNLOCK:
473 SCARG(&bsa, shmid) = SCARG(uap, a1);
474 switch (SCARG(uap, a2)) {
475 case LINUX_IPC_RMID:
476 SCARG(&bsa, cmd) = IPC_RMID;
477 break;
478 case LINUX_SHM_LOCK:
479 SCARG(&bsa, cmd) = SHM_LOCK;
480 break;
481 case LINUX_SHM_UNLOCK:
482 SCARG(&bsa, cmd) = SHM_UNLOCK;
483 break;
484 }
485 if ((error = copyin(SCARG(uap, ptr), (caddr_t) &lseg,
486 sizeof lseg)))
487 return error;
488 linux_to_bsd_shmid_ds(&lseg, &bs);
489 sg = stackgap_init(p->p_emul);
490 bsp = stackgap_alloc(&sg, sizeof (struct shmid_ds));
491 if ((error = copyout((caddr_t) &bs, (caddr_t) bsp, sizeof bs)))
492 return error;
493 SCARG(&bsa, buf) = bsp;
494 return shmctl(p, &bsa, retval);
495 case LINUX_IPC_INFO:
496 case LINUX_SHM_STAT:
497 case LINUX_SHM_INFO:
498 default:
499 return EINVAL;
500 }
501 }
502 #endif /* SYSVSHM */
503