Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / emulation / linux / linux_ipc.c
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: src/sys/compat/linux/linux_ipc.c,v 1.17.2.3 2001/11/05 19:08:22 marcel Exp $
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
43 struct 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
56 struct l_shminfo {
57         l_int shmmax;
58         l_int shmmin;
59         l_int shmmni;
60         l_int shmseg;
61         l_int shmall;
62 };
63
64 struct 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
73 struct 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
83 static void
84 linux_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
96 static void
97 bsd_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
108 struct 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
119 struct 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
133 static void
134 linux_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
143 static void
144 bsd_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
153 static void
154 linux_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
167 static void
168 bsd_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
181 int
182 linux_semop(struct proc *p, 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(p, &bsd_args);
194 }
195
196 int
197 linux_semget(struct proc *p, 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(p, &bsd_args);
209 }
210
211 int
212 linux_semctl(struct proc *p, 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(p, &bsd_args);
264         case LINUX_IPC_STAT:
265                 bsd_args.cmd = IPC_STAT;
266                 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
267                 error = __semctl(p, &bsd_args);
268                 if (error)
269                         return error;
270                 p->p_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid, 
271                                                         unptr->buf->sem_perm);
272                 bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
273                 return copyout(&linux_semid, (caddr_t)args->arg.buf,
274                                             sizeof(linux_semid));
275         case LINUX_IPC_INFO:
276         case LINUX_SEM_INFO:
277                 error = copyin((caddr_t)args->arg.buf, &linux_seminfo, 
278                                                 sizeof(linux_seminfo) );
279                 if (error)
280                         return error;
281                 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
282 /* XXX BSD equivalent?
283 #define used_semids 10
284 #define used_sems 10
285                 linux_seminfo.semusz = used_semids;
286                 linux_seminfo.semaem = used_sems;
287 */
288                 error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf,
289                                                 sizeof(linux_seminfo) );
290                 if (error)
291                         return error;
292                 p->p_retval[0] = seminfo.semmni;
293                 return 0;                       /* No need for __semctl call */
294         case LINUX_GETALL:
295                 /* FALLTHROUGH */
296         case LINUX_SETALL:
297                 /* FALLTHROUGH */
298         default:
299                 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
300                 return EINVAL;
301         }
302         return __semctl(p, &bsd_args);
303 }
304
305 int
306 linux_msgsnd(struct proc *p, struct linux_msgsnd_args *args)
307 {
308     struct msgsnd_args /* {
309         int     msqid;   
310         void    *msgp;   
311         size_t  msgsz;   
312         int     msgflg; 
313     } */ bsd_args;
314
315     bsd_args.msqid = args->msqid;
316     bsd_args.msgp = args->msgp;
317     bsd_args.msgsz = args->msgsz;
318     bsd_args.msgflg = args->msgflg;
319     return msgsnd(p, &bsd_args);
320 }
321
322 int
323 linux_msgrcv(struct proc *p, struct linux_msgrcv_args *args)
324 {
325     struct msgrcv_args /* {     
326         int     msqid;   
327         void    *msgp;   
328         size_t  msgsz;   
329         long    msgtyp; 
330         int     msgflg; 
331     } */ bsd_args; 
332
333     bsd_args.msqid = args->msqid;
334     bsd_args.msgp = args->msgp;
335     bsd_args.msgsz = args->msgsz;
336     bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */
337     bsd_args.msgflg = args->msgflg;
338     return msgrcv(p, &bsd_args);
339 }
340
341 int
342 linux_msgget(struct proc *p, struct linux_msgget_args *args)
343 {
344     struct msgget_args /* {
345         key_t   key;
346         int     msgflg;
347     } */ bsd_args;
348
349     bsd_args.key = args->key;
350     bsd_args.msgflg = args->msgflg;
351     return msgget(p, &bsd_args);
352 }
353
354 int
355 linux_msgctl(struct proc *p, struct linux_msgctl_args *args)
356 {
357     struct msgctl_args /* {
358         int     msqid; 
359         int     cmd;
360         struct  msqid_ds *buf;
361     } */ bsd_args;
362     int error;
363
364     bsd_args.msqid = args->msqid;
365     bsd_args.cmd = args->cmd;
366     bsd_args.buf = (struct msqid_ds *)args->buf;
367     error = msgctl(p, &bsd_args);
368     return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
369 }
370
371 int
372 linux_shmat(struct proc *p, struct linux_shmat_args *args)
373 {
374     struct shmat_args /* {
375         int shmid;
376         void *shmaddr;
377         int shmflg;
378     } */ bsd_args;
379     int error;
380
381     bsd_args.shmid = args->shmid;
382     bsd_args.shmaddr = args->shmaddr;
383     bsd_args.shmflg = args->shmflg;
384     if ((error = shmat(p, &bsd_args)))
385         return error;
386 #ifdef __i386__
387     if ((error = copyout(p->p_retval, (caddr_t)args->raddr, sizeof(l_ulong))))
388         return error;
389     p->p_retval[0] = 0;
390 #endif
391     return 0;
392 }
393
394 int
395 linux_shmdt(struct proc *p, struct linux_shmdt_args *args)
396 {
397     struct shmdt_args /* {
398         void *shmaddr;
399     } */ bsd_args;
400
401     bsd_args.shmaddr = args->shmaddr;
402     return shmdt(p, &bsd_args);
403 }
404
405 int
406 linux_shmget(struct proc *p, struct linux_shmget_args *args)
407 {
408     struct shmget_args /* {
409         key_t key;
410         int size;
411         int shmflg;
412     } */ bsd_args;
413
414     bsd_args.key = args->key;
415     bsd_args.size = args->size;
416     bsd_args.shmflg = args->shmflg;
417     return shmget(p, &bsd_args);
418 }
419
420 int
421 linux_shmctl(struct proc *p, struct linux_shmctl_args *args)
422 {
423     struct l_shmid_ds linux_shmid;
424     struct shmctl_args /* {
425         int shmid;
426         int cmd;
427         struct shmid_ds *buf;
428     } */ bsd_args;
429     int error;
430     caddr_t sg = stackgap_init();
431
432     switch (args->cmd) {
433     case LINUX_IPC_STAT:
434         bsd_args.shmid = args->shmid;
435         bsd_args.cmd = IPC_STAT;
436         bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
437         if ((error = shmctl(p, &bsd_args)))
438             return error;
439         bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
440         return copyout(&linux_shmid, (caddr_t)args->buf, sizeof(linux_shmid));
441
442     case LINUX_IPC_SET:
443         if ((error = copyin((caddr_t)args->buf, &linux_shmid,
444                 sizeof(linux_shmid))))
445             return error;
446         bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
447         linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
448         bsd_args.shmid = args->shmid;
449         bsd_args.cmd = IPC_SET;
450         return shmctl(p, &bsd_args);
451
452     case LINUX_IPC_RMID:
453         bsd_args.shmid = args->shmid;
454         bsd_args.cmd = IPC_RMID;
455         if (args->buf == NULL)
456             bsd_args.buf = NULL;
457         else {
458             if ((error = copyin((caddr_t)args->buf, &linux_shmid, 
459                                 sizeof(linux_shmid))))
460                 return error;
461             bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
462             linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
463         }
464         return shmctl(p, &bsd_args);
465
466     case LINUX_IPC_INFO:
467     case LINUX_SHM_STAT:
468     case LINUX_SHM_INFO:
469     case LINUX_SHM_LOCK:
470     case LINUX_SHM_UNLOCK:
471     default:
472         uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
473         return EINVAL;
474     }
475 }