xref: /freebsd/sys/compat/linux/linux_ipc.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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  * $FreeBSD$
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     int error;
338 
339     bsd_args.msqid = args->arg1;
340     bsd_args.cmd = args->arg2;
341     bsd_args.buf = (struct msqid_ds *)args->ptr;
342     error = msgctl(p, &bsd_args);
343     return ((args->arg2 == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
344 }
345 
346 static int
347 linux_shmat(struct proc *p, struct linux_ipc_args *args)
348 {
349     struct shmat_args /* {
350 	int shmid;
351 	void *shmaddr;
352 	int shmflg;
353     } */ bsd_args;
354     int error;
355 
356     bsd_args.shmid = args->arg1;
357     bsd_args.shmaddr = args->ptr;
358     bsd_args.shmflg = args->arg2;
359     if ((error = shmat(p, &bsd_args)))
360 	return error;
361     if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int))))
362 	return error;
363     p->p_retval[0] = 0;
364     return 0;
365 }
366 
367 static int
368 linux_shmdt(struct proc *p, struct linux_ipc_args *args)
369 {
370     struct shmdt_args /* {
371 	void *shmaddr;
372     } */ bsd_args;
373 
374     bsd_args.shmaddr = args->ptr;
375     return shmdt(p, &bsd_args);
376 }
377 
378 static int
379 linux_shmget(struct proc *p, struct linux_ipc_args *args)
380 {
381     struct shmget_args /* {
382 	key_t key;
383 	int size;
384 	int shmflg;
385     } */ bsd_args;
386 
387     bsd_args.key = args->arg1;
388     bsd_args.size = args->arg2;
389     bsd_args.shmflg = args->arg3;
390     return shmget(p, &bsd_args);
391 }
392 
393 static int
394 linux_shmctl(struct proc *p, struct linux_ipc_args *args)
395 {
396     struct shmid_ds bsd_shmid;
397     struct linux_shmid_ds linux_shmid;
398     struct shmctl_args /* {
399 	int shmid;
400 	int cmd;
401 	struct shmid_ds *buf;
402     } */ bsd_args;
403     int error;
404     caddr_t sg = stackgap_init();
405 
406     switch (args->arg2) {
407     case LINUX_IPC_STAT:
408 	bsd_args.shmid = args->arg1;
409 	bsd_args.cmd = IPC_STAT;
410 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
411 	if ((error = shmctl(p, &bsd_args)))
412 	    return error;
413 	if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid,
414 		    	    sizeof(struct shmid_ds))))
415 	    return error;
416 	bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
417 	return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid));
418 
419     case LINUX_IPC_SET:
420 	if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
421 		    	    sizeof(linux_shmid))))
422 	    return error;
423 	linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
424 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
425 	if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
426 		     	     sizeof(struct shmid_ds))))
427 	    return error;
428 	bsd_args.shmid = args->arg1;
429 	bsd_args.cmd = IPC_SET;
430 	return shmctl(p, &bsd_args);
431 
432     case LINUX_IPC_RMID:
433 	bsd_args.shmid = args->arg1;
434 	bsd_args.cmd = IPC_RMID;
435 	if (NULL == args->ptr)
436 	    bsd_args.buf = NULL;
437 	else {
438 	    if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
439 		    		sizeof(linux_shmid))))
440 		return error;
441 	    linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
442 	    bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
443 	    if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
444 		     		 sizeof(struct shmid_ds))))
445 		return error;
446 	}
447 	return shmctl(p, &bsd_args);
448 
449     case LINUX_IPC_INFO:
450     case LINUX_SHM_STAT:
451     case LINUX_SHM_INFO:
452     case LINUX_SHM_LOCK:
453     case LINUX_SHM_UNLOCK:
454     default:
455 	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
456 	return EINVAL;
457     }
458 }
459 
460 int
461 linux_ipc(struct proc *p, struct linux_ipc_args *args)
462 {
463     switch (args->what) {
464     case LINUX_SEMOP:
465 	return linux_semop(p, args);
466     case LINUX_SEMGET:
467 	return linux_semget(p, args);
468     case LINUX_SEMCTL:
469 	return linux_semctl(p, args);
470     case LINUX_MSGSND:
471 	return linux_msgsnd(p, args);
472     case LINUX_MSGRCV:
473 	return linux_msgrcv(p, args);
474     case LINUX_MSGGET:
475 	return linux_msgget(p, args);
476     case LINUX_MSGCTL:
477 	return linux_msgctl(p, args);
478     case LINUX_SHMAT:
479 	return linux_shmat(p, args);
480     case LINUX_SHMDT:
481 	return linux_shmdt(p, args);
482     case LINUX_SHMGET:
483 	return linux_shmget(p, args);
484     case LINUX_SHMCTL:
485 	return linux_shmctl(p, args);
486     default:
487 	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what);
488 	return ENOSYS;
489     }
490 }
491