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