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 #ifndef lint 29 static const char rcsid[] = 30 "$FreeBSD$"; 31 #endif /* not lint */ 32 33 #include <assert.h> 34 #include <err.h> 35 #include <fcntl.h> 36 #include <kvm.h> 37 #include <nlist.h> 38 #include <limits.h> 39 #include <paths.h> 40 #include <stddef.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/time.h> 49 #include <sys/proc.h> 50 #include <sys/sysctl.h> 51 #define _KERNEL 52 #include <sys/ipc.h> 53 #include <sys/sem.h> 54 #include <sys/shm.h> 55 #include <sys/msg.h> 56 57 /* SysCtlGatherStruct structure. */ 58 struct scgs_vector { 59 const char *sysctl; 60 off_t offset; 61 size_t size; 62 }; 63 64 int use_sysctl = 1; 65 struct semid_ds *sema; 66 struct seminfo seminfo; 67 struct msginfo msginfo; 68 struct msqid_ds *msqids; 69 struct shminfo shminfo; 70 struct shmid_ds *shmsegs; 71 72 void sysctlgatherstruct __P((void *addr, size_t size, 73 struct scgs_vector *vec)); 74 void kget __P((int idx, void *addr, size_t size)); 75 void usage __P((void)); 76 77 static struct nlist symbols[] = { 78 {"sema"}, 79 #define X_SEMA 0 80 {"seminfo"}, 81 #define X_SEMINFO 1 82 {"msginfo"}, 83 #define X_MSGINFO 2 84 {"msqids"}, 85 #define X_MSQIDS 3 86 {"shminfo"}, 87 #define X_SHMINFO 4 88 {"shmsegs"}, 89 #define X_SHMSEGS 5 90 {NULL} 91 }; 92 93 #define SHMINFO_XVEC \ 94 X(shmmax, sizeof(int)) \ 95 X(shmmin, sizeof(int)) \ 96 X(shmmni, sizeof(int)) \ 97 X(shmseg, sizeof(int)) \ 98 X(shmall, sizeof(int)) 99 100 #define SEMINFO_XVEC \ 101 X(semmap, sizeof(int)) \ 102 X(semmni, sizeof(int)) \ 103 X(semmns, sizeof(int)) \ 104 X(semmnu, sizeof(int)) \ 105 X(semmsl, sizeof(int)) \ 106 X(semopm, sizeof(int)) \ 107 X(semume, sizeof(int)) \ 108 X(semusz, sizeof(int)) \ 109 X(semvmx, sizeof(int)) \ 110 X(semaem, sizeof(int)) 111 112 #define MSGINFO_XVEC \ 113 X(msgmax, sizeof(int)) \ 114 X(msgmni, sizeof(int)) \ 115 X(msgmnb, sizeof(int)) \ 116 X(msgtql, sizeof(int)) \ 117 X(msgssz, sizeof(int)) \ 118 X(msgseg, sizeof(int)) 119 120 #define X(a, b) { "kern.ipc." #a, offsetof(TYPEC, a), (b) }, 121 #define TYPEC struct shminfo 122 struct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { NULL } }; 123 #undef TYPEC 124 #define TYPEC struct seminfo 125 struct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { NULL } }; 126 #undef TYPEC 127 #define TYPEC struct msginfo 128 struct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { NULL } }; 129 #undef TYPEC 130 #undef X 131 132 static kvm_t *kd; 133 134 char * 135 fmt_perm(mode) 136 u_short mode; 137 { 138 static char buffer[100]; 139 140 buffer[0] = '-'; 141 buffer[1] = '-'; 142 buffer[2] = ((mode & 0400) ? 'r' : '-'); 143 buffer[3] = ((mode & 0200) ? 'w' : '-'); 144 buffer[4] = ((mode & 0100) ? 'a' : '-'); 145 buffer[5] = ((mode & 0040) ? 'r' : '-'); 146 buffer[6] = ((mode & 0020) ? 'w' : '-'); 147 buffer[7] = ((mode & 0010) ? 'a' : '-'); 148 buffer[8] = ((mode & 0004) ? 'r' : '-'); 149 buffer[9] = ((mode & 0002) ? 'w' : '-'); 150 buffer[10] = ((mode & 0001) ? 'a' : '-'); 151 buffer[11] = '\0'; 152 return (&buffer[0]); 153 } 154 155 void 156 cvt_time(t, buf) 157 time_t t; 158 char *buf; 159 { 160 struct tm *tm; 161 162 if (t == 0) { 163 strcpy(buf, "no-entry"); 164 } else { 165 tm = localtime(&t); 166 sprintf(buf, "%2d:%02d:%02d", 167 tm->tm_hour, tm->tm_min, tm->tm_sec); 168 } 169 } 170 #define SHMINFO 1 171 #define SHMTOTAL 2 172 #define MSGINFO 4 173 #define MSGTOTAL 8 174 #define SEMINFO 16 175 #define SEMTOTAL 32 176 177 #define BIGGEST 1 178 #define CREATOR 2 179 #define OUTSTANDING 4 180 #define PID 8 181 #define TIME 16 182 183 int 184 main(argc, argv) 185 int argc; 186 char *argv[]; 187 { 188 int display = SHMINFO | MSGINFO | SEMINFO; 189 int option = 0; 190 char *core = NULL, *namelist = NULL; 191 char kvmoferr[_POSIX2_LINE_MAX]; /* Error buf for kvm_openfiles. */ 192 int i; 193 194 while ((i = getopt(argc, argv, "MmQqSsabC:cN:optTy")) != -1) 195 switch (i) { 196 case 'M': 197 display = SHMTOTAL; 198 break; 199 case 'm': 200 display = SHMINFO; 201 break; 202 case 'Q': 203 display = MSGTOTAL; 204 break; 205 case 'q': 206 display = MSGINFO; 207 break; 208 case 'S': 209 display = SEMTOTAL; 210 break; 211 case 's': 212 display = SEMINFO; 213 break; 214 case 'T': 215 display = SHMTOTAL | MSGTOTAL | SEMTOTAL; 216 break; 217 case 'a': 218 option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME; 219 break; 220 case 'b': 221 option |= BIGGEST; 222 break; 223 case 'C': 224 core = optarg; 225 break; 226 case 'c': 227 option |= CREATOR; 228 break; 229 case 'N': 230 namelist = optarg; 231 break; 232 case 'o': 233 option |= OUTSTANDING; 234 break; 235 case 'p': 236 option |= PID; 237 break; 238 case 't': 239 option |= TIME; 240 break; 241 case 'y': 242 use_sysctl = 0; 243 break; 244 default: 245 usage(); 246 } 247 248 /* 249 * If paths to the exec file or core file were specified, we 250 * aren't operating on the running kernel, so we can't use 251 * sysctl. 252 */ 253 if (namelist != NULL || core != NULL) 254 use_sysctl = 0; 255 256 if (!use_sysctl) { 257 kd = kvm_openfiles(namelist, core, NULL, O_RDONLY, kvmoferr); 258 if (kd == NULL) 259 errx(1, "kvm_openfiles: %s", kvmoferr); 260 switch (kvm_nlist(kd, symbols)) { 261 case 0: 262 break; 263 case -1: 264 errx(1, "unable to read kernel symbol table"); 265 default: 266 #ifdef notdef /* they'll be told more civilly later */ 267 warnx("nlist failed"); 268 for (i = 0; symbols[i].n_name != NULL; i++) 269 if (symbols[i].n_value == 0) 270 warnx("symbol %s not found", 271 symbols[i].n_name); 272 break; 273 #endif 274 } 275 } 276 277 kget(X_MSGINFO, &msginfo, sizeof(msginfo)); 278 if ((display & (MSGINFO | MSGTOTAL))) { 279 if (display & MSGTOTAL) { 280 printf("msginfo:\n"); 281 printf("\tmsgmax: %6d\t(max characters in a message)\n", 282 msginfo.msgmax); 283 printf("\tmsgmni: %6d\t(# of message queues)\n", 284 msginfo.msgmni); 285 printf("\tmsgmnb: %6d\t(max characters in a message queue)\n", 286 msginfo.msgmnb); 287 printf("\tmsgtql: %6d\t(max # of messages in system)\n", 288 msginfo.msgtql); 289 printf("\tmsgssz: %6d\t(size of a message segment)\n", 290 msginfo.msgssz); 291 printf("\tmsgseg: %6d\t(# of message segments in system)\n\n", 292 msginfo.msgseg); 293 } 294 if (display & MSGINFO) { 295 struct msqid_ds *xmsqids; 296 size_t xmsqids_len; 297 298 299 xmsqids_len = sizeof(struct msqid_ds) * msginfo.msgmni; 300 xmsqids = malloc(xmsqids_len); 301 kget(X_MSQIDS, xmsqids, xmsqids_len); 302 303 printf("Message Queues:\n"); 304 printf("T ID KEY MODE OWNER GROUP"); 305 if (option & CREATOR) 306 printf(" CREATOR CGROUP"); 307 if (option & OUTSTANDING) 308 printf(" CBYTES QNUM"); 309 if (option & BIGGEST) 310 printf(" QBYTES"); 311 if (option & PID) 312 printf(" LSPID LRPID"); 313 if (option & TIME) 314 printf(" STIME RTIME CTIME"); 315 printf("\n"); 316 for (i = 0; i < msginfo.msgmni; i += 1) { 317 if (xmsqids[i].msg_qbytes != 0) { 318 char stime_buf[100], rtime_buf[100], 319 ctime_buf[100]; 320 struct msqid_ds *msqptr = &xmsqids[i]; 321 322 cvt_time(msqptr->msg_stime, stime_buf); 323 cvt_time(msqptr->msg_rtime, rtime_buf); 324 cvt_time(msqptr->msg_ctime, ctime_buf); 325 326 printf("q %6d %10d %s %8s %8s", 327 IXSEQ_TO_IPCID(i, msqptr->msg_perm), 328 msqptr->msg_perm.key, 329 fmt_perm(msqptr->msg_perm.mode), 330 user_from_uid(msqptr->msg_perm.uid, 0), 331 group_from_gid(msqptr->msg_perm.gid, 0)); 332 333 if (option & CREATOR) 334 printf(" %8s %8s", 335 user_from_uid(msqptr->msg_perm.cuid, 0), 336 group_from_gid(msqptr->msg_perm.cgid, 0)); 337 338 if (option & OUTSTANDING) 339 printf(" %6d %6d", 340 msqptr->msg_cbytes, 341 msqptr->msg_qnum); 342 343 if (option & BIGGEST) 344 printf(" %6d", 345 msqptr->msg_qbytes); 346 347 if (option & PID) 348 printf(" %6d %6d", 349 msqptr->msg_lspid, 350 msqptr->msg_lrpid); 351 352 if (option & TIME) 353 printf("%s %s %s", 354 stime_buf, 355 rtime_buf, 356 ctime_buf); 357 358 printf("\n"); 359 } 360 } 361 printf("\n"); 362 } 363 } else 364 if (display & (MSGINFO | MSGTOTAL)) { 365 fprintf(stderr, 366 "SVID messages facility not configured in the system\n"); 367 } 368 369 kget(X_SHMINFO, &shminfo, sizeof(shminfo)); 370 if ((display & (SHMINFO | SHMTOTAL))) { 371 if (display & SHMTOTAL) { 372 printf("shminfo:\n"); 373 printf("\tshmmax: %7d\t(max shared memory segment size)\n", 374 shminfo.shmmax); 375 printf("\tshmmin: %7d\t(min shared memory segment size)\n", 376 shminfo.shmmin); 377 printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n", 378 shminfo.shmmni); 379 printf("\tshmseg: %7d\t(max shared memory segments per process)\n", 380 shminfo.shmseg); 381 printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n", 382 shminfo.shmall); 383 } 384 if (display & SHMINFO) { 385 struct shmid_ds *xshmids; 386 size_t xshmids_len; 387 388 xshmids_len = sizeof(struct shmid_ds) * shminfo.shmmni; 389 xshmids = malloc(xshmids_len); 390 kget(X_SHMSEGS, xshmids, xshmids_len); 391 392 printf("Shared Memory:\n"); 393 printf("T ID KEY MODE OWNER GROUP"); 394 if (option & CREATOR) 395 printf(" CREATOR CGROUP"); 396 if (option & OUTSTANDING) 397 printf(" NATTCH"); 398 if (option & BIGGEST) 399 printf(" SEGSZ"); 400 if (option & PID) 401 printf(" CPID LPID"); 402 if (option & TIME) 403 printf(" ATIME DTIME CTIME"); 404 printf("\n"); 405 for (i = 0; i < shminfo.shmmni; i += 1) { 406 if (xshmids[i].shm_perm.mode & 0x0800) { 407 char atime_buf[100], dtime_buf[100], 408 ctime_buf[100]; 409 struct shmid_ds *shmptr = &xshmids[i]; 410 411 cvt_time(shmptr->shm_atime, atime_buf); 412 cvt_time(shmptr->shm_dtime, dtime_buf); 413 cvt_time(shmptr->shm_ctime, ctime_buf); 414 415 printf("m %6d %10d %s %8s %8s", 416 IXSEQ_TO_IPCID(i, shmptr->shm_perm), 417 shmptr->shm_perm.key, 418 fmt_perm(shmptr->shm_perm.mode), 419 user_from_uid(shmptr->shm_perm.uid, 0), 420 group_from_gid(shmptr->shm_perm.gid, 0)); 421 422 if (option & CREATOR) 423 printf(" %8s %8s", 424 user_from_uid(shmptr->shm_perm.cuid, 0), 425 group_from_gid(shmptr->shm_perm.cgid, 0)); 426 427 if (option & OUTSTANDING) 428 printf(" %6d", 429 shmptr->shm_nattch); 430 431 if (option & BIGGEST) 432 printf(" %6d", 433 shmptr->shm_segsz); 434 435 if (option & PID) 436 printf(" %6d %6d", 437 shmptr->shm_cpid, 438 shmptr->shm_lpid); 439 440 if (option & TIME) 441 printf("%s %s %s", 442 atime_buf, 443 dtime_buf, 444 ctime_buf); 445 446 printf("\n"); 447 } 448 } 449 printf("\n"); 450 } 451 } else 452 if (display & (SHMINFO | SHMTOTAL)) { 453 fprintf(stderr, 454 "SVID shared memory facility not configured in the system\n"); 455 } 456 457 kget(X_SEMINFO, &seminfo, sizeof(seminfo)); 458 if ((display & (SEMINFO | SEMTOTAL))) { 459 struct semid_ds *xsema; 460 size_t xsema_len; 461 462 if (display & SEMTOTAL) { 463 printf("seminfo:\n"); 464 printf("\tsemmap: %6d\t(# of entries in semaphore map)\n", 465 seminfo.semmap); 466 printf("\tsemmni: %6d\t(# of semaphore identifiers)\n", 467 seminfo.semmni); 468 printf("\tsemmns: %6d\t(# of semaphores in system)\n", 469 seminfo.semmns); 470 printf("\tsemmnu: %6d\t(# of undo structures in system)\n", 471 seminfo.semmnu); 472 printf("\tsemmsl: %6d\t(max # of semaphores per id)\n", 473 seminfo.semmsl); 474 printf("\tsemopm: %6d\t(max # of operations per semop call)\n", 475 seminfo.semopm); 476 printf("\tsemume: %6d\t(max # of undo entries per process)\n", 477 seminfo.semume); 478 printf("\tsemusz: %6d\t(size in bytes of undo structure)\n", 479 seminfo.semusz); 480 printf("\tsemvmx: %6d\t(semaphore maximum value)\n", 481 seminfo.semvmx); 482 printf("\tsemaem: %6d\t(adjust on exit max value)\n\n", 483 seminfo.semaem); 484 } 485 if (display & SEMINFO) { 486 xsema_len = sizeof(struct semid_ds) * seminfo.semmni; 487 xsema = malloc(xsema_len); 488 kget(X_SEMA, xsema, xsema_len); 489 490 printf("Semaphores:\n"); 491 printf("T ID KEY MODE OWNER GROUP"); 492 if (option & CREATOR) 493 printf(" CREATOR CGROUP"); 494 if (option & BIGGEST) 495 printf(" NSEMS"); 496 if (option & TIME) 497 printf(" OTIME CTIME"); 498 printf("\n"); 499 for (i = 0; i < seminfo.semmni; i += 1) { 500 if ((xsema[i].sem_perm.mode & SEM_ALLOC) != 0) { 501 char ctime_buf[100], otime_buf[100]; 502 struct semid_ds *semaptr = &xsema[i]; 503 504 cvt_time(semaptr->sem_otime, otime_buf); 505 cvt_time(semaptr->sem_ctime, ctime_buf); 506 507 printf("s %6d %10d %s %8s %8s", 508 IXSEQ_TO_IPCID(i, semaptr->sem_perm), 509 semaptr->sem_perm.key, 510 fmt_perm(semaptr->sem_perm.mode), 511 user_from_uid(semaptr->sem_perm.uid, 0), 512 group_from_gid(semaptr->sem_perm.gid, 0)); 513 514 if (option & CREATOR) 515 printf(" %8s %8s", 516 user_from_uid(semaptr->sem_perm.cuid, 0), 517 group_from_gid(semaptr->sem_perm.cgid, 0)); 518 519 if (option & BIGGEST) 520 printf(" %6d", 521 semaptr->sem_nsems); 522 523 if (option & TIME) 524 printf("%s %s", 525 otime_buf, 526 ctime_buf); 527 528 printf("\n"); 529 } 530 } 531 532 printf("\n"); 533 } 534 } else 535 if (display & (SEMINFO | SEMTOTAL)) { 536 fprintf(stderr, "SVID semaphores facility not configured in the system\n"); 537 } 538 if (!use_sysctl) 539 kvm_close(kd); 540 541 exit(0); 542 } 543 544 void 545 sysctlgatherstruct(addr, size, vecarr) 546 void *addr; 547 size_t size; 548 struct scgs_vector *vecarr; 549 { 550 struct scgs_vector *xp; 551 size_t tsiz; 552 int rv; 553 554 for (xp = vecarr; xp->sysctl != NULL; xp++) { 555 assert(xp->offset <= size); 556 tsiz = xp->size; 557 rv = sysctlbyname(xp->sysctl, (char *)addr + xp->offset, 558 &tsiz, NULL, 0); 559 if (rv == -1) 560 errx(1, "sysctlbyname: %s", xp->sysctl); 561 if (tsiz != xp->size) 562 errx(1, "%s size mismatch (expected %d, got %d)", 563 xp->sysctl, xp->size, tsiz); 564 } 565 } 566 567 void 568 kget(idx, addr, size) 569 int idx; 570 void *addr; 571 size_t size; 572 { 573 char *symn; /* symbol name */ 574 size_t tsiz; 575 int rv; 576 unsigned long kaddr; 577 const char *sym2sysctl[] = { /* symbol to sysctl name table */ 578 "kern.ipc.sema", 579 "kern.ipc.seminfo", 580 "kern.ipc.msginfo", 581 "kern.ipc.msqids", 582 "kern.ipc.shminfo", 583 "kern.ipc.shmsegs" }; 584 585 assert((unsigned)idx <= sizeof(sym2sysctl) / sizeof(*sym2sysctl)); 586 if (!use_sysctl) { 587 symn = symbols[idx].n_name; 588 if (*symn == '_') 589 symn++; 590 if (symbols[idx].n_type == 0 || symbols[idx].n_value == 0) 591 errx(1, "symbol %s undefined", symn); 592 /* 593 * For some symbols, the value we retreieve is 594 * actually a pointer; since we want the actual value, 595 * we have to manually dereference it. 596 */ 597 switch (idx) { 598 case X_MSQIDS: 599 tsiz = sizeof(msqids); 600 rv = kvm_read(kd, symbols[idx].n_value, 601 &msqids, tsiz); 602 kaddr = (u_long)msqids; 603 break; 604 case X_SHMSEGS: 605 tsiz = sizeof(shmsegs); 606 rv = kvm_read(kd, symbols[idx].n_value, 607 &shmsegs, tsiz); 608 kaddr = (u_long)shmsegs; 609 break; 610 case X_SEMA: 611 tsiz = sizeof(sema); 612 rv = kvm_read(kd, symbols[idx].n_value, 613 &sema, tsiz); 614 kaddr = (u_long)sema; 615 break; 616 default: 617 rv = tsiz = 0; 618 kaddr = symbols[idx].n_value; 619 break; 620 } 621 if ((unsigned)rv != tsiz) 622 errx(1, "%s: %s", symn, kvm_geterr(kd)); 623 if ((unsigned)kvm_read(kd, kaddr, addr, size) != size) 624 errx(1, "%s: %s", symn, kvm_geterr(kd)); 625 } else { 626 switch (idx) { 627 case X_SHMINFO: 628 sysctlgatherstruct(addr, size, shminfo_scgsv); 629 break; 630 case X_SEMINFO: 631 sysctlgatherstruct(addr, size, seminfo_scgsv); 632 break; 633 case X_MSGINFO: 634 sysctlgatherstruct(addr, size, msginfo_scgsv); 635 break; 636 default: 637 tsiz = size; 638 rv = sysctlbyname(sym2sysctl[idx], addr, &tsiz, 639 NULL, 0); 640 if (rv == -1) 641 err(1, "sysctlbyname: %s", sym2sysctl[idx]); 642 if (tsiz != size) 643 errx(1, "%s size mismatch " 644 "(expected %d, got %d)", 645 sym2sysctl[idx], size, tsiz); 646 break; 647 } 648 } 649 } 650 651 void 652 usage() 653 { 654 655 fprintf(stderr, 656 "usage: ipcs [-abcmopqsty] [-C corefile] [-N namelist]\n"); 657 exit(1); 658 } 659