1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <errno.h>
29 #include <unistd.h>
30 #include <strings.h>
31 #include <rctl.h>
32 #include <alloca.h>
33 #include <values.h>
34 #include <sys/syscall.h>
35 #include <sys/msg.h>
36 #include <sys/ipc.h>
37 #include <sys/sem.h>
38 #include <sys/shm.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/lx_debug.h>
42 #include <sys/lx_types.h>
43 #include <sys/lx_sysv_ipc.h>
44 #include <sys/lx_misc.h>
45 #include <sys/lx_syscall.h>
46
47 #define SLOT_SEM 0
48 #define SLOT_SHM 1
49 #define SLOT_MSG 2
50
51 static int
52 get_rctlval(rctlblk_t *rblk, char *name)
53 {
54 rctl_qty_t r;
55
56 if (getrctl(name, NULL, rblk, RCTL_FIRST) == -1)
57 return (-errno);
58
59 r = rctlblk_get_value(rblk);
60 if (r > MAXINT)
61 return (-EOVERFLOW);
62 return (r);
63 }
64
65 /*
66 * Given a slot number and a maximum number of ids to extract from the
67 * kernel, return the msgid in the provided slot.
68 */
69 static int
70 slot_to_id(int type, int slot)
71 {
72 uint_t nids, max;
73 int *idbuf = NULL;
74 int r = 0;
75
76 nids = 0;
77 for (;;) {
78 switch (type) {
79 case SLOT_SEM:
80 r = semids(idbuf, nids, &max);
81 break;
82 case SLOT_SHM:
83 r = shmids(idbuf, nids, &max);
84 break;
85 case SLOT_MSG:
86 r = msgids(idbuf, nids, &max);
87 break;
88 }
89
90 if (r < 0)
91 return (-errno);
92
93 if (max == 0)
94 return (-EINVAL);
95
96 if (max <= nids)
97 return (idbuf[slot]);
98
99 nids = max;
100 if ((idbuf = (int *)SAFE_ALLOCA(sizeof (int) * nids)) == NULL)
101 return (-ENOMEM);
102 }
103 }
104
105 /*
106 * Semaphore operations.
107 */
108 static int
109 lx_semget(key_t key, int nsems, int semflg)
110 {
111 int sol_flag;
112 int r;
113
114 lx_debug("\nsemget(%d, %d, %d)\n", key, nsems, semflg);
115 sol_flag = semflg & S_IAMB;
116 if (semflg & LX_IPC_CREAT)
117 sol_flag |= IPC_CREAT;
118 if (semflg & LX_IPC_EXCL)
119 sol_flag |= IPC_EXCL;
120
121 r = semget(key, nsems, sol_flag);
122 return ((r < 0) ? -errno : r);
123 }
124
125 static int
126 lx_semop(int semid, struct sembuf *sops, size_t nsops)
127 {
128 int r;
129
130 lx_debug("\nsemop(%d, 0x%p, %u)\n", semid, sops, nsops);
131 if (nsops == 0)
132 return (-EINVAL);
133
134 r = semop(semid, sops, nsops);
135 return ((r < 0) ? -errno : r);
136 }
137
138 static int
139 lx_semctl_ipcset(int semid, void *buf)
140 {
141 struct lx_semid_ds semds;
142 struct semid_ds sol_semds;
143 int r;
144
145 if (uucopy(buf, &semds, sizeof (semds)))
146 return (-errno);
147
148 bzero(&sol_semds, sizeof (sol_semds));
149 sol_semds.sem_perm.uid = semds.sem_perm.uid;
150 sol_semds.sem_perm.gid = semds.sem_perm.gid;
151 sol_semds.sem_perm.mode = semds.sem_perm.mode;
152
153 r = semctl(semid, 0, IPC_SET, &sol_semds);
154 return ((r < 0) ? -errno : r);
155 }
156
157 static int
158 lx_semctl_ipcstat(int semid, void *buf)
159 {
160 struct lx_semid_ds semds;
161 struct semid_ds sol_semds;
162
163 if (semctl(semid, 0, IPC_STAT, &sol_semds) != 0)
164 return (-errno);
165
166 bzero(&semds, sizeof (semds));
167 semds.sem_perm.key = sol_semds.sem_perm.key;
168 semds.sem_perm.seq = sol_semds.sem_perm.seq;
169 semds.sem_perm.uid = sol_semds.sem_perm.uid;
170 semds.sem_perm.gid = sol_semds.sem_perm.gid;
171 semds.sem_perm.cuid = sol_semds.sem_perm.cuid;
172 semds.sem_perm.cgid = sol_semds.sem_perm.cgid;
173
174 /* Linux only uses the bottom 9 bits */
175 semds.sem_perm.mode = sol_semds.sem_perm.mode & S_IAMB;
176 semds.sem_otime = sol_semds.sem_otime;
177 semds.sem_ctime = sol_semds.sem_ctime;
178 semds.sem_nsems = sol_semds.sem_nsems;
179
180 if (uucopy(&semds, buf, sizeof (semds)))
181 return (-errno);
182
183 return (0);
184 }
185
186 static int
187 lx_semctl_ipcinfo(void *buf)
188 {
189 struct lx_seminfo i;
190 rctlblk_t *rblk;
191 int rblksz;
192 uint_t nids;
193 int idbuf;
194
195 rblksz = rctlblk_size();
196 if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
197 return (-ENOMEM);
198
199 bzero(&i, sizeof (i));
200 if ((i.semmni = get_rctlval(rblk, "project.max-sem-ids")) < 0)
201 return (i.semmni);
202 if ((i.semmsl = get_rctlval(rblk, "process.max-sem-nsems")) < 0)
203 return (i.semmsl);
204 if ((i.semopm = get_rctlval(rblk, "process.max-sem-ops")) < 0)
205 return (i.semopm);
206
207 /*
208 * We don't have corresponding rctls for these fields. The values
209 * are taken from the formulas used to derive the defaults listed
210 * in the Linux header file. We're lying, but trying to be
211 * coherent about it.
212 */
213 i.semmap = i.semmni;
214 i.semmns = i.semmni * i.semmsl;
215 i.semmnu = INT_MAX;
216 i.semume = INT_MAX;
217 i.semvmx = LX_SEMVMX;
218 if (semids(&idbuf, 0, &nids) < 0)
219 return (-errno);
220 i.semusz = nids;
221 i.semaem = INT_MAX;
222
223 if (uucopy(&i, buf, sizeof (i)) != 0)
224 return (-errno);
225
226 return (nids);
227 }
228
229 static int
230 lx_semctl_semstat(int slot, void *buf)
231 {
232 int r, semid;
233
234 semid = slot_to_id(SLOT_SEM, slot);
235 if (semid < 0)
236 return (semid);
237
238 r = lx_semctl_ipcstat(semid, buf);
239 return (r < 0 ? r : semid);
240 }
241
242 /*
243 * For the SETALL operation, we have to examine each of the semaphore
244 * values to be sure it is legal.
245 */
246 static int
247 lx_semctl_setall(int semid, union lx_semun *arg)
248 {
249 struct semid_ds semds;
250 ushort_t *vals;
251 int i, sz, r;
252
253 /*
254 * Find out how many semaphores are involved, reserve enough
255 * memory for an internal copy of the array, and then copy it in
256 * from the process.
257 */
258 if (semctl(semid, 0, IPC_STAT, &semds) != 0)
259 return (-errno);
260 sz = semds.sem_nsems * sizeof (ushort_t);
261 if ((vals = SAFE_ALLOCA(sz)) == NULL)
262 return (-ENOMEM);
263 if (uucopy(arg->sems, vals, sz))
264 return (-errno);
265
266 /* Validate each of the values. */
267 for (i = 0; i < semds.sem_nsems; i++)
268 if (vals[i] > LX_SEMVMX)
269 return (-ERANGE);
270
271 r = semctl(semid, 0, SETALL, arg->sems);
272
273 return ((r < 0) ? -errno : r);
274 }
275
276 static int
277 lx_semctl(int semid, int semnum, int cmd, void *ptr)
278 {
279 union lx_semun arg;
280 int rval;
281 int opt = cmd & ~LX_IPC_64;
282 int use_errno = 0;
283
284 lx_debug("\nsemctl(%d, %d, %d, 0x%p)\n", semid, semnum, cmd, ptr);
285
286 /*
287 * The final arg to semctl() is a pointer to a union. For some
288 * commands we can hand that pointer directly to the kernel. For
289 * these commands, we need to extract an argument from the union
290 * before calling into the kernel.
291 */
292 if (opt == LX_SETVAL || opt == LX_SETALL || opt == LX_GETALL ||
293 opt == LX_IPC_SET || opt == LX_IPC_STAT || opt == LX_SEM_STAT ||
294 opt == LX_IPC_INFO || opt == LX_SEM_INFO)
295 if (uucopy(ptr, &arg, sizeof (arg)))
296 return (-errno);
297
298 switch (opt) {
299 case LX_GETVAL:
300 use_errno = 1;
301 rval = semctl(semid, semnum, GETVAL, NULL);
302 break;
303 case LX_SETVAL:
304 if (arg.val > LX_SEMVMX) {
305 rval = -ERANGE;
306 break;
307 }
308 use_errno = 1;
309 rval = semctl(semid, semnum, SETVAL, arg.val);
310 break;
311 case LX_GETPID:
312 use_errno = 1;
313 rval = semctl(semid, semnum, GETPID, NULL);
314 break;
315 case LX_GETNCNT:
316 use_errno = 1;
317 rval = semctl(semid, semnum, GETNCNT, NULL);
318 break;
319 case LX_GETZCNT:
320 use_errno = 1;
321 rval = semctl(semid, semnum, GETZCNT, NULL);
322 break;
323 case LX_GETALL:
324 use_errno = 1;
325 rval = semctl(semid, semnum, GETALL, arg.sems);
326 break;
327 case LX_SETALL:
328 rval = lx_semctl_setall(semid, &arg);
329 break;
330 case LX_IPC_RMID:
331 use_errno = 1;
332 rval = semctl(semid, semnum, IPC_RMID, NULL);
333 break;
334 case LX_SEM_STAT:
335 rval = lx_semctl_semstat(semid, arg.semds);
336 break;
337 case LX_IPC_STAT:
338 rval = lx_semctl_ipcstat(semid, arg.semds);
339 break;
340
341 case LX_IPC_SET:
342 rval = lx_semctl_ipcset(semid, arg.semds);
343 break;
344
345 case LX_IPC_INFO:
346 case LX_SEM_INFO:
347 rval = lx_semctl_ipcinfo(arg.semds);
348 break;
349
350 default:
351 rval = -EINVAL;
352 }
353
354 if (use_errno == 1 && rval < 0)
355 return (-errno);
356 return (rval);
357 }
358
359 /*
360 * msg operations.
361 */
362 static int
363 lx_msgget(key_t key, int flag)
364 {
365 int sol_flag;
366 int r;
367
368 lx_debug("\tlx_msgget(%d, %d)\n", key, flag);
369
370 sol_flag = flag & S_IAMB;
371 if (flag & LX_IPC_CREAT)
372 sol_flag |= IPC_CREAT;
373 if (flag & LX_IPC_EXCL)
374 sol_flag |= IPC_EXCL;
375
376 r = msgget(key, sol_flag);
377 return (r < 0 ? -errno : r);
378 }
379
380 static int
381 lx_msgsnd(int id, struct msgbuf *buf, size_t sz, int flag)
382 {
383 int sol_flag = 0;
384 int r;
385
386 lx_debug("\tlx_msgsnd(%d, 0x%p, %d, %d)\n", id, buf, sz, flag);
387
388 if (flag & LX_IPC_NOWAIT)
389 sol_flag |= IPC_NOWAIT;
390
391 if (((ssize_t)sz < 0) || (sz > LX_MSGMAX))
392 return (-EINVAL);
393
394 r = msgsnd(id, buf, sz, sol_flag);
395 return (r < 0 ? -errno : r);
396 }
397
398 static int
399 lx_msgrcv(int id, struct msgbuf *buf, size_t sz, int flag)
400 {
401 int sol_flag = 0;
402 struct {
403 void *msgp;
404 long msgtype;
405 } args;
406 int r;
407
408 /*
409 * Rather than passing 5 args into ipc(2) directly, glibc passes 4
410 * args and uses the buf argument to point to a structure
411 * containing two args: a pointer to the message and the message
412 * type.
413 */
414 if (uucopy(buf, &args, sizeof (args)))
415 return (-errno);
416
417 lx_debug("\tlx_msgrcv(%d, 0x%p, %d, %d, %ld, %d)\n",
418 id, args.msgp, sz, args.msgtype, flag);
419
420 /*
421 * Check for a negative sz parameter.
422 *
423 * Unlike msgsnd(2), the Linux man page does not specify that
424 * msgrcv(2) should return EINVAL if (sz > MSGMAX), only if (sz < 0).
425 */
426 if ((ssize_t)sz < 0)
427 return (-EINVAL);
428
429 if (flag & LX_MSG_NOERROR)
430 sol_flag |= MSG_NOERROR;
431 if (flag & LX_IPC_NOWAIT)
432 sol_flag |= IPC_NOWAIT;
433
434 r = msgrcv(id, args.msgp, sz, args.msgtype, sol_flag);
435 return (r < 0 ? -errno : r);
436 }
437
438 static int
439 lx_msgctl_ipcstat(int msgid, void *buf)
440 {
441 struct lx_msqid_ds msgids;
442 struct msqid_ds sol_msgids;
443 int r;
444
445 r = msgctl(msgid, IPC_STAT, &sol_msgids);
446 if (r < 0)
447 return (-errno);
448
449 bzero(&msgids, sizeof (msgids));
450 msgids.msg_perm.key = sol_msgids.msg_perm.key;
451 msgids.msg_perm.seq = sol_msgids.msg_perm.seq;
452 msgids.msg_perm.uid = sol_msgids.msg_perm.uid;
453 msgids.msg_perm.gid = sol_msgids.msg_perm.gid;
454 msgids.msg_perm.cuid = sol_msgids.msg_perm.cuid;
455 msgids.msg_perm.cgid = sol_msgids.msg_perm.cgid;
456
457 /* Linux only uses the bottom 9 bits */
458 msgids.msg_perm.mode = sol_msgids.msg_perm.mode & S_IAMB;
459
460 msgids.msg_stime = sol_msgids.msg_stime;
461 msgids.msg_rtime = sol_msgids.msg_rtime;
462 msgids.msg_ctime = sol_msgids.msg_ctime;
463 msgids.msg_qbytes = sol_msgids.msg_qbytes;
464 msgids.msg_cbytes = sol_msgids.msg_cbytes;
465 msgids.msg_qnum = sol_msgids.msg_qnum;
466 msgids.msg_lspid = sol_msgids.msg_lspid;
467 msgids.msg_lrpid = sol_msgids.msg_lrpid;
468
469 if (uucopy(&msgids, buf, sizeof (msgids)))
470 return (-errno);
471
472 return (0);
473 }
474
475 static int
476 lx_msgctl_ipcinfo(int cmd, void *buf)
477 {
478 struct lx_msginfo m;
479 rctlblk_t *rblk;
480 int idbuf, rblksz, msgseg, maxmsgs;
481 uint_t nids;
482 int rval;
483
484 rblksz = rctlblk_size();
485 if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
486 return (-ENOMEM);
487
488 bzero(&m, sizeof (m));
489 if ((m.msgmni = get_rctlval(rblk, "project.max-msg-ids")) < 0)
490 return (m.msgmni);
491 if ((m.msgmnb = get_rctlval(rblk, "process.max-msg-qbytes")) < 0)
492 return (m.msgmnb);
493
494 if (cmd == LX_IPC_INFO) {
495 if ((maxmsgs = get_rctlval(rblk,
496 "process.max-msg-messages")) < 0)
497 return (maxmsgs);
498 m.msgtql = maxmsgs * m.msgmni;
499 m.msgmap = m.msgmnb;
500 m.msgpool = m.msgmax * m.msgmnb;
501 rval = 0;
502 } else {
503 if (msgids(&idbuf, 0, &nids) < 0)
504 return (-errno);
505 m.msgpool = nids;
506
507 /*
508 * For these fields, we can't even come up with a good fake
509 * approximation. These are listed as 'obsolete' or
510 * 'unused' in the header files, so hopefully nobody is
511 * relying on them anyway.
512 */
513 m.msgtql = INT_MAX;
514 m.msgmap = INT_MAX;
515 rval = nids;
516 }
517
518 /*
519 * We don't have corresponding rctls for these fields. The values
520 * are taken from the formulas used to derive the defaults listed
521 * in the Linux header file. We're lying, but trying to be
522 * coherent about it.
523 */
524 m.msgmax = m.msgmnb;
525 m.msgssz = 16;
526 msgseg = (m.msgpool * 1024) / m.msgssz;
527 m.msgseg = (msgseg > 0xffff) ? 0xffff : msgseg;
528
529 if (uucopy(&m, buf, sizeof (m)))
530 return (-errno);
531 return (rval);
532 }
533
534 static int
535 lx_msgctl_ipcset(int msgid, void *buf)
536 {
537 struct lx_msqid_ds msgids;
538 struct msqid_ds sol_msgids;
539 int r;
540
541 if (uucopy(buf, &msgids, sizeof (msgids)))
542 return (-errno);
543
544 bzero(&sol_msgids, sizeof (sol_msgids));
545 sol_msgids.msg_perm.uid = LX_UID16_TO_UID32(msgids.msg_perm.uid);
546 sol_msgids.msg_perm.gid = LX_UID16_TO_UID32(msgids.msg_perm.gid);
547
548 /* Linux only uses the bottom 9 bits */
549 sol_msgids.msg_perm.mode = msgids.msg_perm.mode & S_IAMB;
550 sol_msgids.msg_qbytes = msgids.msg_qbytes;
551
552 r = msgctl(msgid, IPC_SET, &sol_msgids);
553 return (r < 0 ? -errno : r);
554 }
555
556 static int
557 lx_msgctl_msgstat(int slot, void *buf)
558 {
559 int r, msgid;
560
561 lx_debug("msgstat(%d, 0x%p)\n", slot, buf);
562
563 msgid = slot_to_id(SLOT_MSG, slot);
564
565 if (msgid < 0)
566 return (msgid);
567
568 r = lx_msgctl_ipcstat(msgid, buf);
569 return (r < 0 ? r : msgid);
570 }
571
572 /*
573 * Split off the various msgctl's here
574 */
575 static int
576 lx_msgctl(int msgid, int cmd, void *buf)
577 {
578 int r;
579
580 lx_debug("\tlx_msgctl(%d, %d, 0x%p)\n", msgid, cmd, buf);
581 switch (cmd & ~LX_IPC_64) {
582 case LX_IPC_RMID:
583 r = msgctl(msgid, IPC_RMID, NULL);
584 if (r < 0)
585 r = -errno;
586 break;
587 case LX_IPC_SET:
588 r = lx_msgctl_ipcset(msgid, buf);
589 break;
590 case LX_IPC_STAT:
591 r = lx_msgctl_ipcstat(msgid, buf);
592 break;
593 case LX_MSG_STAT:
594 r = lx_msgctl_msgstat(msgid, buf);
595 break;
596
597 case LX_IPC_INFO:
598 case LX_MSG_INFO:
599 r = lx_msgctl_ipcinfo(cmd, buf);
600 break;
601
602 default:
603 r = -EINVAL;
604 break;
605 }
606
607 return (r);
608 }
609
610 /*
611 * shm-related operations.
612 */
613 static int
614 lx_shmget(key_t key, size_t size, int flag)
615 {
616 int sol_flag;
617 int r;
618
619 lx_debug("\tlx_shmget(%d, %d, %d)\n", key, size, flag);
620
621 sol_flag = flag & S_IAMB;
622 if (flag & LX_IPC_CREAT)
623 sol_flag |= IPC_CREAT;
624 if (flag & LX_IPC_EXCL)
625 sol_flag |= IPC_EXCL;
626
627 r = shmget(key, size, sol_flag);
628 return (r < 0 ? -errno : r);
629 }
630
631 static int
632 lx_shmat(int shmid, void *addr, int flags, void **rval)
633 {
634 int sol_flags;
635 void *ptr;
636
637 lx_debug("\tlx_shmat(%d, 0x%p, %d, 0%o)\n", shmid, addr, flags);
638
639 sol_flags = 0;
640 if (flags & LX_SHM_RDONLY)
641 sol_flags |= SHM_RDONLY;
642 if (flags & LX_SHM_RND)
643 sol_flags |= SHM_RND;
644 if ((flags & LX_SHM_REMAP) && (addr == NULL))
645 return (-EINVAL);
646
647 ptr = shmat(shmid, addr, sol_flags);
648 if (ptr == (void *)-1)
649 return (-errno);
650 if (uucopy(&ptr, rval, sizeof (ptr)) != 0)
651 return (-errno);
652
653 return (0);
654 }
655
656 static int
657 lx_shmctl_ipcinfo(void *buf)
658 {
659 struct lx_shminfo s;
660 rctlblk_t *rblk;
661 int rblksz;
662
663 rblksz = rctlblk_size();
664 if ((rblk = (rctlblk_t *)SAFE_ALLOCA(rblksz)) == NULL)
665 return (-ENOMEM);
666
667 bzero(&s, sizeof (s));
668 if ((s.shmmni = get_rctlval(rblk, "project.max-shm-ids")) < 0)
669 return (s.shmmni);
670 if ((s.shmmax = get_rctlval(rblk, "project.max-shm-memory")) < 0)
671 return (s.shmmax);
672
673 /*
674 * We don't have corresponding rctls for these fields. The values
675 * are taken from the formulas used to derive the defaults listed
676 * in the Linux header file. We're lying, but trying to be
677 * coherent about it.
678 */
679 s.shmmin = 1;
680 s.shmseg = INT_MAX;
681 s.shmall = s.shmmax / getpagesize();
682
683 if (uucopy(&s, buf, sizeof (s)))
684 return (-errno);
685
686 return (0);
687 }
688
689 static int
690 lx_shmctl_ipcstat(int shmid, void *buf)
691 {
692 struct lx_shmid_ds shmds;
693 struct shmid_ds sol_shmds;
694
695 if (shmctl(shmid, IPC_STAT, &sol_shmds) != 0)
696 return (-errno);
697
698 bzero(&shmds, sizeof (shmds));
699 shmds.shm_perm.key = sol_shmds.shm_perm.key;
700 shmds.shm_perm.seq = sol_shmds.shm_perm.seq;
701 shmds.shm_perm.uid = sol_shmds.shm_perm.uid;
702 shmds.shm_perm.gid = sol_shmds.shm_perm.gid;
703 shmds.shm_perm.cuid = sol_shmds.shm_perm.cuid;
704 shmds.shm_perm.cgid = sol_shmds.shm_perm.cgid;
705 shmds.shm_perm.mode = sol_shmds.shm_perm.mode & S_IAMB;
706 if (sol_shmds.shm_lkcnt > 0)
707 shmds.shm_perm.mode |= LX_SHM_LOCKED;
708 shmds.shm_segsz = sol_shmds.shm_segsz;
709 shmds.shm_atime = sol_shmds.shm_atime;
710 shmds.shm_dtime = sol_shmds.shm_dtime;
711 shmds.shm_ctime = sol_shmds.shm_ctime;
712 shmds.shm_cpid = sol_shmds.shm_cpid;
713 shmds.shm_lpid = sol_shmds.shm_lpid;
714 shmds.shm_nattch = (ushort_t)sol_shmds.shm_nattch;
715
716 if (uucopy(&shmds, buf, sizeof (shmds)))
717 return (-errno);
718
719 return (0);
720 }
721
722 static int
723 lx_shmctl_ipcset(int shmid, void *buf)
724 {
725 struct lx_shmid_ds shmds;
726 struct shmid_ds sol_shmds;
727 int r;
728
729 if (uucopy(buf, &shmds, sizeof (shmds)))
730 return (-errno);
731
732 bzero(&sol_shmds, sizeof (sol_shmds));
733 sol_shmds.shm_perm.uid = shmds.shm_perm.uid;
734 sol_shmds.shm_perm.gid = shmds.shm_perm.gid;
735 sol_shmds.shm_perm.mode = shmds.shm_perm.mode & S_IAMB;
736
737 r = shmctl(shmid, IPC_SET, &sol_shmds);
738 return (r < 0 ? -errno : r);
739 }
740
741 /*
742 * Build and return a shm_info structure. We only return the bare
743 * essentials required by ipcs. The rest of the info is not readily
744 * available.
745 */
746 static int
747 lx_shmctl_shminfo(void *buf)
748 {
749 struct lx_shm_info shminfo;
750 uint_t nids;
751 int idbuf;
752
753 bzero(&shminfo, sizeof (shminfo));
754
755 if (shmids(&idbuf, 0, &nids) < 0)
756 return (-errno);
757
758 shminfo.used_ids = nids;
759 if (uucopy(&shminfo, buf, sizeof (shminfo)) != 0)
760 return (-errno);
761
762 return (nids);
763 }
764
765 static int
766 lx_shmctl_shmstat(int slot, void *buf)
767 {
768 int r, shmid;
769
770 lx_debug("shmctl_shmstat(%d, 0x%p)\n", slot, buf);
771 shmid = slot_to_id(SLOT_SHM, slot);
772 if (shmid < 0)
773 return (shmid);
774
775 r = lx_shmctl_ipcstat(shmid, buf);
776 return (r < 0 ? r : shmid);
777 }
778
779 static int
780 lx_shmctl(int shmid, int cmd, void *buf)
781 {
782 int r;
783 int use_errno = 0;
784
785 lx_debug("\tlx_shmctl(%d, %d, 0x%p)\n", shmid, cmd, buf);
786 switch (cmd & ~LX_IPC_64) {
787 case LX_IPC_RMID:
788 use_errno = 1;
789 r = shmctl(shmid, IPC_RMID, NULL);
790 break;
791
792 case LX_IPC_SET:
793 r = lx_shmctl_ipcset(shmid, buf);
794 break;
795
796 case LX_IPC_STAT:
797 r = lx_shmctl_ipcstat(shmid, buf);
798 break;
799
800 case LX_IPC_INFO:
801 r = lx_shmctl_ipcinfo(buf);
802 break;
803
804 case LX_SHM_LOCK:
805 use_errno = 1;
806 r = shmctl(shmid, SHM_LOCK, NULL);
807 break;
808
809 case LX_SHM_UNLOCK:
810 use_errno = 1;
811 r = shmctl(shmid, SHM_UNLOCK, NULL);
812 break;
813
814 case LX_SHM_INFO:
815 r = lx_shmctl_shminfo(buf);
816 break;
817
818 case LX_SHM_STAT:
819 r = lx_shmctl_shmstat(shmid, buf);
820 break;
821 default:
822 r = -EINVAL;
823 break;
824 }
825
826 if (use_errno == 1 && r < 0)
827 return (-errno);
828
829 return (r);
830 }
831
832 /*
833 * Under Linux, glibc funnels all of the sysv IPC operations into this
834 * single ipc(2) system call. We need to blow that up and filter the
835 * remnants into the proper Solaris system calls.
836 */
837 int
838 lx_ipc(uintptr_t cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
839 uintptr_t arg4)
840 {
841 int r;
842 void *bufptr = (void *)arg4;
843
844 lx_debug("lx_ipc(%d, %d, %d, %d, 0x%p, %d)\n",
845 cmd, arg1, arg2, arg3, bufptr, arg4);
846
847 switch (cmd) {
848 case LX_MSGGET:
849 r = lx_msgget((key_t)arg1, (int)arg2);
850 break;
851 case LX_MSGSND:
852 r = lx_msgsnd((int)arg1, bufptr, (size_t)arg2, (int)arg3);
853 break;
854 case LX_MSGRCV:
855 r = lx_msgrcv((int)arg1, bufptr, (size_t)arg2, (int)arg3);
856 break;
857 case LX_MSGCTL:
858 r = lx_msgctl((int)arg1, (int)arg2, bufptr);
859 break;
860 case LX_SEMCTL:
861 r = lx_semctl((int)arg1, (size_t)arg2, (int)arg3, bufptr);
862 break;
863 case LX_SEMOP:
864 /*
865 * 'struct sembuf' is the same on Linux and Solaris, so we
866 * pass bufptr straight through.
867 */
868 r = lx_semop((int)arg1, bufptr, (size_t)arg2);
869 break;
870 case LX_SEMGET:
871 r = lx_semget((int)arg1, (size_t)arg2, (int)arg3);
872 break;
873 case LX_SHMAT:
874 r = lx_shmat((int)arg1, bufptr, (size_t)arg2, (void *)arg3);
875 break;
876 case LX_SHMDT:
877 r = shmdt(bufptr);
878 if (r < 0)
879 r = -errno;
880 break;
881 case LX_SHMGET:
882 r = lx_shmget((int)arg1, (size_t)arg2, (int)arg3);
883 break;
884 case LX_SHMCTL:
885 r = lx_shmctl((int)arg1, (int)arg2, bufptr);
886 break;
887
888 default:
889 r = -EINVAL;
890 }
891
892 return (r);
893 }