xref: /freebsd/sys/compat/linux/linux_ipc.c (revision 6de306ecee3831f48debaad1d0b22418faa48e10)
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_semop_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_semget_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_semctl_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->arg3);
264 		return EINVAL;
265 	}
266 	return __semctl(p, &bsd_args);
267 }
268 
269 int
270 linux_msgsnd(struct proc *p, struct linux_msgsnd_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_msgrcv_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_msgget_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_msgctl_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_shmat_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 #ifdef __i386__
351     if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int))))
352 	return error;
353     p->p_retval[0] = 0;
354 #endif
355     return 0;
356 }
357 
358 int
359 linux_shmdt(struct proc *p, struct linux_shmdt_args *args)
360 {
361     struct shmdt_args /* {
362 	void *shmaddr;
363     } */ bsd_args;
364 
365     bsd_args.shmaddr = args->ptr;
366     return shmdt(p, &bsd_args);
367 }
368 
369 int
370 linux_shmget(struct proc *p, struct linux_shmget_args *args)
371 {
372     struct shmget_args /* {
373 	key_t key;
374 	int size;
375 	int shmflg;
376     } */ bsd_args;
377 
378     bsd_args.key = args->arg1;
379     bsd_args.size = args->arg2;
380     bsd_args.shmflg = args->arg3;
381     return shmget(p, &bsd_args);
382 }
383 
384 int
385 linux_shmctl(struct proc *p, struct linux_shmctl_args *args)
386 {
387     struct shmid_ds bsd_shmid;
388     struct linux_shmid_ds linux_shmid;
389     struct shmctl_args /* {
390 	int shmid;
391 	int cmd;
392 	struct shmid_ds *buf;
393     } */ bsd_args;
394     int error;
395     caddr_t sg = stackgap_init();
396 
397     switch (args->arg2) {
398     case LINUX_IPC_STAT:
399 	bsd_args.shmid = args->arg1;
400 	bsd_args.cmd = IPC_STAT;
401 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
402 	if ((error = shmctl(p, &bsd_args)))
403 	    return error;
404 	if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid,
405 		    	    sizeof(struct shmid_ds))))
406 	    return error;
407 	bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
408 	return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid));
409 
410     case LINUX_IPC_SET:
411 	if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
412 		    	    sizeof(linux_shmid))))
413 	    return error;
414 	linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
415 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
416 	if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
417 		     	     sizeof(struct shmid_ds))))
418 	    return error;
419 	bsd_args.shmid = args->arg1;
420 	bsd_args.cmd = IPC_SET;
421 	return shmctl(p, &bsd_args);
422 
423     case LINUX_IPC_RMID:
424 	bsd_args.shmid = args->arg1;
425 	bsd_args.cmd = IPC_RMID;
426 	if (NULL == args->ptr)
427 	    bsd_args.buf = NULL;
428 	else {
429 	    if ((error = copyin(args->ptr, (caddr_t)&linux_shmid,
430 		    		sizeof(linux_shmid))))
431 		return error;
432 	    linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
433 	    bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
434 	    if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf,
435 		     		 sizeof(struct shmid_ds))))
436 		return error;
437 	}
438 	return shmctl(p, &bsd_args);
439 
440     case LINUX_IPC_INFO:
441     case LINUX_SHM_STAT:
442     case LINUX_SHM_INFO:
443     case LINUX_SHM_LOCK:
444     case LINUX_SHM_UNLOCK:
445     default:
446 	uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->arg2);
447 	return EINVAL;
448     }
449 }
450