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