linux_ipc.c revision 83366
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: head/sys/compat/linux/linux_ipc.c 83366 2001-09-12 08:38:13Z julian $
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_ipc_perm {
44	l_key_t		key;
45	l_uid16_t	uid;
46	l_gid16_t	gid;
47	l_uid16_t	cuid;
48	l_gid16_t	cgid;
49	l_ushort	mode;
50	l_ushort	seq;
51};
52
53static void
54linux_to_bsd_ipc_perm(struct l_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
66static void
67bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_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
78struct l_semid_ds {
79	struct l_ipc_perm	sem_perm;
80	l_time_t		sem_otime;
81	l_time_t		sem_ctime;
82	void			*sem_base;
83	void			*sem_pending;
84	void			*sem_pending_last;
85	void			*undo;
86	l_ushort		sem_nsems;
87};
88
89struct l_shmid_ds {
90	struct l_ipc_perm	shm_perm;
91	l_int			shm_segsz;
92	l_time_t		shm_atime;
93	l_time_t		shm_dtime;
94	l_time_t		shm_ctime;
95	l_ushort		shm_cpid;
96	l_ushort		shm_lpid;
97	l_short			shm_nattch;
98	l_ushort		private1;
99	void			*private2;
100	void			*private3;
101};
102
103static void
104linux_to_bsd_semid_ds(struct l_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
113static void
114bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_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
123static void
124linux_to_bsd_shmid_ds(struct l_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
137static void
138bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_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
151int
152linux_semop(struct thread *td, 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->semid;
161	bsd_args.sops = (struct sembuf *)args->tsops;
162	bsd_args.nsops = args->nsops;
163	return semop(td, &bsd_args);
164}
165
166int
167linux_semget(struct thread *td, 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->key;
176	bsd_args.nsems = args->nsems;
177	bsd_args.semflg = args->semflg;
178	return semget(td, &bsd_args);
179}
180
181int
182linux_semctl(struct thread *td, struct linux_semctl_args *args)
183{
184	struct l_semid_ds linux_semid;
185	struct __semctl_args /* {
186		int		semid;
187		int		semnum;
188		int		cmd;
189		union semun	*arg;
190	} */ bsd_args;
191	int error;
192	union semun *unptr;
193	caddr_t sg;
194
195	sg = stackgap_init();
196	bsd_args.semid = args->semid;
197	bsd_args.semnum = args->semnum;
198	bsd_args.arg = (union semun *)&args->arg;
199
200	switch (args->cmd) {
201	case LINUX_IPC_RMID:
202		bsd_args.cmd = IPC_RMID;
203		break;
204	case LINUX_GETNCNT:
205		bsd_args.cmd = GETNCNT;
206		break;
207	case LINUX_GETPID:
208		bsd_args.cmd = GETPID;
209		break;
210	case LINUX_GETVAL:
211		bsd_args.cmd = GETVAL;
212		break;
213	case LINUX_GETZCNT:
214		bsd_args.cmd = GETZCNT;
215		break;
216	case LINUX_SETVAL:
217		bsd_args.cmd = SETVAL;
218		break;
219	case LINUX_IPC_SET:
220		bsd_args.cmd = IPC_SET;
221		error = copyin((caddr_t)args->arg.buf, &linux_semid,
222		    sizeof(linux_semid));
223		if (error)
224			return (error);
225		unptr = stackgap_alloc(&sg, sizeof(union semun));
226		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
227		linux_to_bsd_semid_ds(&linux_semid, unptr->buf);
228		bsd_args.arg = unptr;
229		return __semctl(td, &bsd_args);
230	case LINUX_IPC_STAT:
231		bsd_args.cmd = IPC_STAT;
232		unptr = stackgap_alloc(&sg, sizeof(union semun));
233		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
234		bsd_args.arg = unptr;
235		error = __semctl(td, &bsd_args);
236		if (error)
237			return error;
238		bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
239		return copyout(&linux_semid, (caddr_t)args->arg.buf,
240		    sizeof(linux_semid));
241	case LINUX_GETALL:
242		/* FALLTHROUGH */
243	case LINUX_SETALL:
244		/* FALLTHROUGH */
245	default:
246		uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
247		return EINVAL;
248	}
249	return __semctl(td, &bsd_args);
250}
251
252int
253linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
254{
255    struct msgsnd_args /* {
256	int     msqid;
257	void    *msgp;
258	size_t  msgsz;
259	int     msgflg;
260    } */ bsd_args;
261
262    bsd_args.msqid = args->msqid;
263    bsd_args.msgp = args->msgp;
264    bsd_args.msgsz = args->msgsz;
265    bsd_args.msgflg = args->msgflg;
266    return msgsnd(td, &bsd_args);
267}
268
269int
270linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
271{
272    struct msgrcv_args /* {
273        int 	msqid;
274	void	*msgp;
275	size_t	msgsz;
276	long	msgtyp;
277	int	msgflg;
278    } */ bsd_args;
279
280    bsd_args.msqid = args->msqid;
281    bsd_args.msgp = args->msgp;
282    bsd_args.msgsz = args->msgsz;
283    bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */
284    bsd_args.msgflg = args->msgflg;
285    return msgrcv(td, &bsd_args);
286}
287
288int
289linux_msgget(struct thread *td, struct linux_msgget_args *args)
290{
291    struct msgget_args /* {
292	key_t	key;
293        int 	msgflg;
294    } */ bsd_args;
295
296    bsd_args.key = args->key;
297    bsd_args.msgflg = args->msgflg;
298    return msgget(td, &bsd_args);
299}
300
301int
302linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
303{
304    struct msgctl_args /* {
305	int     msqid;
306	int     cmd;
307	struct	msqid_ds *buf;
308    } */ bsd_args;
309    int error;
310
311    bsd_args.msqid = args->msqid;
312    bsd_args.cmd = args->cmd;
313    bsd_args.buf = (struct msqid_ds *)args->buf;
314    error = msgctl(td, &bsd_args);
315    return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
316}
317
318int
319linux_shmat(struct thread *td, struct linux_shmat_args *args)
320{
321    struct shmat_args /* {
322	int shmid;
323	void *shmaddr;
324	int shmflg;
325    } */ bsd_args;
326    int error;
327
328    bsd_args.shmid = args->shmid;
329    bsd_args.shmaddr = args->shmaddr;
330    bsd_args.shmflg = args->shmflg;
331    if ((error = shmat(td, &bsd_args)))
332	return error;
333#ifdef __i386__
334    if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong))))
335	return error;
336    td->td_retval[0] = 0;
337#endif
338    return 0;
339}
340
341int
342linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
343{
344    struct shmdt_args /* {
345	void *shmaddr;
346    } */ bsd_args;
347
348    bsd_args.shmaddr = args->shmaddr;
349    return shmdt(td, &bsd_args);
350}
351
352int
353linux_shmget(struct thread *td, struct linux_shmget_args *args)
354{
355    struct shmget_args /* {
356	key_t key;
357	int size;
358	int shmflg;
359    } */ bsd_args;
360
361    bsd_args.key = args->key;
362    bsd_args.size = args->size;
363    bsd_args.shmflg = args->shmflg;
364    return shmget(td, &bsd_args);
365}
366
367int
368linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
369{
370    struct l_shmid_ds linux_shmid;
371    struct shmctl_args /* {
372	int shmid;
373	int cmd;
374	struct shmid_ds *buf;
375    } */ bsd_args;
376    int error;
377    caddr_t sg = stackgap_init();
378
379    switch (args->cmd) {
380    case LINUX_IPC_STAT:
381	bsd_args.shmid = args->shmid;
382	bsd_args.cmd = IPC_STAT;
383	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
384	if ((error = shmctl(td, &bsd_args)))
385	    return error;
386	bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
387	return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid));
388
389    case LINUX_IPC_SET:
390	if ((error = copyin((caddr_t)args->buf, &linux_shmid,
391		sizeof(linux_shmid))))
392	    return error;
393	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
394	linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
395	bsd_args.shmid = args->shmid;
396	bsd_args.cmd = IPC_SET;
397	return shmctl(td, &bsd_args);
398
399    case LINUX_IPC_RMID:
400	bsd_args.shmid = args->shmid;
401	bsd_args.cmd = IPC_RMID;
402	if (args->buf == NULL)
403	    bsd_args.buf = NULL;
404	else {
405	    if ((error = copyin((caddr_t)args->buf, &linux_shmid,
406		    		sizeof(linux_shmid))))
407		return error;
408	    bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
409	    linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
410	}
411	return shmctl(td, &bsd_args);
412
413    case LINUX_IPC_INFO:
414    case LINUX_SHM_STAT:
415    case LINUX_SHM_INFO:
416    case LINUX_SHM_LOCK:
417    case LINUX_SHM_UNLOCK:
418    default:
419	uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
420	return EINVAL;
421    }
422}
423