xref: /freebsd/sys/compat/linux/linux_ipc.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/sysproto.h>
34 #include <sys/proc.h>
35 #include <sys/sem.h>
36 #include <sys/shm.h>
37 
38 #include <machine/../linux/linux.h>
39 #ifdef __alpha__
40 #include <linux_proto.h>
41 #else
42 #include <machine/../linux/linux_proto.h>
43 #endif
44 #include <compat/linux/linux_ipc.h>
45 #include <compat/linux/linux_util.h>
46 
47 struct linux_ipc_perm {
48     linux_key_t key;
49     unsigned short uid;
50     unsigned short gid;
51     unsigned short cuid;
52     unsigned short cgid;
53     unsigned short mode;
54     unsigned short seq;
55 };
56 
57 static void
58 linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp)
59 {
60     bpp->key = lpp->key;
61     bpp->uid = lpp->uid;
62     bpp->gid = lpp->gid;
63     bpp->cuid = lpp->cuid;
64     bpp->cgid = lpp->cgid;
65     bpp->mode = lpp->mode;
66     bpp->seq = lpp->seq;
67 }
68 
69 
70 static void
71 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp)
72 {
73     lpp->key = bpp->key;
74     lpp->uid = bpp->uid;
75     lpp->gid = bpp->gid;
76     lpp->cuid = bpp->cuid;
77     lpp->cgid = bpp->cgid;
78     lpp->mode = bpp->mode;
79     lpp->seq = bpp->seq;
80 }
81 
82 struct linux_semid_ds {
83 	struct linux_ipc_perm	sem_perm;
84 	linux_time_t		sem_otime;
85 	linux_time_t		sem_ctime;
86 	void			*sem_base;
87 	void			*sem_pending;
88 	void			*sem_pending_last;
89 	void			*undo;
90 	ushort			sem_nsems;
91 };
92 
93 struct linux_shmid_ds {
94     struct linux_ipc_perm shm_perm;
95     int shm_segsz;
96     linux_time_t shm_atime;
97     linux_time_t shm_dtime;
98     linux_time_t shm_ctime;
99     ushort shm_cpid;
100     ushort shm_lpid;
101     short shm_nattch;
102     ushort private1;
103     void *private2;
104     void *private3;
105 };
106 
107 static void
108 linux_to_bsd_semid_ds(struct linux_semid_ds *lsp, struct semid_ds *bsp)
109 {
110     linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
111     bsp->sem_otime = lsp->sem_otime;
112     bsp->sem_ctime = lsp->sem_ctime;
113     bsp->sem_nsems = lsp->sem_nsems;
114     bsp->sem_base = lsp->sem_base;
115 }
116 
117 static void
118 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct linux_semid_ds *lsp)
119 {
120 	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
121 	lsp->sem_otime = bsp->sem_otime;
122 	lsp->sem_ctime = bsp->sem_ctime;
123 	lsp->sem_nsems = bsp->sem_nsems;
124 	lsp->sem_base = bsp->sem_base;
125 }
126 
127 static void
128 linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp)
129 {
130     linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
131     bsp->shm_segsz = lsp->shm_segsz;
132     bsp->shm_lpid = lsp->shm_lpid;
133     bsp->shm_cpid = lsp->shm_cpid;
134     bsp->shm_nattch = lsp->shm_nattch;
135     bsp->shm_atime = lsp->shm_atime;
136     bsp->shm_dtime = lsp->shm_dtime;
137     bsp->shm_ctime = lsp->shm_ctime;
138     bsp->shm_internal = lsp->private3;	/* this goes (yet) SOS */
139 }
140 
141 static void
142 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp)
143 {
144     bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
145     lsp->shm_segsz = bsp->shm_segsz;
146     lsp->shm_lpid = bsp->shm_lpid;
147     lsp->shm_cpid = bsp->shm_cpid;
148     lsp->shm_nattch = bsp->shm_nattch;
149     lsp->shm_atime = bsp->shm_atime;
150     lsp->shm_dtime = bsp->shm_dtime;
151     lsp->shm_ctime = bsp->shm_ctime;
152     lsp->private3 = bsp->shm_internal;	/* this goes (yet) SOS */
153 }
154 
155 int
156 linux_semop(struct proc *p, struct linux_semop_args *args)
157 {
158 	struct semop_args /* {
159 	int	semid;
160 	struct	sembuf *sops;
161 	int		nsops;
162 	} */ bsd_args;
163 
164 	bsd_args.semid = args->arg1;
165 	bsd_args.sops = (struct sembuf *)args->ptr;
166 	bsd_args.nsops = args->arg2;
167 	return semop(p, &bsd_args);
168 }
169 
170 int
171 linux_semget(struct proc *p, struct linux_semget_args *args)
172 {
173 	struct semget_args /* {
174 	key_t	key;
175 	int		nsems;
176 	int		semflg;
177 	} */ bsd_args;
178 
179 	bsd_args.key = args->arg1;
180 	bsd_args.nsems = args->arg2;
181 	bsd_args.semflg = args->arg3;
182 	return semget(p, &bsd_args);
183 }
184 
185 int
186 linux_semctl(struct proc *p, struct linux_semctl_args *args)
187 {
188 	struct linux_semid_ds	linux_semid;
189 	struct semid_ds	bsd_semid;
190 	struct __semctl_args /* {
191 	int		semid;
192 	int		semnum;
193 	int		cmd;
194 	union	semun *arg;
195 	} */ bsd_args;
196 	int	error;
197 	caddr_t sg, unptr, dsp, ldsp;
198 
199 	sg = stackgap_init();
200 	bsd_args.semid = args->arg1;
201 	bsd_args.semnum = args->arg2;
202 	bsd_args.cmd = args->arg3;
203 	bsd_args.arg = (union semun *)args->ptr;
204 
205 	switch (args->arg3) {
206 	case LINUX_IPC_RMID:
207 		bsd_args.cmd = IPC_RMID;
208 		break;
209 	case LINUX_GETNCNT:
210 		bsd_args.cmd = GETNCNT;
211 		break;
212 	case LINUX_GETPID:
213 		bsd_args.cmd = GETPID;
214 		break;
215 	case LINUX_GETVAL:
216 		bsd_args.cmd = GETVAL;
217 		break;
218 	case LINUX_GETZCNT:
219 		bsd_args.cmd = GETZCNT;
220 		break;
221 	case LINUX_SETVAL:
222 		bsd_args.cmd = SETVAL;
223 		break;
224 	case LINUX_IPC_SET:
225 		bsd_args.cmd = IPC_SET;
226 		error = copyin(args->ptr, &ldsp, sizeof(ldsp));
227 		if (error)
228 			return error;
229 		error = copyin(ldsp, (caddr_t)&linux_semid, sizeof(linux_semid));
230 		if (error)
231 			return error;
232 		linux_to_bsd_semid_ds(&linux_semid, &bsd_semid);
233 		unptr = stackgap_alloc(&sg, sizeof(union semun));
234 		dsp = stackgap_alloc(&sg, sizeof(struct semid_ds));
235 		error = copyout((caddr_t)&bsd_semid, dsp, sizeof(bsd_semid));
236 		if (error)
237 			return error;
238 		error = copyout((caddr_t)&dsp, unptr, sizeof(dsp));
239 		if (error)
240 			return error;
241 		bsd_args.arg = (union semun *)unptr;
242 		return __semctl(p, &bsd_args);
243 	case LINUX_IPC_STAT:
244 		bsd_args.cmd = IPC_STAT;
245 		unptr = stackgap_alloc(&sg, sizeof(union semun *));
246 		dsp = stackgap_alloc(&sg, sizeof(struct semid_ds));
247 		error = copyout((caddr_t)&dsp, unptr, sizeof(dsp));
248 		if (error)
249 			return error;
250 		bsd_args.arg = (union semun *)unptr;
251 		error = __semctl(p, &bsd_args);
252 		if (error)
253 			return error;
254 		error = copyin(dsp, (caddr_t)&bsd_semid, sizeof(bsd_semid));
255 		if (error)
256 			return error;
257 		bsd_to_linux_semid_ds(&bsd_semid, &linux_semid);
258 		error = copyin(args->ptr, &ldsp, sizeof(ldsp));
259 		if (error)
260 			return error;
261 		return copyout((caddr_t)&linux_semid, ldsp, sizeof(linux_semid));
262 	case LINUX_GETALL:
263 		/* FALLTHROUGH */
264 	case LINUX_SETALL:
265 		/* FALLTHROUGH */
266 	default:
267 		uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->arg3);
268 		return EINVAL;
269 	}
270 	return __semctl(p, &bsd_args);
271 }
272 
273 int
274 linux_msgsnd(struct proc *p, struct linux_msgsnd_args *args)
275 {
276     struct msgsnd_args /* {
277 	int     msqid;
278 	void    *msgp;
279 	size_t  msgsz;
280 	int     msgflg;
281     } */ bsd_args;
282 
283     bsd_args.msqid = args->arg1;
284     bsd_args.msgp = args->ptr;
285     bsd_args.msgsz = args->arg2;
286     bsd_args.msgflg = args->arg3;
287     return msgsnd(p, &bsd_args);
288 }
289 
290 int
291 linux_msgrcv(struct proc *p, struct linux_msgrcv_args *args)
292 {
293     struct msgrcv_args /* {
294         int 	msqid;
295 	void	*msgp;
296 	size_t	msgsz;
297 	long	msgtyp;
298 	int	msgflg;
299     } */ bsd_args;
300 
301     bsd_args.msqid = args->arg1;
302     bsd_args.msgp = args->ptr;
303     bsd_args.msgsz = args->arg2;
304     bsd_args.msgtyp = 0;
305     bsd_args.msgflg = args->arg3;
306     return msgrcv(p, &bsd_args);
307 }
308 
309 int
310 linux_msgget(struct proc *p, struct linux_msgget_args *args)
311 {
312     struct msgget_args /* {
313 	key_t	key;
314         int 	msgflg;
315     } */ bsd_args;
316 
317     bsd_args.key = args->arg1;
318     bsd_args.msgflg = args->arg2;
319     return msgget(p, &bsd_args);
320 }
321 
322 int
323 linux_msgctl(struct proc *p, struct linux_msgctl_args *args)
324 {
325     struct msgctl_args /* {
326 	int     msqid;
327 	int     cmd;
328 	struct	msqid_ds *buf;
329     } */ bsd_args;
330     int error;
331 
332     bsd_args.msqid = args->arg1;
333     bsd_args.cmd = args->arg2;
334     bsd_args.buf = (struct msqid_ds *)args->ptr;
335     error = msgctl(p, &bsd_args);
336     return ((args->arg2 == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
337 }
338 
339 int
340 linux_shmat(struct proc *p, struct linux_shmat_args *args)
341 {
342     struct shmat_args /* {
343 	int shmid;
344 	void *shmaddr;
345 	int shmflg;
346     } */ bsd_args;
347     int error;
348 
349     bsd_args.shmid = args->arg1;
350     bsd_args.shmaddr = args->ptr;
351     bsd_args.shmflg = args->arg2;
352     if ((error = shmat(p, &bsd_args)))
353 	return error;
354 #ifdef __i386__
355     if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int))))
356 	return error;
357     p->p_retval[0] = 0;
358 #endif
359     return 0;
360 }
361 
362 int
363 linux_shmdt(struct proc *p, struct linux_shmdt_args *args)
364 {
365     struct shmdt_args /* {
366 	void *shmaddr;
367     } */ bsd_args;
368 
369     bsd_args.shmaddr = args->ptr;
370     return shmdt(p, &bsd_args);
371 }
372 
373 int
374 linux_shmget(struct proc *p, struct linux_shmget_args *args)
375 {
376     struct shmget_args /* {
377 	key_t key;
378 	int size;
379 	int shmflg;
380     } */ bsd_args;
381 
382     bsd_args.key = args->arg1;
383     bsd_args.size = args->arg2;
384     bsd_args.shmflg = args->arg3;
385     return shmget(p, &bsd_args);
386 }
387 
388 int
389 linux_shmctl(struct proc *p, struct linux_shmctl_args *args)
390 {
391     struct shmid_ds bsd_shmid;
392     struct linux_shmid_ds linux_shmid;
393     struct shmctl_args /* {
394 	int shmid;
395 	int cmd;
396 	struct shmid_ds *buf;
397     } */ bsd_args;
398     int error;
399     caddr_t sg = stackgap_init();
400 
401     switch (args->arg2) {
402     case LINUX_IPC_STAT:
403 	bsd_args.shmid = args->arg1;
404 	bsd_args.cmd = IPC_STAT;
405 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
406 	if ((error = shmctl(p, &bsd_args)))
407 	    return error;
408 	if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid,
409 		    	    sizeof(struct shmid_ds))))
410 	    return error;
411 	bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
412 	return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid));
413 
414     case LINUX_IPC_SET:
415 	if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
416 		    	    sizeof(linux_shmid))))
417 	    return error;
418 	linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
419 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
420 	if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
421 		     	     sizeof(struct shmid_ds))))
422 	    return error;
423 	bsd_args.shmid = args->arg1;
424 	bsd_args.cmd = IPC_SET;
425 	return shmctl(p, &bsd_args);
426 
427     case LINUX_IPC_RMID:
428 	bsd_args.shmid = args->arg1;
429 	bsd_args.cmd = IPC_RMID;
430 	if (NULL == args->ptr)
431 	    bsd_args.buf = NULL;
432 	else {
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 	}
442 	return shmctl(p, &bsd_args);
443 
444     case LINUX_IPC_INFO:
445     case LINUX_SHM_STAT:
446     case LINUX_SHM_INFO:
447     case LINUX_SHM_LOCK:
448     case LINUX_SHM_UNLOCK:
449     default:
450 	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->arg2);
451 	return EINVAL;
452     }
453 }
454