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 }