linux_ipc.c revision 97748
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: head/sys/compat/linux/linux_ipc.c 97748 2002-06-02 20:05:59Z schweikh $
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
43struct 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
56struct l_shminfo {
57	l_int shmmax;
58	l_int shmmin;
59	l_int shmmni;
60	l_int shmseg;
61	l_int shmall;
62};
63
64struct 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
73static void
74bsd_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
83static void
84bsd_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
94struct 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
104static void
105linux_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
117static void
118bsd_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
129struct 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
140struct 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
154static void
155linux_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
164static void
165bsd_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
174static void
175linux_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
188static void
189bsd_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
202int
203linux_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
217int
218linux_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
232int
233linux_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
330int
331linux_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
347int
348linux_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
366int
367linux_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
379int
380linux_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
396int
397linux_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
419int
420linux_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
430int
431linux_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
445int
446linux_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