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