proc->thread stage 2: MAJOR revamping of system calls, ucred, jail API,
[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.3 2003/06/23 17:55:26 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 /* {
186         int     semid;
187         struct  sembuf *sops;
188         int             nsops;
189         } */ bsd_args;
190
191         bsd_args.semid = args->semid;
192         bsd_args.sops = (struct sembuf *)args->tsops;
193         bsd_args.nsops = args->nsops;
194         return semop(&bsd_args);
195 }
196
197 int
198 linux_semget(struct linux_semget_args *args)
199 {
200         struct semget_args /* {
201         key_t   key;
202         int             nsems;
203         int             semflg;
204         } */ bsd_args;
205
206         bsd_args.key = args->key;
207         bsd_args.nsems = args->nsems;
208         bsd_args.semflg = args->semflg;
209         return semget(&bsd_args);
210 }
211
212 int
213 linux_semctl(struct linux_semctl_args *args)
214 {
215         struct proc *p = curproc;
216         struct l_semid_ds linux_semid;
217         struct __semctl_args /* {
218                 int             semid;
219                 int             semnum;
220                 int             cmd;
221                 union semun     *arg;
222         } */ bsd_args;
223         struct l_seminfo linux_seminfo;
224         int error;
225         union semun *unptr;
226         caddr_t sg;
227
228         sg = stackgap_init();
229
230         /* Make sure the arg parameter can be copied in. */
231         unptr = stackgap_alloc(&sg, sizeof(union semun));
232         bcopy(&args->arg, unptr, sizeof(union semun));
233
234         bsd_args.semid = args->semid;
235         bsd_args.semnum = args->semnum;
236         bsd_args.arg = unptr;
237
238         switch (args->cmd) {
239         case LINUX_IPC_RMID:
240                 bsd_args.cmd = IPC_RMID;
241                 break;
242         case LINUX_GETNCNT:
243                 bsd_args.cmd = GETNCNT;
244                 break;
245         case LINUX_GETPID:
246                 bsd_args.cmd = GETPID;
247                 break;
248         case LINUX_GETVAL:
249                 bsd_args.cmd = GETVAL;
250                 break;
251         case LINUX_GETZCNT:
252                 bsd_args.cmd = GETZCNT;
253                 break;
254         case LINUX_SETVAL:
255                 bsd_args.cmd = SETVAL;
256                 break;
257         case LINUX_IPC_SET:
258                 bsd_args.cmd = IPC_SET;
259                 error = copyin((caddr_t)args->arg.buf, &linux_semid,
260                     sizeof(linux_semid));
261                 if (error)
262                         return (error);
263                 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
264                 linux_to_bsd_semid_ds(&linux_semid, unptr->buf);
265                 return __semctl(&bsd_args);
266         case LINUX_IPC_STAT:
267                 bsd_args.cmd = IPC_STAT;
268                 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
269                 error = __semctl(&bsd_args);
270                 if (error)
271                         return error;
272                 p->p_retval[0] = IXSEQ_TO_IPCID(bsd_args.semid, 
273                                                         unptr->buf->sem_perm);
274                 bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
275                 return copyout(&linux_semid, (caddr_t)args->arg.buf,
276                                             sizeof(linux_semid));
277         case LINUX_IPC_INFO:
278         case LINUX_SEM_INFO:
279                 error = copyin((caddr_t)args->arg.buf, &linux_seminfo, 
280                                                 sizeof(linux_seminfo) );
281                 if (error)
282                         return error;
283                 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
284 /* XXX BSD equivalent?
285 #define used_semids 10
286 #define used_sems 10
287                 linux_seminfo.semusz = used_semids;
288                 linux_seminfo.semaem = used_sems;
289 */
290                 error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf,
291                                                 sizeof(linux_seminfo) );
292                 if (error)
293                         return error;
294                 p->p_retval[0] = seminfo.semmni;
295                 return 0;                       /* No need for __semctl call */
296         case LINUX_GETALL:
297                 /* FALLTHROUGH */
298         case LINUX_SETALL:
299                 /* FALLTHROUGH */
300         default:
301                 uprintf("linux: 'ipc' typ=%d not implemented\n", args->cmd);
302                 return EINVAL;
303         }
304         return __semctl(&bsd_args);
305 }
306
307 int
308 linux_msgsnd(struct linux_msgsnd_args *args)
309 {
310     struct msgsnd_args /* {
311         int     msqid;   
312         void    *msgp;   
313         size_t  msgsz;   
314         int     msgflg; 
315     } */ bsd_args;
316
317     bsd_args.msqid = args->msqid;
318     bsd_args.msgp = args->msgp;
319     bsd_args.msgsz = args->msgsz;
320     bsd_args.msgflg = args->msgflg;
321     return msgsnd(&bsd_args);
322 }
323
324 int
325 linux_msgrcv(struct linux_msgrcv_args *args)
326 {
327     struct msgrcv_args /* {     
328         int     msqid;   
329         void    *msgp;   
330         size_t  msgsz;   
331         long    msgtyp; 
332         int     msgflg; 
333     } */ bsd_args; 
334
335     bsd_args.msqid = args->msqid;
336     bsd_args.msgp = args->msgp;
337     bsd_args.msgsz = args->msgsz;
338     bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */
339     bsd_args.msgflg = args->msgflg;
340     return msgrcv(&bsd_args);
341 }
342
343 int
344 linux_msgget(struct linux_msgget_args *args)
345 {
346     struct msgget_args /* {
347         key_t   key;
348         int     msgflg;
349     } */ bsd_args;
350
351     bsd_args.key = args->key;
352     bsd_args.msgflg = args->msgflg;
353     return msgget(&bsd_args);
354 }
355
356 int
357 linux_msgctl(struct linux_msgctl_args *args)
358 {
359     struct msgctl_args /* {
360         int     msqid; 
361         int     cmd;
362         struct  msqid_ds *buf;
363     } */ bsd_args;
364     int error;
365
366     bsd_args.msqid = args->msqid;
367     bsd_args.cmd = args->cmd;
368     bsd_args.buf = (struct msqid_ds *)args->buf;
369     error = msgctl(&bsd_args);
370     return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
371 }
372
373 int
374 linux_shmat(struct linux_shmat_args *args)
375 {
376     struct proc *p = curproc;
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(&bsd_args)))
388         return error;
389 #ifdef __i386__
390     if ((error = copyout(p->p_retval, (caddr_t)args->raddr, sizeof(l_ulong))))
391         return error;
392     p->p_retval[0] = 0;
393 #endif
394     return 0;
395 }
396
397 int
398 linux_shmdt(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(&bsd_args);
406 }
407
408 int
409 linux_shmget(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(&bsd_args);
421 }
422
423 int
424 linux_shmctl(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(&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(&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(&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 }