xref: /freebsd/sys/compat/linux/linux_ipc.c (revision 09e8dea79366f1e5b3a73e8a271b26e4b6bf2e6a)
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 without 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 l_seminfo {
44 	l_int semmap;
45 	l_int semmni;
46 	l_int semmns;
47 	l_int semmnu;
48 	l_int semmsl;
49 	l_int semopm;
50 	l_int semume;
51 	l_int semusz;
52 	l_int semvmx;
53 	l_int semaem;
54 };
55 
56 struct l_shminfo {
57 	l_int shmmax;
58 	l_int shmmin;
59 	l_int shmmni;
60 	l_int shmseg;
61 	l_int shmall;
62 };
63 
64 struct l_shm_info {
65 	l_int used_ids;
66 	l_ulong shm_tot;  /* total allocated shm */
67 	l_ulong shm_rss;  /* total resident shm */
68 	l_ulong shm_swp;  /* total swapped shm */
69 	l_ulong swap_attempts;
70 	l_ulong swap_successes;
71 };
72 
73 static void
74 bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp)
75 {
76 	lpp->shmmax = bpp->shmmax;
77 	lpp->shmmin = bpp->shmmin;
78 	lpp->shmmni = bpp->shmmni;
79 	lpp->shmseg = bpp->shmseg;
80 	lpp->shmall = bpp->shmall;
81 }
82 
83 static void
84 bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
85 {
86 	lpp->used_ids = bpp->used_ids ;
87 	lpp->shm_tot = bpp->shm_tot ;
88 	lpp->shm_rss = bpp->shm_rss ;
89 	lpp->shm_swp = bpp->shm_swp ;
90 	lpp->swap_attempts = bpp->swap_attempts ;
91 	lpp->swap_successes = bpp->swap_successes ;
92 }
93 
94 struct l_ipc_perm {
95 	l_key_t		key;
96 	l_uid16_t	uid;
97 	l_gid16_t	gid;
98 	l_uid16_t	cuid;
99 	l_gid16_t	cgid;
100 	l_ushort	mode;
101 	l_ushort	seq;
102 };
103 
104 static void
105 linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp)
106 {
107     bpp->key = lpp->key;
108     bpp->uid = lpp->uid;
109     bpp->gid = lpp->gid;
110     bpp->cuid = lpp->cuid;
111     bpp->cgid = lpp->cgid;
112     bpp->mode = lpp->mode;
113     bpp->seq = lpp->seq;
114 }
115 
116 
117 static void
118 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp)
119 {
120     lpp->key = bpp->key;
121     lpp->uid = bpp->uid;
122     lpp->gid = bpp->gid;
123     lpp->cuid = bpp->cuid;
124     lpp->cgid = bpp->cgid;
125     lpp->mode = bpp->mode;
126     lpp->seq = bpp->seq;
127 }
128 
129 struct l_semid_ds {
130 	struct l_ipc_perm	sem_perm;
131 	l_time_t		sem_otime;
132 	l_time_t		sem_ctime;
133 	void			*sem_base;
134 	void			*sem_pending;
135 	void			*sem_pending_last;
136 	void			*undo;
137 	l_ushort		sem_nsems;
138 };
139 
140 struct l_shmid_ds {
141 	struct l_ipc_perm	shm_perm;
142 	l_int			shm_segsz;
143 	l_time_t		shm_atime;
144 	l_time_t		shm_dtime;
145 	l_time_t		shm_ctime;
146 	l_ushort		shm_cpid;
147 	l_ushort		shm_lpid;
148 	l_short			shm_nattch;
149 	l_ushort		private1;
150 	void			*private2;
151 	void			*private3;
152 };
153 
154 static void
155 linux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp)
156 {
157     linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
158     bsp->sem_otime = lsp->sem_otime;
159     bsp->sem_ctime = lsp->sem_ctime;
160     bsp->sem_nsems = lsp->sem_nsems;
161     bsp->sem_base = lsp->sem_base;
162 }
163 
164 static void
165 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp)
166 {
167 	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
168 	lsp->sem_otime = bsp->sem_otime;
169 	lsp->sem_ctime = bsp->sem_ctime;
170 	lsp->sem_nsems = bsp->sem_nsems;
171 	lsp->sem_base = bsp->sem_base;
172 }
173 
174 static void
175 linux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp)
176 {
177     linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
178     bsp->shm_segsz = lsp->shm_segsz;
179     bsp->shm_lpid = lsp->shm_lpid;
180     bsp->shm_cpid = lsp->shm_cpid;
181     bsp->shm_nattch = lsp->shm_nattch;
182     bsp->shm_atime = lsp->shm_atime;
183     bsp->shm_dtime = lsp->shm_dtime;
184     bsp->shm_ctime = lsp->shm_ctime;
185     bsp->shm_internal = lsp->private3;	/* this goes (yet) SOS */
186 }
187 
188 static void
189 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp)
190 {
191     bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
192     lsp->shm_segsz = bsp->shm_segsz;
193     lsp->shm_lpid = bsp->shm_lpid;
194     lsp->shm_cpid = bsp->shm_cpid;
195     lsp->shm_nattch = bsp->shm_nattch;
196     lsp->shm_atime = bsp->shm_atime;
197     lsp->shm_dtime = bsp->shm_dtime;
198     lsp->shm_ctime = bsp->shm_ctime;
199     lsp->private3 = bsp->shm_internal;	/* this goes (yet) SOS */
200 }
201 
202 int
203 linux_semop(struct thread *td, struct linux_semop_args *args)
204 {
205 	struct semop_args /* {
206 	int	semid;
207 	struct	sembuf *sops;
208 	int		nsops;
209 	} */ bsd_args;
210 
211 	bsd_args.semid = args->semid;
212 	bsd_args.sops = (struct sembuf *)args->tsops;
213 	bsd_args.nsops = args->nsops;
214 	return semop(td, &bsd_args);
215 }
216 
217 int
218 linux_semget(struct thread *td, struct linux_semget_args *args)
219 {
220 	struct semget_args /* {
221 	key_t	key;
222 	int		nsems;
223 	int		semflg;
224 	} */ bsd_args;
225 
226 	bsd_args.key = args->key;
227 	bsd_args.nsems = args->nsems;
228 	bsd_args.semflg = args->semflg;
229 	return semget(td, &bsd_args);
230 }
231 
232 int
233 linux_semctl(struct thread *td, struct linux_semctl_args *args)
234 {
235 	struct l_semid_ds linux_semid;
236 	struct __semctl_args /* {
237 		int		semid;
238 		int		semnum;
239 		int		cmd;
240 		union semun	*arg;
241 	} */ bsd_args;
242 	struct l_seminfo linux_seminfo;
243 	int error;
244 	union semun *unptr;
245 	caddr_t sg;
246 
247 	sg = stackgap_init();
248 
249 	/* Make sure the arg parameter can be copied in. */
250 	unptr = stackgap_alloc(&sg, sizeof(union semun));
251 	bcopy(&args->arg, unptr, sizeof(union semun));
252 
253 	bsd_args.semid = args->semid;
254 	bsd_args.semnum = args->semnum;
255 	bsd_args.arg = unptr;
256 
257 	switch (args->cmd) {
258 	case LINUX_IPC_RMID:
259 		bsd_args.cmd = IPC_RMID;
260 		break;
261 	case LINUX_GETNCNT:
262 		bsd_args.cmd = GETNCNT;
263 		break;
264 	case LINUX_GETPID:
265 		bsd_args.cmd = GETPID;
266 		break;
267 	case LINUX_GETVAL:
268 		bsd_args.cmd = GETVAL;
269 		break;
270 	case LINUX_GETZCNT:
271 		bsd_args.cmd = GETZCNT;
272 		break;
273 	case LINUX_SETVAL:
274 		bsd_args.cmd = SETVAL;
275 		break;
276 	case LINUX_IPC_SET:
277 		bsd_args.cmd = IPC_SET;
278 		error = copyin((caddr_t)args->arg.buf, &linux_semid,
279 		    sizeof(linux_semid));
280 		if (error)
281 			return (error);
282 		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
283 		linux_to_bsd_semid_ds(&linux_semid, unptr->buf);
284 		return __semctl(td, &bsd_args);
285 	case LINUX_IPC_STAT:
286 	case LINUX_SEM_STAT:
287 		if( args->cmd == LINUX_IPC_STAT )
288 			bsd_args.cmd = IPC_STAT;
289 		else
290 			bsd_args.cmd = SEM_STAT;
291 		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
292 		error = __semctl(td, &bsd_args);
293 		if (error)
294 			return error;
295 		td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid,
296 							unptr->buf->sem_perm);
297 		bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
298 		return copyout(&linux_semid, (caddr_t)args->arg.buf,
299 					    sizeof(linux_semid));
300 	case LINUX_IPC_INFO:
301 	case LINUX_SEM_INFO:
302 		error = copyin((caddr_t)args->arg.buf, &linux_seminfo,
303 						sizeof(linux_seminfo) );
304 		if (error)
305 			return error;
306 		bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
307 /* XXX BSD equivalent?
308 #define used_semids 10
309 #define used_sems 10
310 		linux_seminfo.semusz = used_semids;
311 		linux_seminfo.semaem = used_sems;
312 */
313 		error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf,
314 						sizeof(linux_seminfo) );
315 		if (error)
316 			return error;
317 		td->td_retval[0] = seminfo.semmni;
318 		return 0;			/* No need for __semctl call */
319 	case LINUX_GETALL:
320 		/* FALLTHROUGH */
321 	case LINUX_SETALL:
322 		/* FALLTHROUGH */
323 	default:
324 		uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
325 		return EINVAL;
326 	}
327 	return __semctl(td, &bsd_args);
328 }
329 
330 int
331 linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
332 {
333     struct msgsnd_args /* {
334 	int     msqid;
335 	void    *msgp;
336 	size_t  msgsz;
337 	int     msgflg;
338     } */ bsd_args;
339 
340     bsd_args.msqid = args->msqid;
341     bsd_args.msgp = args->msgp;
342     bsd_args.msgsz = args->msgsz;
343     bsd_args.msgflg = args->msgflg;
344     return msgsnd(td, &bsd_args);
345 }
346 
347 int
348 linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
349 {
350     struct msgrcv_args /* {
351         int 	msqid;
352 	void	*msgp;
353 	size_t	msgsz;
354 	long	msgtyp;
355 	int	msgflg;
356     } */ bsd_args;
357 
358     bsd_args.msqid = args->msqid;
359     bsd_args.msgp = args->msgp;
360     bsd_args.msgsz = args->msgsz;
361     bsd_args.msgtyp = args->msgtyp;
362     bsd_args.msgflg = args->msgflg;
363     return msgrcv(td, &bsd_args);
364 }
365 
366 int
367 linux_msgget(struct thread *td, struct linux_msgget_args *args)
368 {
369     struct msgget_args /* {
370 	key_t	key;
371         int 	msgflg;
372     } */ bsd_args;
373 
374     bsd_args.key = args->key;
375     bsd_args.msgflg = args->msgflg;
376     return msgget(td, &bsd_args);
377 }
378 
379 int
380 linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
381 {
382     struct msgctl_args /* {
383 	int     msqid;
384 	int     cmd;
385 	struct	msqid_ds *buf;
386     } */ bsd_args;
387     int error;
388 
389     bsd_args.msqid = args->msqid;
390     bsd_args.cmd = args->cmd;
391     bsd_args.buf = (struct msqid_ds *)args->buf;
392     error = msgctl(td, &bsd_args);
393     return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
394 }
395 
396 int
397 linux_shmat(struct thread *td, struct linux_shmat_args *args)
398 {
399     struct shmat_args /* {
400 	int shmid;
401 	void *shmaddr;
402 	int shmflg;
403     } */ bsd_args;
404     int error;
405 
406     bsd_args.shmid = args->shmid;
407     bsd_args.shmaddr = args->shmaddr;
408     bsd_args.shmflg = args->shmflg;
409     if ((error = shmat(td, &bsd_args)))
410 	return error;
411 #ifdef __i386__
412     if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong))))
413 	return error;
414     td->td_retval[0] = 0;
415 #endif
416     return 0;
417 }
418 
419 int
420 linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
421 {
422     struct shmdt_args /* {
423 	void *shmaddr;
424     } */ bsd_args;
425 
426     bsd_args.shmaddr = args->shmaddr;
427     return shmdt(td, &bsd_args);
428 }
429 
430 int
431 linux_shmget(struct thread *td, struct linux_shmget_args *args)
432 {
433     struct shmget_args /* {
434 	key_t key;
435 	int size;
436 	int shmflg;
437     } */ bsd_args;
438 
439     bsd_args.key = args->key;
440     bsd_args.size = args->size;
441     bsd_args.shmflg = args->shmflg;
442     return shmget(td, &bsd_args);
443 }
444 
445 int
446 linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
447 {
448     struct l_shmid_ds linux_shmid;
449 	struct l_shminfo linux_shminfo;
450 	struct l_shm_info linux_shm_info;
451     struct shmctl_args /* {
452 	int shmid;
453 	int cmd;
454 	struct shmid_ds *buf;
455     } */ bsd_args;
456     int error;
457     caddr_t sg = stackgap_init();
458 
459     switch (args->cmd) {
460 
461 	case LINUX_IPC_INFO:
462 	bsd_args.shmid = args->shmid;
463 	bsd_args.cmd = IPC_INFO;
464 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shminfo));
465 	if ((error = shmctl(td, &bsd_args)))
466 		return error;
467 	bsd_to_linux_shminfo( (struct shminfo *)bsd_args.buf, &linux_shminfo );
468 	return copyout(&linux_shminfo, (caddr_t)args->buf, sizeof(shminfo));
469 
470 	case LINUX_SHM_INFO:
471 	bsd_args.shmid = args->shmid;
472 	bsd_args.cmd = SHM_INFO;
473 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shm_info));
474 	if ((error = shmctl(td, &bsd_args)))
475 	    return error;
476 	bsd_to_linux_shm_info( (struct shm_info *)bsd_args.buf, &linux_shm_info );
477 	return copyout(&linux_shm_info, (caddr_t)args->buf, sizeof(struct shm_info));
478 
479     case LINUX_IPC_STAT:
480 	bsd_args.shmid = args->shmid;
481 	bsd_args.cmd = IPC_STAT;
482 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
483 	if ((error = shmctl(td, &bsd_args)))
484 	    return error;
485 	bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
486 	return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid));
487 
488 	case LINUX_SHM_STAT:
489 	bsd_args.shmid = args->shmid;
490 	bsd_args.cmd = SHM_STAT;
491 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
492 	if ((error = shmctl(td, &bsd_args))) {
493 	    return error;
494 	}
495 	bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
496 	return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid));
497 
498     case LINUX_IPC_SET:
499 	if ((error = copyin((caddr_t)args->buf, &linux_shmid,
500 		sizeof(linux_shmid))))
501 	    return error;
502 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
503 	linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
504 	bsd_args.shmid = args->shmid;
505 	bsd_args.cmd = IPC_SET;
506 	return shmctl(td, &bsd_args);
507 
508     case LINUX_IPC_RMID:
509 	bsd_args.shmid = args->shmid;
510 	bsd_args.cmd = IPC_RMID;
511 	if (args->buf == NULL)
512 	    bsd_args.buf = NULL;
513 	else {
514 	    if ((error = copyin((caddr_t)args->buf, &linux_shmid,
515 		    		sizeof(linux_shmid))))
516 		return error;
517 	    bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
518 	    linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
519 	}
520 	return shmctl(td, &bsd_args);
521 
522     case LINUX_SHM_LOCK:
523     case LINUX_SHM_UNLOCK:
524     default:
525 	uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
526 	return EINVAL;
527     }
528 }
529