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