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