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