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