xref: /netbsd-src/sys/compat/linux/common/linux_ipccall.c (revision 1f2744e6e4915c9da2a3f980279398c4cf7d5e6d)
1 /*	$NetBSD: linux_ipccall.c,v 1.2 1995/03/08 17:27:42 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/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();
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();
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();
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