xref: /freebsd/sys/compat/linux/linux_ipc.c (revision 33b77e2decd50e53798014b70bf7ca3bdc4c0c7e)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *  $Id: linux_ipc.c,v 1.12 1997/10/28 10:50:02 kato Exp $
29  */
30 
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/sysproto.h>
35 #include <sys/proc.h>
36 #include <sys/sem.h>
37 #include <sys/shm.h>
38 
39 #include <i386/linux/linux.h>
40 #include <i386/linux/linux_proto.h>
41 #include <i386/linux/linux_util.h>
42 
43 static int linux_semop __P((struct proc *, struct linux_ipc_args *));
44 static int linux_semget __P((struct proc *, struct linux_ipc_args *));
45 static int linux_semctl __P((struct proc *, struct linux_ipc_args *));
46 static int linux_msgsnd __P((struct proc *, struct linux_ipc_args *));
47 static int linux_msgrcv __P((struct proc *, struct linux_ipc_args *));
48 static int linux_msgctl __P((struct proc *, struct linux_ipc_args *));
49 static int linux_shmat __P((struct proc *, struct linux_ipc_args *));
50 static int linux_shmdt __P((struct proc *, struct linux_ipc_args *));
51 static int linux_shmget __P((struct proc *, struct linux_ipc_args *));
52 static int linux_shmctl __P((struct proc *, struct linux_ipc_args *));
53 
54 struct linux_ipc_perm {
55     linux_key_t key;
56     unsigned short uid;
57     unsigned short gid;
58     unsigned short cuid;
59     unsigned short cgid;
60     unsigned short mode;
61     unsigned short seq;
62 };
63 
64 static void
65 linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp)
66 {
67     bpp->key = lpp->key;
68     bpp->uid = lpp->uid;
69     bpp->gid = lpp->gid;
70     bpp->cuid = lpp->cuid;
71     bpp->cgid = lpp->cgid;
72     bpp->mode = lpp->mode;
73     bpp->seq = lpp->seq;
74 }
75 
76 
77 static void
78 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp)
79 {
80     lpp->key = bpp->key;
81     lpp->uid = bpp->uid;
82     lpp->gid = bpp->gid;
83     lpp->cuid = bpp->cuid;
84     lpp->cgid = bpp->cgid;
85     lpp->mode = bpp->mode;
86     lpp->seq = bpp->seq;
87 }
88 
89 struct linux_semid_ds {
90 	struct linux_ipc_perm	sem_perm;
91 	linux_time_t		sem_otime;
92 	linux_time_t		sem_ctime;
93 	void			*sem_base;
94 	void			*sem_pending;
95 	void			*sem_pending_last;
96 	void			*undo;
97 	ushort			sem_nsems;
98 };
99 
100 struct linux_shmid_ds {
101     struct linux_ipc_perm shm_perm;
102     int shm_segsz;
103     linux_time_t shm_atime;
104     linux_time_t shm_dtime;
105     linux_time_t shm_ctime;
106     ushort shm_cpid;
107     ushort shm_lpid;
108     short shm_nattch;
109     ushort private1;
110     void *private2;
111     void *private3;
112 };
113 
114 static void
115 linux_to_bsd_semid_ds(struct linux_semid_ds *lsp, struct semid_ds *bsp)
116 {
117     linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
118     bsp->sem_otime = lsp->sem_otime;
119     bsp->sem_ctime = lsp->sem_ctime;
120     bsp->sem_nsems = lsp->sem_nsems;
121     bsp->sem_base = lsp->sem_base;
122 }
123 
124 static void
125 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct linux_semid_ds *lsp)
126 {
127 	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
128 	lsp->sem_otime = bsp->sem_otime;
129 	lsp->sem_ctime = bsp->sem_ctime;
130 	lsp->sem_nsems = bsp->sem_nsems;
131 	lsp->sem_base = bsp->sem_base;
132 }
133 
134 static void
135 linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp)
136 {
137     linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
138     bsp->shm_segsz = lsp->shm_segsz;
139     bsp->shm_lpid = lsp->shm_lpid;
140     bsp->shm_cpid = lsp->shm_cpid;
141     bsp->shm_nattch = lsp->shm_nattch;
142     bsp->shm_atime = lsp->shm_atime;
143     bsp->shm_dtime = lsp->shm_dtime;
144     bsp->shm_ctime = lsp->shm_ctime;
145     bsp->shm_internal = lsp->private3;	/* this goes (yet) SOS */
146 }
147 
148 static void
149 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp)
150 {
151     bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
152     lsp->shm_segsz = bsp->shm_segsz;
153     lsp->shm_lpid = bsp->shm_lpid;
154     lsp->shm_cpid = bsp->shm_cpid;
155     lsp->shm_nattch = bsp->shm_nattch;
156     lsp->shm_atime = bsp->shm_atime;
157     lsp->shm_dtime = bsp->shm_dtime;
158     lsp->shm_ctime = bsp->shm_ctime;
159     lsp->private3 = bsp->shm_internal;	/* this goes (yet) SOS */
160 }
161 
162 static int
163 linux_semop(struct proc *p, struct linux_ipc_args *args)
164 {
165 	struct semop_args /* {
166 	int	semid;
167 	struct	sembuf *sops;
168 	int		nsops;
169 	} */ bsd_args;
170 
171 	bsd_args.semid = args->arg1;
172 	bsd_args.sops = (struct sembuf *)args->ptr;
173 	bsd_args.nsops = args->arg2;
174 	return semop(p, &bsd_args);
175 }
176 
177 static int
178 linux_semget(struct proc *p, struct linux_ipc_args *args)
179 {
180 	struct semget_args /* {
181 	key_t	key;
182 	int		nsems;
183 	int		semflg;
184 	} */ bsd_args;
185 
186 	bsd_args.key = args->arg1;
187 	bsd_args.nsems = args->arg2;
188 	bsd_args.semflg = args->arg3;
189 	return semget(p, &bsd_args);
190 }
191 
192 static int
193 linux_semctl(struct proc *p, struct linux_ipc_args *args)
194 {
195 	struct linux_semid_ds	linux_semid;
196 	struct semid_ds	bsd_semid;
197 	struct __semctl_args /* {
198 	int		semid;
199 	int		semnum;
200 	int		cmd;
201 	union	semun *arg;
202 	} */ bsd_args;
203 	int	error;
204 	caddr_t sg, unptr, dsp, ldsp;
205 
206 	sg = stackgap_init();
207 	bsd_args.semid = args->arg1;
208 	bsd_args.semnum = args->arg2;
209 	bsd_args.cmd = args->arg3;
210 	bsd_args.arg = (union semun *)args->ptr;
211 
212 	switch (args->arg3) {
213 	case LINUX_IPC_RMID:
214 		bsd_args.cmd = IPC_RMID;
215 		break;
216 	case LINUX_GETNCNT:
217 		bsd_args.cmd = GETNCNT;
218 		break;
219 	case LINUX_GETPID:
220 		bsd_args.cmd = GETPID;
221 		break;
222 	case LINUX_GETVAL:
223 		bsd_args.cmd = GETVAL;
224 		break;
225 	case LINUX_GETZCNT:
226 		bsd_args.cmd = GETZCNT;
227 		break;
228 	case LINUX_SETVAL:
229 		bsd_args.cmd = SETVAL;
230 		break;
231 	case LINUX_IPC_SET:
232 		bsd_args.cmd = IPC_SET;
233 		error = copyin(args->ptr, &ldsp, sizeof(ldsp));
234 		if (error)
235 			return error;
236 		error = copyin(ldsp, (caddr_t)&linux_semid, sizeof(linux_semid));
237 		if (error)
238 			return error;
239 		linux_to_bsd_semid_ds(&linux_semid, &bsd_semid);
240 		unptr = stackgap_alloc(&sg, sizeof(union semun));
241 		dsp = stackgap_alloc(&sg, sizeof(struct semid_ds));
242 		error = copyout((caddr_t)&bsd_semid, dsp, sizeof(bsd_semid));
243 		if (error)
244 			return error;
245 		error = copyout((caddr_t)&dsp, unptr, sizeof(dsp));
246 		if (error)
247 			return error;
248 		bsd_args.arg = (union semun *)unptr;
249 		return __semctl(p, &bsd_args);
250 	case LINUX_IPC_STAT:
251 		bsd_args.cmd = IPC_STAT;
252 		unptr = stackgap_alloc(&sg, sizeof(union semun *));
253 		dsp = stackgap_alloc(&sg, sizeof(struct semid_ds));
254 		error = copyout((caddr_t)&dsp, unptr, sizeof(dsp));
255 		if (error)
256 			return error;
257 		bsd_args.arg = (union semun *)unptr;
258 		error = __semctl(p, &bsd_args);
259 		if (error)
260 			return error;
261 		error = copyin(dsp, (caddr_t)&bsd_semid, sizeof(bsd_semid));
262 		if (error)
263 			return error;
264 		bsd_to_linux_semid_ds(&bsd_semid, &linux_semid);
265 		error = copyin(args->ptr, &ldsp, sizeof(ldsp));
266 		if (error)
267 			return error;
268 		return copyout((caddr_t)&linux_semid, ldsp, sizeof(linux_semid));
269 	case LINUX_GETALL:
270 		/* FALLTHROUGH */
271 	case LINUX_SETALL:
272 		/* FALLTHROUGH */
273 	default:
274 		uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
275 		return EINVAL;
276 	}
277 	return __semctl(p, &bsd_args);
278 }
279 
280 static int
281 linux_msgsnd(struct proc *p, struct linux_ipc_args *args)
282 {
283     struct msgsnd_args /* {
284 	int     msqid;
285 	void    *msgp;
286 	size_t  msgsz;
287 	int     msgflg;
288     } */ bsd_args;
289 
290     bsd_args.msqid = args->arg1;
291     bsd_args.msgp = args->ptr;
292     bsd_args.msgsz = args->arg2;
293     bsd_args.msgflg = args->arg3;
294     return msgsnd(p, &bsd_args);
295 }
296 
297 static int
298 linux_msgrcv(struct proc *p, struct linux_ipc_args *args)
299 {
300     struct msgrcv_args /* {
301         int 	msqid;
302 	void	*msgp;
303 	size_t	msgsz;
304 	long	msgtyp;
305 	int	msgflg;
306     } */ bsd_args;
307 
308     bsd_args.msqid = args->arg1;
309     bsd_args.msgp = args->ptr;
310     bsd_args.msgsz = args->arg2;
311     bsd_args.msgtyp = 0;
312     bsd_args.msgflg = args->arg3;
313     return msgrcv(p, &bsd_args);
314 }
315 
316 static int
317 linux_msgget(struct proc *p, struct linux_ipc_args *args)
318 {
319     struct msgget_args /* {
320 	key_t	key;
321         int 	msgflg;
322     } */ bsd_args;
323 
324     bsd_args.key = args->arg1;
325     bsd_args.msgflg = args->arg2;
326     return msgget(p, &bsd_args);
327 }
328 
329 static int
330 linux_msgctl(struct proc *p, struct linux_ipc_args *args)
331 {
332     struct msgctl_args /* {
333 	int     msqid;
334 	int     cmd;
335 	struct	msqid_ds *buf;
336     } */ bsd_args;
337 
338     bsd_args.msqid = args->arg1;
339     bsd_args.cmd = args->arg2;
340     bsd_args.buf = (struct msqid_ds *)args->ptr;
341     return msgctl(p, &bsd_args);
342 }
343 
344 static int
345 linux_shmat(struct proc *p, struct linux_ipc_args *args)
346 {
347     struct shmat_args /* {
348 	int shmid;
349 	void *shmaddr;
350 	int shmflg;
351     } */ bsd_args;
352     int error;
353 
354     bsd_args.shmid = args->arg1;
355     bsd_args.shmaddr = args->ptr;
356     bsd_args.shmflg = args->arg2;
357     if ((error = shmat(p, &bsd_args)))
358 	return error;
359     if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int))))
360 	return error;
361     p->p_retval[0] = 0;
362     return 0;
363 }
364 
365 static int
366 linux_shmdt(struct proc *p, struct linux_ipc_args *args)
367 {
368     struct shmdt_args /* {
369 	void *shmaddr;
370     } */ bsd_args;
371 
372     bsd_args.shmaddr = args->ptr;
373     return shmdt(p, &bsd_args);
374 }
375 
376 static int
377 linux_shmget(struct proc *p, struct linux_ipc_args *args)
378 {
379     struct shmget_args /* {
380 	key_t key;
381 	int size;
382 	int shmflg;
383     } */ bsd_args;
384 
385     bsd_args.key = args->arg1;
386     bsd_args.size = args->arg2;
387     bsd_args.shmflg = args->arg3;
388     return shmget(p, &bsd_args);
389 }
390 
391 static int
392 linux_shmctl(struct proc *p, struct linux_ipc_args *args)
393 {
394     struct shmid_ds bsd_shmid;
395     struct linux_shmid_ds linux_shmid;
396     struct shmctl_args /* {
397 	int shmid;
398 	int cmd;
399 	struct shmid_ds *buf;
400     } */ bsd_args;
401     int error;
402     caddr_t sg = stackgap_init();
403 
404     switch (args->arg2) {
405     case LINUX_IPC_STAT:
406 	bsd_args.shmid = args->arg1;
407 	bsd_args.cmd = IPC_STAT;
408 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
409 	if ((error = shmctl(p, &bsd_args)))
410 	    return error;
411 	if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid,
412 		    	    sizeof(struct shmid_ds))))
413 	    return error;
414 	bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
415 	return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid));
416 
417     case LINUX_IPC_SET:
418 	if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
419 		    	    sizeof(linux_shmid))))
420 	    return error;
421 	linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
422 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
423 	if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
424 		     	     sizeof(struct shmid_ds))))
425 	    return error;
426 	bsd_args.shmid = args->arg1;
427 	bsd_args.cmd = IPC_SET;
428 	return shmctl(p, &bsd_args);
429 
430     case LINUX_IPC_RMID:
431 	bsd_args.shmid = args->arg1;
432 	bsd_args.cmd = IPC_RMID;
433 	if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
434 		    	    sizeof(linux_shmid))))
435 	    return error;
436 	linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
437 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
438 	if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
439 		     	     sizeof(struct shmid_ds))))
440 	    return error;
441 	return shmctl(p, &bsd_args);
442 
443     case LINUX_IPC_INFO:
444     case LINUX_SHM_STAT:
445     case LINUX_SHM_INFO:
446     case LINUX_SHM_LOCK:
447     case LINUX_SHM_UNLOCK:
448     default:
449 	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
450 	return EINVAL;
451     }
452 }
453 
454 int
455 linux_ipc(struct proc *p, struct linux_ipc_args *args)
456 {
457     switch (args->what) {
458     case LINUX_SEMOP:
459 	return linux_semop(p, args);
460     case LINUX_SEMGET:
461 	return linux_semget(p, args);
462     case LINUX_SEMCTL:
463 	return linux_semctl(p, args);
464     case LINUX_MSGSND:
465 	return linux_msgsnd(p, args);
466     case LINUX_MSGRCV:
467 	return linux_msgrcv(p, args);
468     case LINUX_MSGGET:
469 	return linux_msgget(p, args);
470     case LINUX_MSGCTL:
471 	return linux_msgctl(p, args);
472     case LINUX_SHMAT:
473 	return linux_shmat(p, args);
474     case LINUX_SHMDT:
475 	return linux_shmdt(p, args);
476     case LINUX_SHMGET:
477 	return linux_shmget(p, args);
478     case LINUX_SHMCTL:
479 	return linux_shmctl(p, args);
480     default:
481 	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
482 	return ENOSYS;
483     }
484 }
485