linux_ipc.c revision 83501
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 83501 2001-09-15 09:50:38Z mr $
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	bsd_args.semid = args->semid;
228	bsd_args.semnum = args->semnum;
229	bsd_args.arg = (union semun *)&args->arg;
230
231	switch (args->cmd) {
232	case LINUX_IPC_RMID:
233		bsd_args.cmd = IPC_RMID;
234		break;
235	case LINUX_GETNCNT:
236		bsd_args.cmd = GETNCNT;
237		break;
238	case LINUX_GETPID:
239		bsd_args.cmd = GETPID;
240		break;
241	case LINUX_GETVAL:
242		bsd_args.cmd = GETVAL;
243		break;
244	case LINUX_GETZCNT:
245		bsd_args.cmd = GETZCNT;
246		break;
247	case LINUX_SETVAL:
248		bsd_args.cmd = SETVAL;
249		break;
250	case LINUX_IPC_SET:
251		bsd_args.cmd = IPC_SET;
252		error = copyin((caddr_t)args->arg.buf, &linux_semid,
253		    sizeof(linux_semid));
254		if (error)
255			return (error);
256		unptr = stackgap_alloc(&sg, sizeof(union semun));
257		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
258		linux_to_bsd_semid_ds(&linux_semid, unptr->buf);
259		bsd_args.arg = unptr;
260		return __semctl(td, &bsd_args);
261	case LINUX_IPC_STAT:
262	case LINUX_SEM_STAT:
263		if( args->cmd == LINUX_IPC_STAT )
264			bsd_args.cmd = IPC_STAT;
265		else
266			bsd_args.cmd = SEM_STAT;
267		unptr = stackgap_alloc(&sg, sizeof(union semun));
268		unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
269		bsd_args.arg = unptr;
270		error = __semctl(td, &bsd_args);
271		if (error)
272			return error;
273		td->td_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid,
274							unptr->buf->sem_perm);
275		bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
276		return copyout(&linux_semid, (caddr_t)args->arg.buf,
277					    sizeof(linux_semid));
278	case LINUX_IPC_INFO:
279	case LINUX_SEM_INFO:
280		error = copyin((caddr_t)args->arg.buf, &linux_seminfo,
281						sizeof(linux_seminfo) );
282		if (error)
283			return error;
284		bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
285/* XXX BSD equivalent?
286#define used_semids 10
287#define used_sems 10
288		linux_seminfo.semusz = used_semids;
289		linux_seminfo.semaem = used_sems;
290*/
291		error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf,
292						sizeof(linux_seminfo) );
293		if (error)
294			return error;
295		td->td_retval[0] = seminfo.semmni;
296		return 0;			/* No need for __semctl call */
297	case LINUX_GETALL:
298		/* FALLTHROUGH */
299	case LINUX_SETALL:
300		/* FALLTHROUGH */
301	default:
302		uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
303		return EINVAL;
304	}
305	return __semctl(td, &bsd_args);
306}
307
308int
309linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
310{
311    struct msgsnd_args /* {
312	int     msqid;
313	void    *msgp;
314	size_t  msgsz;
315	int     msgflg;
316    } */ bsd_args;
317
318    bsd_args.msqid = args->msqid;
319    bsd_args.msgp = args->msgp;
320    bsd_args.msgsz = args->msgsz;
321    bsd_args.msgflg = args->msgflg;
322    return msgsnd(td, &bsd_args);
323}
324
325int
326linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
327{
328    struct msgrcv_args /* {
329        int 	msqid;
330	void	*msgp;
331	size_t	msgsz;
332	long	msgtyp;
333	int	msgflg;
334    } */ bsd_args;
335
336    bsd_args.msqid = args->msqid;
337    bsd_args.msgp = args->msgp;
338    bsd_args.msgsz = args->msgsz;
339    bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */
340    bsd_args.msgflg = args->msgflg;
341    return msgrcv(td, &bsd_args);
342}
343
344int
345linux_msgget(struct thread *td, struct linux_msgget_args *args)
346{
347    struct msgget_args /* {
348	key_t	key;
349        int 	msgflg;
350    } */ bsd_args;
351
352    bsd_args.key = args->key;
353    bsd_args.msgflg = args->msgflg;
354    return msgget(td, &bsd_args);
355}
356
357int
358linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
359{
360    struct msgctl_args /* {
361	int     msqid;
362	int     cmd;
363	struct	msqid_ds *buf;
364    } */ bsd_args;
365    int error;
366
367    bsd_args.msqid = args->msqid;
368    bsd_args.cmd = args->cmd;
369    bsd_args.buf = (struct msqid_ds *)args->buf;
370    error = msgctl(td, &bsd_args);
371    return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
372}
373
374int
375linux_shmat(struct thread *td, struct linux_shmat_args *args)
376{
377    struct shmat_args /* {
378	int shmid;
379	void *shmaddr;
380	int shmflg;
381    } */ bsd_args;
382    int error;
383
384    bsd_args.shmid = args->shmid;
385    bsd_args.shmaddr = args->shmaddr;
386    bsd_args.shmflg = args->shmflg;
387    if ((error = shmat(td, &bsd_args)))
388	return error;
389#ifdef __i386__
390    if ((error = copyout(td->td_retval, (caddr_t)args->raddr, sizeof(l_ulong))))
391	return error;
392    td->td_retval[0] = 0;
393#endif
394    return 0;
395}
396
397int
398linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
399{
400    struct shmdt_args /* {
401	void *shmaddr;
402    } */ bsd_args;
403
404    bsd_args.shmaddr = args->shmaddr;
405    return shmdt(td, &bsd_args);
406}
407
408int
409linux_shmget(struct thread *td, struct linux_shmget_args *args)
410{
411    struct shmget_args /* {
412	key_t key;
413	int size;
414	int shmflg;
415    } */ bsd_args;
416
417    bsd_args.key = args->key;
418    bsd_args.size = args->size;
419    bsd_args.shmflg = args->shmflg;
420    return shmget(td, &bsd_args);
421}
422
423int
424linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
425{
426    struct l_shmid_ds linux_shmid;
427    struct shmctl_args /* {
428	int shmid;
429	int cmd;
430	struct shmid_ds *buf;
431    } */ bsd_args;
432    int error;
433    caddr_t sg = stackgap_init();
434
435    switch (args->cmd) {
436    case LINUX_IPC_STAT:
437	bsd_args.shmid = args->shmid;
438	bsd_args.cmd = IPC_STAT;
439	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
440	if ((error = shmctl(td, &bsd_args)))
441	    return error;
442	bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
443	return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid));
444
445    case LINUX_IPC_SET:
446	if ((error = copyin((caddr_t)args->buf, &linux_shmid,
447		sizeof(linux_shmid))))
448	    return error;
449	bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
450	linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
451	bsd_args.shmid = args->shmid;
452	bsd_args.cmd = IPC_SET;
453	return shmctl(td, &bsd_args);
454
455    case LINUX_IPC_RMID:
456	bsd_args.shmid = args->shmid;
457	bsd_args.cmd = IPC_RMID;
458	if (args->buf == NULL)
459	    bsd_args.buf = NULL;
460	else {
461	    if ((error = copyin((caddr_t)args->buf, &linux_shmid,
462		    		sizeof(linux_shmid))))
463		return error;
464	    bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
465	    linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
466	}
467	return shmctl(td, &bsd_args);
468
469    case LINUX_IPC_INFO:
470    case LINUX_SHM_STAT:
471    case LINUX_SHM_INFO:
472    case LINUX_SHM_LOCK:
473    case LINUX_SHM_UNLOCK:
474    default:
475	uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
476	return EINVAL;
477    }
478}
479