1/* 2 * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com> 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 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29 30#include <assert.h> 31#include <err.h> 32#include <fcntl.h> 33#include <grp.h> 34#include <nlist.h> 35#include <limits.h> 36#include <paths.h> 37#include <pwd.h> 38#include <stddef.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43#include <sysexits.h> 44 45#include "sys/types.h" 46#include <sys/ucred.h> 47#include <sys/time.h> 48#include <sys/proc.h> 49#include <sys/param.h> 50#include <sys/sysctl.h> 51#include <errno.h> 52#include "sys/ipcs.h" 53#define KERNEL 1 /* To get new ipc_perm and __(sem|shm|msg)ds_new */ 54#include "sys/ipc.h" 55#include "sys/sem_internal.h" 56#include "sys/shm_internal.h" 57#include "sys/msg.h" 58 59 60/* The following is a kludge, until the problem of multiple inclusions 61 of ipc.h is taken care of. */ 62#ifndef IXSEQ_TO_IPCID 63#define IXSEQ_TO_IPCID(ix,perm) (((perm._seq) << 16L) | (ix & 0xffff)) 64#endif 65 66static char * 67fmt_perm(u_short mode, char write_char) 68{ 69 static char buffer[100]; 70 71 buffer[0] = '-'; 72 buffer[1] = '-'; 73 buffer[2] = ((mode & 0400) ? 'r' : '-'); 74 buffer[3] = ((mode & 0200) ? write_char : '-'); 75 buffer[4] = '-'; 76 buffer[5] = ((mode & 0040) ? 'r' : '-'); 77 buffer[6] = ((mode & 0020) ? write_char : '-'); 78 buffer[7] = '-'; 79 buffer[8] = ((mode & 0004) ? 'r' : '-'); 80 buffer[9] = ((mode & 0002) ? write_char : '-'); 81 buffer[10] = '-'; 82 buffer[11] = '\0'; 83 return (&buffer[0]); 84} 85 86static void 87cvt_time(time_t t, char *buf) 88{ 89 struct tm *tm; 90 91 if (t == 0) { 92 strcpy(buf, "no-entry"); 93 } else { 94 tm = localtime(&t); 95 if (tm != NULL) { 96 sprintf(buf, "%2d:%02d:%02d", 97 tm->tm_hour, tm->tm_min, tm->tm_sec); 98 } 99 } 100} 101#define SHMINFO 1 102#define SHMTOTAL 2 103#define MSGINFO 4 104#define MSGTOTAL 8 105#define SEMINFO 16 106#define SEMTOTAL 32 107 108#define BIGGEST 1 109#define CREATOR 2 110#define OUTSTANDING 4 111#define PID 8 112#define TIME 16 113 114static void 115usage(void) 116{ 117 errx(EX_USAGE, "%s","usage: ipcs [-abcmopqstMQST]\n"); 118} 119 120static int 121safe_sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) 122{ 123 int rv, sv_errno=0; 124 125 if (seteuid(0)) /* iterator needs root write access to sysctl */ 126 err(1, "seteuid(0) failed"); 127 128 rv = sysctlbyname(name, oldp, oldlenp, newp, newlen); 129 if (rv < 0) 130 sv_errno = errno; 131 132 if (seteuid(getuid())) 133 err(1, "seteuid(%d) failed", getuid()); 134 135 if (rv < 0) 136 errno = sv_errno; 137 return rv; 138} 139 140int 141main(argc, argv) 142 int argc; 143 char *argv[]; 144{ 145 int display = 0; 146 int option = 0; 147 int exit_val = 0; 148 time_t now; 149 char datestring[100]; 150 int i; 151 152 if (seteuid(getuid())) /* run as user */ 153 err(1, "seteuid(%d) failed", getuid()); 154 155 while ((i = getopt(argc, argv, "MmQqSsabcoptT")) != -1) 156 switch (i) { 157 case 'M': 158 display = SHMTOTAL; 159 break; 160 case 'm': 161 display |= SHMINFO; 162 break; 163 case 'Q': 164 display = MSGTOTAL; 165 break; 166 case 'q': 167 display |= MSGINFO; 168 break; 169 case 'S': 170 display = SEMTOTAL; 171 break; 172 case 's': 173 display |= SEMINFO; 174 break; 175 case 'T': 176 display = SHMTOTAL | MSGTOTAL | SEMTOTAL; 177 break; 178 case 'a': 179 option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME; 180 break; 181 case 'b': 182 option |= BIGGEST; 183 break; 184 case 'c': 185 option |= CREATOR; 186 break; 187 case 'o': 188 option |= OUTSTANDING; 189 break; 190 case 'p': 191 option |= PID; 192 break; 193 case 't': 194 option |= TIME; 195 break; 196 default: 197 usage(); 198 } 199 if (display == 0) 200 display = SHMINFO | MSGINFO | SEMINFO; 201 now = time(0); 202 struct tm* tm = localtime(&now); 203 if (tm == NULL) { 204 now = 0; 205 tm = localtime(&now); 206 } 207 if (0 == strftime(datestring, sizeof(datestring), "%a %b %e %H:%M:%S %Z %Y", tm)) 208 errx(1, "strftime failed\n"); 209 printf("IPC status from <running system> as of %s\n", datestring); 210 if ((display & (MSGINFO | MSGTOTAL))) { 211 if (display & MSGTOTAL) { 212 struct IPCS_command ic; 213 struct msginfo msginfo; 214 size_t ic_size = sizeof(ic); 215 216 ic.ipcs_magic = IPCS_MAGIC; 217 ic.ipcs_op = IPCS_MSG_CONF; 218 ic.ipcs_cursor = 0; /* 0 for fw. compat. */ 219 ic.ipcs_data = &msginfo; 220 ic.ipcs_datalen = sizeof(msginfo); 221 222 if (safe_sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size)) { 223 if (errno != EPERM) { 224 char buffer[1024]; 225 snprintf(buffer, 1024, "sysctlbyname(IPCS_MSG_SYSCTL, op=CONF, &ic, &%ld) datalen=%d", 226 sizeof(ic), ic.ipcs_datalen); 227 perror(buffer); 228 } else 229 perror("sysctlbyname IPCS_MSG_SYSCTL"); 230 } 231 232 printf("msginfo:\n"); 233 printf("\tmsgmax: %6d\t(max characters in a message)\n", 234 msginfo.msgmax); 235 printf("\tmsgmni: %6d\t(# of message queues)\n", 236 msginfo.msgmni); 237 printf("\tmsgmnb: %6d\t(max characters in a message queue)\n", 238 msginfo.msgmnb); 239 printf("\tmsgtql: %6d\t(max # of messages in system)\n", 240 msginfo.msgtql); 241 printf("\tmsgssz: %6d\t(size of a message segment)\n", 242 msginfo.msgssz); 243 printf("\tmsgseg: %6d\t(# of message segments in system)\n\n", 244 msginfo.msgseg); 245 } 246 if (display & MSGINFO) { 247 struct IPCS_command ic; 248 struct __msqid_ds_new ds; 249 struct __msqid_ds_new *msqptr = &ds; 250 size_t ic_size = sizeof(ic); 251 252 printf("T ID KEY MODE OWNER GROUP"); 253 if (option & CREATOR) 254 printf(" CREATOR CGROUP"); 255 if (option & OUTSTANDING) 256 printf(" CBYTES QNUM"); 257 if (option & BIGGEST) 258 printf(" QBYTES"); 259 if (option & PID) 260 printf(" LSPID LRPID"); 261 if (option & TIME) 262 printf(" STIME RTIME CTIME"); 263 printf("\nMessage Queues:\n"); 264 265 ic.ipcs_magic = IPCS_MAGIC; 266 ic.ipcs_op = IPCS_MSG_ITER; 267 ic.ipcs_cursor = 0; /* start */ 268 ic.ipcs_datalen = sizeof(*msqptr); 269 ic.ipcs_data = msqptr; 270 271 memset(msqptr, 0, sizeof(*msqptr)); 272 273 while(!(safe_sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size))) { 274 ic.ipcs_data = msqptr; 275 276 if (msqptr->msg_qbytes != 0) { 277 char stime_buf[100], rtime_buf[100], 278 ctime_buf[100]; 279 280 cvt_time(msqptr->msg_stime, stime_buf); 281 cvt_time(msqptr->msg_rtime, rtime_buf); 282 cvt_time(msqptr->msg_ctime, ctime_buf); 283 284 printf("q %6d 0x%08x %s %8s %8s", 285 IXSEQ_TO_IPCID((ic.ipcs_cursor-1), msqptr->msg_perm), 286 (int)msqptr->msg_perm._key, 287 fmt_perm(msqptr->msg_perm.mode, 'w'), 288 user_from_uid(msqptr->msg_perm.uid, 0), 289 group_from_gid(msqptr->msg_perm.gid, 0)); 290 291 if (option & CREATOR) 292 printf(" %8s %8s", 293 user_from_uid(msqptr->msg_perm.cuid, 0), 294 group_from_gid(msqptr->msg_perm.cgid, 0)); 295 296 if (option & OUTSTANDING) 297 printf(" %6lu %6lu", 298 msqptr->msg_cbytes, 299 msqptr->msg_qnum); 300 301 if (option & BIGGEST) 302 printf(" %6lu", 303 msqptr->msg_qbytes); 304 305 if (option & PID) 306 printf(" %6d %6d", 307 msqptr->msg_lspid, 308 msqptr->msg_lrpid); 309 310 if (option & TIME) 311 printf(" %s %s %s", 312 stime_buf, 313 rtime_buf, 314 ctime_buf); 315 316 printf("\n"); 317 } 318 memset(msqptr, 0, sizeof(*msqptr)); 319 errno = 0; 320 } 321 322 if (errno != ENOENT && errno != ERANGE) { 323 if (errno != EPERM) { 324 errx(1, "sysctlbyname(IPCS_MSG_SYSCTL, op=ITER, &ic, &%ld) datalen=%d failed:%s\n", 325 sizeof(ic), ic.ipcs_datalen, strerror(errno)); 326 } else 327 errx(1, "sysctlbyname IPCS_MSG_SYSCTL: %s", strerror(errno)); 328 } 329 printf("\n"); 330 } 331 } else 332 if (display & (MSGINFO | MSGTOTAL)) { 333 errx(1, "%s", "SVID messages facility not configured in the system\n"); 334 } 335 336 if ((display & (SHMINFO | SHMTOTAL))) { 337 if (display & SHMTOTAL) { 338 struct IPCS_command ic; 339 struct shminfo shminfo; 340 size_t ic_size = sizeof(ic); 341 342 ic.ipcs_magic = IPCS_MAGIC; 343 ic.ipcs_op = IPCS_SHM_CONF; 344 ic.ipcs_cursor = 0; /* 0 for fw. compat. */ 345 ic.ipcs_data = &shminfo; 346 ic.ipcs_datalen = sizeof(shminfo); 347 348 if (safe_sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size)) { 349 if (errno != EPERM) { 350 errx(1, "sysctlbyname(IPCS_SHM_SYSCTL, op=CONF, &ic, &%ld) datalen=%d failed: %s\n", 351 sizeof(ic), ic.ipcs_datalen, strerror(errno)); 352 } else 353 errx(1, "sysctlbyname: %s", strerror(errno)); 354 } 355 printf("shminfo:\n"); 356 printf("\tshmmax: %7lld\t(max shared memory segment size)\n", 357 shminfo.shmmax); 358 printf("\tshmmin: %7lld\t(min shared memory segment size)\n", 359 shminfo.shmmin); 360 printf("\tshmmni: %7lld\t(max number of shared memory identifiers)\n", 361 shminfo.shmmni); 362 printf("\tshmseg: %7lld\t(max shared memory segments per process)\n", 363 shminfo.shmseg); 364 printf("\tshmall: %7lld\t(max amount of shared memory in pages)\n\n", 365 shminfo.shmall); 366 } 367 if (display & SHMINFO) { 368 struct IPCS_command ic; 369 struct __shmid_ds_new ds; 370 struct __shmid_ds_new *shmptr = &ds; 371 size_t ic_size = sizeof(ic); 372 373 printf("T ID KEY MODE OWNER GROUP"); 374 if (option & CREATOR) 375 printf(" CREATOR CGROUP"); 376 if (option & OUTSTANDING) 377 printf(" NATTCH"); 378 if (option & BIGGEST) 379 printf(" SEGSZ"); 380 if (option & PID) 381 printf(" CPID LPID"); 382 if (option & TIME) 383 printf(" ATIME DTIME CTIME"); 384 printf("\nShared Memory:\n"); 385 { /* XXX */ 386 387 ic.ipcs_magic = IPCS_MAGIC; 388 ic.ipcs_op = IPCS_SHM_ITER; 389 ic.ipcs_cursor = 0; /* start */ 390 ic.ipcs_datalen = sizeof(*shmptr); 391 ic.ipcs_data = shmptr; 392 memset(shmptr, 0, sizeof(*shmptr)); 393 394 while(!(safe_sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size))) { 395 ic.ipcs_data = shmptr; /* xnu workaround */ 396 397 if (shmptr->shm_perm.mode & 0x0800) { 398 char atime_buf[100], dtime_buf[100], 399 ctime_buf[100]; 400 401 cvt_time(shmptr->shm_atime, atime_buf); 402 cvt_time(shmptr->shm_dtime, dtime_buf); 403 cvt_time(shmptr->shm_ctime, ctime_buf); 404 405 printf("m %6d 0x%08x %s %8s %8s", 406 IXSEQ_TO_IPCID((ic.ipcs_cursor-1), shmptr->shm_perm), 407 (int)shmptr->shm_perm._key, 408 fmt_perm(shmptr->shm_perm.mode, 'w'), 409 user_from_uid(shmptr->shm_perm.uid, 0), 410 group_from_gid(shmptr->shm_perm.gid, 0)); 411 412 if (option & CREATOR) 413 printf(" %8s %8s", 414 user_from_uid(shmptr->shm_perm.cuid, 0), 415 group_from_gid(shmptr->shm_perm.cgid, 0)); 416 417 if (option & OUTSTANDING) 418 printf(" %6d", 419 shmptr->shm_nattch); 420 421 if (option & BIGGEST) 422 printf(" %6ld", 423 shmptr->shm_segsz); 424 425 if (option & PID) 426 printf(" %6d %6d", 427 shmptr->shm_cpid, 428 shmptr->shm_lpid); 429 430 if (option & TIME) 431 printf(" %s %s %s", 432 atime_buf, 433 dtime_buf, 434 ctime_buf); 435 436 printf("\n"); 437 } 438 memset(shmptr, 0, sizeof(*shmptr)); 439 errno = 0; 440 } 441 442 if (errno != ENOENT && errno != ERANGE) { 443 if (errno != EPERM) { 444 errx(1, "sysctlbyname(IPCS_SHM_SYSCTL, op=ITER, &ic, &%ld) datalen=%d failed:%s\n", 445 sizeof(ic), ic.ipcs_datalen, strerror(errno)); 446 } else 447 errx(1, "sysctlbyname: %s", strerror(errno)); 448 } 449 } /* XXX */ 450 printf("\n"); 451 } 452 } 453else 454 if (display & (SHMINFO | SHMTOTAL)) { 455 errx(1, "%s", "SVID shared memory facility not configured in the system\n"); 456 } 457 458 if ((display & (SEMINFO | SEMTOTAL))) { 459 if (display & SEMTOTAL) { 460 struct IPCS_command ic; 461 struct seminfo seminfo; 462 size_t ic_size = sizeof(ic); 463 464 ic.ipcs_magic = IPCS_MAGIC; 465 ic.ipcs_op = IPCS_SEM_CONF; 466 ic.ipcs_cursor = 0; /* 0 for fw. compat. */ 467 ic.ipcs_data = &seminfo; 468 ic.ipcs_datalen = sizeof(seminfo); 469 470 if (safe_sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size)) { 471 if (errno != EPERM) { 472 char buffer[1024]; 473 snprintf(buffer, 1024, "sysctlbyname(IPCS_SEM_SYSCTL, op=CONF, &ic, &%ld) datalen=%d", 474 sizeof(ic), ic.ipcs_datalen); 475 perror(buffer); 476 } else 477 perror("sysctlbyname IPCS_SEM_SYSCTL/SEM_CONF"); 478 } 479 480 printf("seminfo:\n"); 481 printf("\tsemmap: %6d\t(# of entries in semaphore map)\n", 482 seminfo.semmap); 483 printf("\tsemmni: %6d\t(# of semaphore identifiers)\n", 484 seminfo.semmni); 485 printf("\tsemmns: %6d\t(# of semaphores in system)\n", 486 seminfo.semmns); 487 printf("\tsemmnu: %6d\t(# of undo structures in system)\n", 488 seminfo.semmnu); 489 printf("\tsemmsl: %6d\t(max # of semaphores per id)\n", 490 seminfo.semmsl); 491 printf("\tsemopm: %6d\t(max # of operations per semop call)\n", 492 seminfo.semopm); 493 printf("\tsemume: %6d\t(max # of undo entries per process)\n", 494 seminfo.semume); 495 printf("\tsemusz: %6d\t(size in bytes of undo structure)\n", 496 seminfo.semusz); 497 printf("\tsemvmx: %6d\t(semaphore maximum value)\n", 498 seminfo.semvmx); 499 printf("\tsemaem: %6d\t(adjust on exit max value)\n\n", 500 seminfo.semaem); 501 } 502 if (display & SEMINFO) { 503 struct IPCS_command ic; 504 struct __semid_ds_new ds; 505 struct __semid_ds_new *semaptr = &ds; 506 size_t ic_size = sizeof(ic); 507 508 printf("T ID KEY MODE OWNER GROUP"); 509 if (option & CREATOR) 510 printf(" CREATOR CGROUP"); 511 if (option & BIGGEST) 512 printf(" NSEMS"); 513 if (option & TIME) 514 printf(" OTIME CTIME"); 515 printf("\nSemaphores:\n"); 516 517 ic.ipcs_magic = IPCS_MAGIC; 518 ic.ipcs_op = IPCS_SEM_ITER; 519 ic.ipcs_cursor = 0; /* start */ 520 ic.ipcs_datalen = sizeof(*semaptr); 521 ic.ipcs_data = semaptr; 522 523 memset(semaptr, 0, sizeof(*semaptr)); 524 525 while(!(safe_sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size))) { 526 ic.ipcs_data = semaptr; /* xnu workaround */ 527 528 if ((semaptr->sem_perm.mode & SEM_ALLOC) != 0) { 529 char ctime_buf[100], otime_buf[100]; 530 531 cvt_time(semaptr->sem_otime, otime_buf); 532 cvt_time(semaptr->sem_ctime, ctime_buf); 533 534 printf("s %6d 0x%08x %s %8s %8s", 535 IXSEQ_TO_IPCID((ic.ipcs_cursor-1), semaptr->sem_perm), 536 (int)semaptr->sem_perm._key, 537 fmt_perm(semaptr->sem_perm.mode, 'a'), 538 user_from_uid(semaptr->sem_perm.uid, 0), 539 group_from_gid(semaptr->sem_perm.gid, 0)); 540 541 if (option & CREATOR) 542 printf(" %8s %8s", 543 user_from_uid(semaptr->sem_perm.cuid, 0), 544 group_from_gid(semaptr->sem_perm.cgid, 0)); 545 546 if (option & BIGGEST) 547 printf(" %6d", 548 semaptr->sem_nsems); 549 550 if (option & TIME) 551 printf(" %s %s", 552 otime_buf, 553 ctime_buf); 554 555 printf("\n"); 556 } 557 memset(semaptr, 0, sizeof(*semaptr)); 558 errno = 0; 559 } 560 561 if (errno != ENOENT && errno != ERANGE) { 562 if (errno != EPERM) { 563 errx(1, "sysctlbyname(IPCS_SEM_SYSCTL/ITER, op=ITER, &ic, &%ld) datalen=%d failed: %s\n", 564 sizeof(ic), ic.ipcs_datalen, strerror(errno)); 565 } else 566 errx(1, "sysctlbyname: IPCS_SEM_SYSCTL %s", strerror(errno)); 567 } 568 printf("\n"); 569 } 570 } else 571 if (display & (SEMINFO | SEMTOTAL)) { 572 errx(1, "%s", "SVID semaphores facility not configured in the system\n"); 573 } 574 575 exit(exit_val); 576} 577