Convert files to UTF-8
[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 without 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.8 2006/06/05 07:26:09 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/msg.h>
37 #include <sys/sem.h>
38 #include <sys/shm.h>
39
40 #include <arch_linux/linux.h>
41 #include <machine/limits.h>
42 #include <arch_linux/linux_proto.h>
43 #include "linux_ipc.h"
44 #include "linux_util.h"
45
46
47 static void
48 bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp)
49 {
50         lpp->shmmax = bpp->shmmax;
51         lpp->shmmin = bpp->shmmin;
52         lpp->shmmni = bpp->shmmni;
53         lpp->shmseg = bpp->shmseg;
54         lpp->shmall = bpp->shmall;
55 }
56
57 #if 0
58 static void
59 bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
60 {
61         lpp->used_ids = bpp->used_ids ;
62         lpp->shm_tot = bpp->shm_tot ;
63         lpp->shm_rss = bpp->shm_rss ;
64         lpp->shm_swp = bpp->shm_swp ;
65         lpp->swap_attempts = bpp->swap_attempts ;
66         lpp->swap_successes = bpp->swap_successes ;
67 }
68 #endif
69
70 /*
71  * MPSAFE
72  */
73 static void
74 linux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp)
75 {
76     bpp->key = lpp->key;
77     bpp->uid = lpp->uid;
78     bpp->gid = lpp->gid;
79     bpp->cuid = lpp->cuid;
80     bpp->cgid = lpp->cgid;
81     bpp->mode = lpp->mode;
82     bpp->seq = lpp->seq;
83 }
84
85 /*
86  * MPSAFE
87  */
88 static void
89 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp)
90 {
91     lpp->key = bpp->key;
92     lpp->uid = bpp->uid;
93     lpp->gid = bpp->gid;
94     lpp->cuid = bpp->cuid;
95     lpp->cgid = bpp->cgid;
96     lpp->mode = bpp->mode;
97     lpp->seq = bpp->seq;
98 }
99
100 /*
101  * MPSAFE
102  */
103 static void
104 linux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp)
105 {
106     linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
107     bsp->sem_otime = lsp->sem_otime;
108     bsp->sem_ctime = lsp->sem_ctime;
109     bsp->sem_nsems = lsp->sem_nsems;
110     bsp->sem_base = lsp->sem_base;
111 }
112
113 /*
114  * MPSAFE
115  */
116 static void
117 bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp)
118 {
119         bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
120         lsp->sem_otime = bsp->sem_otime;
121         lsp->sem_ctime = bsp->sem_ctime;
122         lsp->sem_nsems = bsp->sem_nsems;
123         lsp->sem_base = bsp->sem_base;
124 }
125
126 /*
127  * MPSAFE
128  */
129 static void
130 linux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp)
131 {
132     linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
133     bsp->shm_segsz = lsp->shm_segsz;
134     bsp->shm_lpid = lsp->shm_lpid;
135     bsp->shm_cpid = lsp->shm_cpid;
136     bsp->shm_nattch = lsp->shm_nattch;
137     bsp->shm_atime = lsp->shm_atime;
138     bsp->shm_dtime = lsp->shm_dtime;
139     bsp->shm_ctime = lsp->shm_ctime;
140 }
141
142 /*
143  * MPSAFE
144  */
145 static void
146 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp)
147 {
148     bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
149     if (bsp->shm_segsz > INT_MAX)
150             lsp->shm_segsz = INT_MAX;
151     else
152             lsp->shm_segsz = bsp->shm_segsz;
153     lsp->shm_lpid = bsp->shm_lpid;
154     lsp->shm_cpid = bsp->shm_cpid;
155     lsp->shm_nattch = bsp->shm_nattch;
156     lsp->shm_atime = bsp->shm_atime;
157     lsp->shm_dtime = bsp->shm_dtime;
158     lsp->shm_ctime = bsp->shm_ctime;
159     lsp->private3 = 0;
160 }
161
162 static void
163 linux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp)
164 {
165     linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm);
166     bsp->msg_cbytes = lsp->msg_cbytes;
167     bsp->msg_qnum = lsp->msg_qnum;
168     bsp->msg_qbytes = lsp->msg_qbytes;
169     bsp->msg_lspid = lsp->msg_lspid;
170     bsp->msg_lrpid = lsp->msg_lrpid;
171     bsp->msg_stime = lsp->msg_stime;
172     bsp->msg_rtime = lsp->msg_rtime;
173     bsp->msg_ctime = lsp->msg_ctime;
174 }
175
176 static void
177 bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp)
178 {
179     bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm);
180     lsp->msg_cbytes = bsp->msg_cbytes;
181     lsp->msg_qnum = bsp->msg_qnum;
182     lsp->msg_qbytes = bsp->msg_qbytes;
183     lsp->msg_lspid = bsp->msg_lspid;
184     lsp->msg_lrpid = bsp->msg_lrpid;
185     lsp->msg_stime = bsp->msg_stime;
186     lsp->msg_rtime = bsp->msg_rtime;
187     lsp->msg_ctime = bsp->msg_ctime;
188 }
189
190 static void
191 linux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out)
192 {
193
194         /* XXX: do we really need to do something here? */
195         out->key = in->key;
196         out->uid = in->uid;
197         out->gid = in->gid;
198         out->cuid = in->cuid;
199         out->cgid = in->cgid;
200         out->mode = in->mode;
201         out->seq = in->seq;
202 }
203
204 static int
205 linux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
206 {
207         struct l_msqid64_ds linux_msqid64;
208         int error;
209
210         if (ver == LINUX_IPC_64) {
211                 error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64));
212                 if (error != 0)
213                         return (error);
214
215                 bzero(linux_msqid, sizeof(*linux_msqid));
216
217                 linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid;
218                 linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid;
219                 linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode;
220
221                 if (linux_msqid64.msg_qbytes > USHRT_MAX)
222                         linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes;
223                 else
224                         linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes;
225         } else {
226                 error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid));
227         }
228         return (error);
229 }
230
231 static int
232 linux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
233 {
234         struct l_msqid64_ds linux_msqid64;
235
236         if (ver == LINUX_IPC_64) {
237                 bzero(&linux_msqid64, sizeof(linux_msqid64));
238
239                 linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm,
240                     &linux_msqid64.msg_perm);
241
242                 linux_msqid64.msg_stime = linux_msqid->msg_stime;
243                 linux_msqid64.msg_rtime = linux_msqid->msg_rtime;
244                 linux_msqid64.msg_ctime = linux_msqid->msg_ctime;
245
246                 if (linux_msqid->msg_cbytes == 0)
247                         linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes;
248                 else
249                         linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes;
250
251                 linux_msqid64.msg_qnum = linux_msqid->msg_qnum;
252
253                 if (linux_msqid->msg_qbytes == 0)
254                         linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes;
255                 else
256                         linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes;
257
258                 linux_msqid64.msg_lspid = linux_msqid->msg_lspid;
259                 linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid;
260
261                 return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64)));
262         } else {
263                 return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid)));
264         }
265 }
266
267 static int
268 linux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
269 {
270         struct l_semid64_ds linux_semid64;
271         int error;
272
273         if (ver == LINUX_IPC_64) {
274                 error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64));
275                 if (error != 0)
276                         return (error);
277
278                 bzero(linux_semid, sizeof(*linux_semid));
279
280                 linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid;
281                 linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid;
282                 linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode;
283         } else {
284                 error = copyin(uaddr, linux_semid, sizeof(*linux_semid));
285         }
286         return (error);
287 }
288
289 static int
290 linux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
291 {
292         struct l_semid64_ds linux_semid64;
293
294         if (ver == LINUX_IPC_64) {
295                 bzero(&linux_semid64, sizeof(linux_semid64));
296
297                 linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm,
298                     &linux_semid64.sem_perm);
299
300                 linux_semid64.sem_otime = linux_semid->sem_otime;
301                 linux_semid64.sem_ctime = linux_semid->sem_ctime;
302                 linux_semid64.sem_nsems = linux_semid->sem_nsems;
303
304                 return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64)));
305         } else {
306                 return (copyout(linux_semid, uaddr, sizeof(*linux_semid)));
307         }
308 }
309
310 static int
311 linux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
312 {
313         struct l_shmid64_ds linux_shmid64;
314         int error;
315
316         if (ver == LINUX_IPC_64) {
317                 error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64));
318                 if (error != 0)
319                         return (error);
320
321                 bzero(linux_shmid, sizeof(*linux_shmid));
322
323                 linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid;
324                 linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid;
325                 linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode;
326         } else {
327                 error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid));
328         }
329         return (error);
330 }
331
332 static int
333 linux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
334 {
335         struct l_shmid64_ds linux_shmid64;
336
337         /*
338          * XXX: This is backwards and loses information in shm_nattch
339          * and shm_segsz.  We should probably either expose the BSD
340          * shmid structure directly and convert it to either the
341          * non-64 or 64 variant directly or the code should always
342          * convert to the 64 variant and then truncate values into the
343          * non-64 variant if needed since the 64 variant has more
344          * precision.
345          */
346         if (ver == LINUX_IPC_64) {
347                 bzero(&linux_shmid64, sizeof(linux_shmid64));
348
349                 linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm,
350                     &linux_shmid64.shm_perm);
351
352                 linux_shmid64.shm_segsz = linux_shmid->shm_segsz;
353                 linux_shmid64.shm_atime = linux_shmid->shm_atime;
354                 linux_shmid64.shm_dtime = linux_shmid->shm_dtime;
355                 linux_shmid64.shm_ctime = linux_shmid->shm_ctime;
356                 linux_shmid64.shm_cpid = linux_shmid->shm_cpid;
357                 linux_shmid64.shm_lpid = linux_shmid->shm_lpid;
358                 linux_shmid64.shm_nattch = linux_shmid->shm_nattch;
359
360                 return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64)));
361         } else {
362                 return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid)));
363         }
364 }
365
366 static int
367 linux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo,
368     caddr_t uaddr)
369 {
370         struct l_shminfo64 linux_shminfo64;
371
372         if (ver == LINUX_IPC_64) {
373                 bzero(&linux_shminfo64, sizeof(linux_shminfo64));
374
375                 linux_shminfo64.shmmax = linux_shminfo->shmmax;
376                 linux_shminfo64.shmmin = linux_shminfo->shmmin;
377                 linux_shminfo64.shmmni = linux_shminfo->shmmni;
378                 linux_shminfo64.shmseg = linux_shminfo->shmseg;
379                 linux_shminfo64.shmall = linux_shminfo->shmall;
380
381                 return (copyout(&linux_shminfo64, uaddr,
382                     sizeof(linux_shminfo64)));
383         } else {
384                 return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo)));
385         }
386 }
387
388 /*
389  * MPSAFE
390  */
391 int
392 linux_semop(struct linux_semop_args *args)
393 {
394         struct semop_args bsd_args;
395         int error;
396
397         bsd_args.sysmsg_result = 0;
398         bsd_args.semid = args->semid;
399         bsd_args.sops = (struct sembuf *)args->tsops;
400         bsd_args.nsops = args->nsops;
401         error = sys_semop(&bsd_args);
402         args->sysmsg_result = bsd_args.sysmsg_result;
403         return(error);
404 }
405
406 /*
407  * MPSAFE
408  */
409 int
410 linux_semget(struct linux_semget_args *args)
411 {
412         struct semget_args bsd_args;
413         int error;
414
415         bsd_args.sysmsg_result = 0;
416         bsd_args.key = args->key;
417         bsd_args.nsems = args->nsems;
418         bsd_args.semflg = args->semflg;
419         error = sys_semget(&bsd_args);
420         args->sysmsg_result = bsd_args.sysmsg_result;
421         return(error);
422 }
423
424 /*
425  * MPSAFE
426  */
427 int
428 linux_semctl(struct linux_semctl_args *args)
429 {
430         struct l_semid_ds linux_semid;
431         struct __semctl_args bsd_args;
432         struct l_seminfo linux_seminfo;
433         int error;
434         union semun *unptr;
435         caddr_t sg;
436
437         sg = stackgap_init();
438
439         /* Make sure the arg parameter can be copied in. */
440         unptr = stackgap_alloc(&sg, sizeof(union semun));
441         bcopy(&args->arg, unptr, sizeof(union semun));
442
443         bsd_args.sysmsg_result = 0;
444         bsd_args.semid = args->semid;
445         bsd_args.semnum = args->semnum;
446         bsd_args.arg = unptr;
447
448         switch (args->cmd & ~LINUX_IPC_64) {
449         case LINUX_IPC_RMID:
450                 bsd_args.cmd = IPC_RMID;
451                 break;
452         case LINUX_GETNCNT:
453                 bsd_args.cmd = GETNCNT;
454                 break;
455         case LINUX_GETPID:
456                 bsd_args.cmd = GETPID;
457                 break;
458         case LINUX_GETVAL:
459                 bsd_args.cmd = GETVAL;
460                 break;
461         case LINUX_GETZCNT:
462                 bsd_args.cmd = GETZCNT;
463                 break;
464         case LINUX_SETVAL:
465                 bsd_args.cmd = SETVAL;
466                 break;
467         case LINUX_IPC_SET:
468                 bsd_args.cmd = IPC_SET;
469                 error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
470                     &linux_semid, (caddr_t)args->arg.buf);
471                 if (error)
472                         return (error);
473                 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
474                 linux_to_bsd_semid_ds(&linux_semid, unptr->buf);
475                 break;
476         case LINUX_IPC_STAT:
477         case LINUX_SEM_STAT:
478                 if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT)
479                         bsd_args.cmd = IPC_STAT;
480                 else
481                         bsd_args.cmd = SEM_STAT;
482                 unptr->buf = stackgap_alloc(&sg, sizeof(struct semid_ds));
483                 error = sys___semctl(&bsd_args);
484                 if (error)
485                         return error;
486                 args->sysmsg_result = IXSEQ_TO_IPCID(bsd_args.semid, 
487                                                         unptr->buf->sem_perm);
488                 bsd_to_linux_semid_ds(unptr->buf, &linux_semid);
489                 error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
490                     &linux_semid, (caddr_t)(args->arg.buf));
491                 if (error == 0)
492                         args->sysmsg_iresult = ((args->cmd & ~LINUX_IPC_64) == SEM_STAT)
493                             ? bsd_args.sysmsg_result : 0;
494                 return (error);
495         case LINUX_IPC_INFO:
496         case LINUX_SEM_INFO:
497                 error = copyin((caddr_t)args->arg.buf, &linux_seminfo, 
498                                                 sizeof(linux_seminfo) );
499                 if (error)
500                         return error;
501                 bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
502 /* XXX BSD equivalent?
503 #define used_semids 10
504 #define used_sems 10
505                 linux_seminfo.semusz = used_semids;
506                 linux_seminfo.semaem = used_sems;
507 */
508                 error = copyout((caddr_t)&linux_seminfo, (caddr_t)args->arg.buf,
509                                                 sizeof(linux_seminfo) );
510                 if (error)
511                         return error;
512                 args->sysmsg_result = seminfo.semmni;
513                 return 0;                       /* No need for __semctl call */
514         case LINUX_GETALL:
515                 bsd_args.cmd = GETALL;
516                 break;
517         case LINUX_SETALL:
518                 bsd_args.cmd = SETALL;
519                 break;
520         default:
521                 uprintf("linux: 'ipc' type=%d not implemented\n", args->cmd & ~LINUX_IPC_64);
522                 return EINVAL;
523         }
524         error = sys___semctl(&bsd_args);
525         args->sysmsg_result = bsd_args.sysmsg_result;
526         return(error);
527 }
528
529 /*
530  * MPSAFE
531  */
532 int
533 linux_msgsnd(struct linux_msgsnd_args *args)
534 {
535     struct msgsnd_args bsd_args;
536     int error;
537
538     if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
539         return (EINVAL);
540     bsd_args.sysmsg_result = 0;
541     bsd_args.msqid = args->msqid;
542     bsd_args.msgp = args->msgp;
543     bsd_args.msgsz = args->msgsz;
544     bsd_args.msgflg = args->msgflg;
545     error = sys_msgsnd(&bsd_args);
546     args->sysmsg_result = bsd_args.sysmsg_result;
547     return(error);
548 }
549
550 /*
551  * MPSAFE
552  */
553 int
554 linux_msgrcv(struct linux_msgrcv_args *args)
555 {
556     struct msgrcv_args bsd_args; 
557     int error;
558     if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
559             return (EINVAL);
560     bsd_args.sysmsg_result = 0;
561     bsd_args.msqid = args->msqid;
562     bsd_args.msgp = args->msgp;
563     bsd_args.msgsz = args->msgsz;
564     bsd_args.msgtyp = 0; /* XXX - args->msgtyp; */
565     bsd_args.msgflg = args->msgflg;
566     error = sys_msgrcv(&bsd_args);
567     args->sysmsg_result = bsd_args.sysmsg_result;
568     return(error);
569 }
570
571 /*
572  * MPSAFE
573  */
574 int
575 linux_msgget(struct linux_msgget_args *args)
576 {
577     struct msgget_args bsd_args;
578     int error;
579
580     bsd_args.sysmsg_result = 0;
581     bsd_args.key = args->key;
582     bsd_args.msgflg = args->msgflg;
583     error = sys_msgget(&bsd_args);
584     args->sysmsg_result = bsd_args.sysmsg_result;
585     return(error);
586 }
587
588 /*
589  * MPSAFE
590  */
591 int
592 linux_msgctl(struct linux_msgctl_args *args)
593 {
594     struct msgctl_args bsd_args;
595     struct l_msqid_ds linux_msqid;
596     int error, bsd_cmd;
597     struct msqid_ds *unptr;
598     caddr_t sg;
599    
600    sg = stackgap_init();
601         /* Make sure the arg parameter can be copied in. */
602         unptr = stackgap_alloc(&sg, sizeof(struct msqid_ds));
603         bcopy(&args->buf, unptr, sizeof(struct msqid_ds));
604
605     bsd_cmd = args->cmd & ~LINUX_IPC_64;
606     bsd_args.sysmsg_result = 0;
607     bsd_args.msqid = args->msqid;
608     bsd_args.cmd = bsd_cmd;
609     bsd_args.buf = unptr;
610     switch(bsd_cmd) {
611     case LINUX_IPC_INFO:
612     case LINUX_MSG_INFO: {
613         struct l_msginfo linux_msginfo;
614
615         /*
616          * XXX MSG_INFO uses the same data structure but returns different
617          * dynamic counters in msgpool, msgmap, and msgtql fields.
618          */
619         linux_msginfo.msgpool = (long)msginfo.msgmni *
620             (long)msginfo.msgmnb / 1024L;       /* XXX MSG_INFO. */
621         linux_msginfo.msgmap = msginfo.msgmnb;  /* XXX MSG_INFO. */
622         linux_msginfo.msgmax = msginfo.msgmax;
623         linux_msginfo.msgmnb = msginfo.msgmnb;
624         linux_msginfo.msgmni = msginfo.msgmni;
625         linux_msginfo.msgssz = msginfo.msgssz;
626         linux_msginfo.msgtql = msginfo.msgtql;  /* XXX MSG_INFO. */
627         linux_msginfo.msgseg = msginfo.msgseg;
628         error = copyout(&linux_msginfo, PTRIN(args->buf),
629             sizeof(linux_msginfo));
630         if (error == 0)
631             args->sysmsg_iresult = msginfo.msgmni;      /* XXX */
632
633         return (error);
634     }
635
636 /*
637  * TODO: implement this
638  * case LINUX_MSG_STAT:
639  */
640     case LINUX_IPC_STAT:
641         /* NOTHING */
642         break;
643
644     case LINUX_IPC_SET:
645         error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
646             &linux_msqid, (caddr_t)(args->buf));
647         if (error)
648             return (error);
649         linux_to_bsd_msqid_ds(&linux_msqid, unptr);
650         break;
651
652     case LINUX_IPC_RMID:
653         /* NOTHING */
654         break;
655
656     default:
657         return (EINVAL);
658         break;
659     }
660
661     error = sys_msgctl(&bsd_args);
662     if (error != 0)
663         if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
664             return (error);
665     if (bsd_cmd == LINUX_IPC_STAT) {
666         bsd_to_linux_msqid_ds(bsd_args.buf, &linux_msqid);
667         return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
668           &linux_msqid, PTRIN(args->buf)));
669     }
670     args->sysmsg_result = bsd_args.sysmsg_result;
671     return ((args->cmd == LINUX_IPC_RMID && error == EINVAL) ? 0 : error);
672
673
674
675
676 }
677
678 /*
679  * MPSAFE
680  */
681 int
682 linux_shmat(struct linux_shmat_args *args)
683 {
684     struct shmat_args bsd_args;
685     int error;
686
687     bsd_args.sysmsg_result = 0;
688     bsd_args.shmid = args->shmid;
689     bsd_args.shmaddr = args->shmaddr;
690     bsd_args.shmflg = args->shmflg;
691     if ((error = sys_shmat(&bsd_args)))
692         return error;
693 #ifdef __i386__
694     if ((error = copyout(&bsd_args.sysmsg_lresult, (caddr_t)args->raddr, sizeof(l_ulong))))
695         return error;
696     args->sysmsg_result = 0;
697 #else
698     args->sysmsg_result = bsd_args.sysmsg_result;
699 #endif
700     return 0;
701 }
702
703 /*
704  * MPSAFE
705  */
706 int
707 linux_shmdt(struct linux_shmdt_args *args)
708 {
709     struct shmdt_args bsd_args;
710     int error;
711
712     bsd_args.sysmsg_result = 0;
713     bsd_args.shmaddr = args->shmaddr;
714     error = sys_shmdt(&bsd_args);
715     args->sysmsg_result = bsd_args.sysmsg_result;
716     return(error);
717 }
718
719 /*
720  * MPSAFE
721  */
722 int
723 linux_shmget(struct linux_shmget_args *args)
724 {
725     struct shmget_args bsd_args;
726     int error;
727
728     bsd_args.sysmsg_result = 0;
729     bsd_args.key = args->key;
730     bsd_args.size = args->size;
731     bsd_args.shmflg = args->shmflg;
732     error = sys_shmget(&bsd_args);
733     args->sysmsg_result = bsd_args.sysmsg_result;
734     return(error);
735 }
736
737 /*
738  * MPSAFE
739  */
740 extern int shm_nused;
741 int
742 linux_shmctl(struct linux_shmctl_args *args)
743 {
744     struct l_shmid_ds linux_shmid;
745     struct l_shminfo linux_shminfo;
746     struct l_shm_info linux_shm_info;
747     struct shmctl_args bsd_args;
748     int error;
749     caddr_t sg = stackgap_init();
750
751     bsd_args.sysmsg_result = 0;
752     switch (args->cmd & ~LINUX_IPC_64) {
753     case LINUX_IPC_STAT:
754     case LINUX_SHM_STAT:
755         bsd_args.shmid = args->shmid;
756         bsd_args.cmd = IPC_STAT;
757         bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
758         if ((error = sys_shmctl(&bsd_args)))
759             return error;
760         bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
761         args->sysmsg_result = bsd_args.sysmsg_result;
762         return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
763              &linux_shmid, PTRIN(args->buf)));
764
765     case LINUX_IPC_SET:
766         if ((error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
767           &linux_shmid, PTRIN(args->buf))))
768             return error;
769         bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
770         linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
771         bsd_args.shmid = args->shmid;
772         bsd_args.cmd = IPC_SET;
773         break;
774     case LINUX_IPC_RMID:
775         bsd_args.shmid = args->shmid;
776         bsd_args.cmd = IPC_RMID;
777         if (args->buf == NULL)
778             bsd_args.buf = NULL;
779         else {
780             if ((error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
781                     &linux_shmid, PTRIN(args->buf))))
782                 return error;
783             bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
784             linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
785         }
786         break;
787     case LINUX_IPC_INFO:
788         bsd_to_linux_shminfo(&shminfo, &linux_shminfo);
789         return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
790             &linux_shminfo, PTRIN(args->buf)));
791         break;
792     case LINUX_SHM_INFO:
793         linux_shm_info.used_ids = shm_nused;
794         linux_shm_info.shm_tot = 0;
795         linux_shm_info.shm_rss = 0;
796         linux_shm_info.shm_swp = 0;
797         linux_shm_info.swap_attempts = 0;
798         linux_shm_info.swap_successes = 0;
799         return copyout(&linux_shm_info, PTRIN(args->buf),
800             sizeof(struct l_shm_info));
801     
802     case LINUX_SHM_LOCK:
803     case LINUX_SHM_UNLOCK:
804     default:
805         uprintf("linux: 'ipc' type=%d not implemented\n", args->cmd & ~LINUX_IPC_64);
806         return EINVAL;
807     }
808     error = sys_shmctl(&bsd_args);
809     args->sysmsg_result = bsd_args.sysmsg_result;
810     return(error);
811 }