xref: /freebsd/sys/compat/linux/linux_ipc.c (revision ae2bac960e47ce620c0d2d9ce2068670ea9f8aa6)
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 
228 	/* Make sure the arg parameter can be copied in. */
229 	unptr = stackgap_alloc(&sg, sizeof(union semun));
230 	bcopy(&args->arg, unptr, sizeof(union semun));
231 
232 	bsd_args.semid = args->semid;
233 	bsd_args.semnum = args->semnum;
234 	bsd_args.arg = unptr;
235 
236 	switch (args->cmd) {
237 	case LINUX_IPC_RMID:
238 		bsd_args.cmd = IPC_RMID;
239 		break;
240 	case LINUX_GETNCNT:
241 		bsd_args.cmd = GETNCNT;
242 		break;
243 	case LINUX_GETPID:
244 		bsd_args.cmd = GETPID;
245 		break;
246 	case LINUX_GETVAL:
247 		bsd_args.cmd = GETVAL;
248 		break;
249 	case LINUX_GETZCNT:
250 		bsd_args.cmd = GETZCNT;
251 		break;
252 	case LINUX_SETVAL:
253 		bsd_args.cmd = SETVAL;
254 		break;
255 	case LINUX_IPC_SET:
256 		bsd_args.cmd = IPC_SET;
257 		error = copyin((caddr_t)args->arg.buf, &linux_semid,
258 		    sizeof(linux_semid));
259 		if (error)
260 			return (error);
261 		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
262 		linux_to_bsd_semid_ds(&linux_semid, unptr->buf);
263 		return __semctl(td, &bsd_args);
264 	case LINUX_IPC_STAT:
265 	case LINUX_SEM_STAT:
266 		if( args->cmd == LINUX_IPC_STAT )
267 			bsd_args.cmd = IPC_STAT;
268 		else
269 			bsd_args.cmd = SEM_STAT;
270 		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
271 		error = __semctl(td, &bsd_args);
272 		if (error)
273 			return error;
274 		td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid,
275 							unptr->buf->sem_perm);
276 		bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
277 		return copyout(&linux_semid, (caddr_t)args->arg.buf,
278 					    sizeof(linux_semid));
279 	case LINUX_IPC_INFO:
280 	case LINUX_SEM_INFO:
281 		error = copyin((caddr_t)args->arg.buf, &linux_seminfo,
282 						sizeof(linux_seminfo) );
283 		if (error)
284 			return error;
285 		bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
286 /* XXX BSD equivalent?
287 #define used_semids 10
288 #define used_sems 10
289 		linux_seminfo.semusz = used_semids;
290 		linux_seminfo.semaem = used_sems;
291 */
292 		error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf,
293 						sizeof(linux_seminfo) );
294 		if (error)
295 			return error;
296 		td->td_retval[0] = seminfo.semmni;
297 		return 0;			/* No need for __semctl call */
298 	case LINUX_GETALL:
299 		/* FALLTHROUGH */
300 	case LINUX_SETALL:
301 		/* FALLTHROUGH */
302 	default:
303 		uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
304 		return EINVAL;
305 	}
306 	return __semctl(td, &bsd_args);
307 }
308 
309 int
310 linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
311 {
312     struct msgsnd_args /* {
313 	int     msqid;
314 	void    *msgp;
315 	size_t  msgsz;
316 	int     msgflg;
317     } */ bsd_args;
318 
319     bsd_args.msqid = args->msqid;
320     bsd_args.msgp = args->msgp;
321     bsd_args.msgsz = args->msgsz;
322     bsd_args.msgflg = args->msgflg;
323     return msgsnd(td, &bsd_args);
324 }
325 
326 int
327 linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
328 {
329     struct msgrcv_args /* {
330         int 	msqid;
331 	void	*msgp;
332 	size_t	msgsz;
333 	long	msgtyp;
334 	int	msgflg;
335     } */ bsd_args;
336 
337     bsd_args.msqid = args->msqid;
338     bsd_args.msgp = args->msgp;
339     bsd_args.msgsz = args->msgsz;
340     bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */
341     bsd_args.msgflg = args->msgflg;
342     return msgrcv(td, &bsd_args);
343 }
344 
345 int
346 linux_msgget(struct thread *td, struct linux_msgget_args *args)
347 {
348     struct msgget_args /* {
349 	key_t	key;
350         int 	msgflg;
351     } */ bsd_args;
352 
353     bsd_args.key = args->key;
354     bsd_args.msgflg = args->msgflg;
355     return msgget(td, &bsd_args);
356 }
357 
358 int
359 linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
360 {
361     struct msgctl_args /* {
362 	int     msqid;
363 	int     cmd;
364 	struct	msqid_ds *buf;
365     } */ bsd_args;
366     int error;
367 
368     bsd_args.msqid = args->msqid;
369     bsd_args.cmd = args->cmd;
370     bsd_args.buf = (struct msqid_ds *)args->buf;
371     error = msgctl(td, &bsd_args);
372     return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
373 }
374 
375 int
376 linux_shmat(struct thread *td, struct linux_shmat_args *args)
377 {
378     struct shmat_args /* {
379 	int shmid;
380 	void *shmaddr;
381 	int shmflg;
382     } */ bsd_args;
383     int error;
384 
385     bsd_args.shmid = args->shmid;
386     bsd_args.shmaddr = args->shmaddr;
387     bsd_args.shmflg = args->shmflg;
388     if ((error = shmat(td, &bsd_args)))
389 	return error;
390 #ifdef __i386__
391     if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong))))
392 	return error;
393     td->td_retval[0] = 0;
394 #endif
395     return 0;
396 }
397 
398 int
399 linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
400 {
401     struct shmdt_args /* {
402 	void *shmaddr;
403     } */ bsd_args;
404 
405     bsd_args.shmaddr = args->shmaddr;
406     return shmdt(td, &bsd_args);
407 }
408 
409 int
410 linux_shmget(struct thread *td, struct linux_shmget_args *args)
411 {
412     struct shmget_args /* {
413 	key_t key;
414 	int size;
415 	int shmflg;
416     } */ bsd_args;
417 
418     bsd_args.key = args->key;
419     bsd_args.size = args->size;
420     bsd_args.shmflg = args->shmflg;
421     return shmget(td, &bsd_args);
422 }
423 
424 int
425 linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
426 {
427     struct l_shmid_ds linux_shmid;
428     struct shmctl_args /* {
429 	int shmid;
430 	int cmd;
431 	struct shmid_ds *buf;
432     } */ bsd_args;
433     int error;
434     caddr_t sg = stackgap_init();
435 
436     switch (args->cmd) {
437     case LINUX_IPC_STAT:
438 	bsd_args.shmid = args->shmid;
439 	bsd_args.cmd = IPC_STAT;
440 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
441 	if ((error = shmctl(td, &bsd_args)))
442 	    return error;
443 	bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
444 	return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid));
445 
446     case LINUX_IPC_SET:
447 	if ((error = copyin((caddr_t)args->buf, &linux_shmid,
448 		sizeof(linux_shmid))))
449 	    return error;
450 	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
451 	linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
452 	bsd_args.shmid = args->shmid;
453 	bsd_args.cmd = IPC_SET;
454 	return shmctl(td, &bsd_args);
455 
456     case LINUX_IPC_RMID:
457 	bsd_args.shmid = args->shmid;
458 	bsd_args.cmd = IPC_RMID;
459 	if (args->buf == NULL)
460 	    bsd_args.buf = NULL;
461 	else {
462 	    if ((error = copyin((caddr_t)args->buf, &linux_shmid,
463 		    		sizeof(linux_shmid))))
464 		return error;
465 	    bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
466 	    linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
467 	}
468 	return shmctl(td, &bsd_args);
469 
470     case LINUX_IPC_INFO:
471     case LINUX_SHM_STAT:
472     case LINUX_SHM_INFO:
473     case LINUX_SHM_LOCK:
474     case LINUX_SHM_UNLOCK:
475     default:
476 	uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
477 	return EINVAL;
478     }
479 }
480