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