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