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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * ipcs - IPC status 31 * 32 * Examine and print certain things about 33 * message queues, semaphores and shared memory. 34 * 35 * IPC information is obtained via msgctl64, semctl64 and shmctl64. 36 * As of SunOS 5.8, the IPC identifiers are obtained from msgids(), 37 * semids(), and shmids() rather than reading them from /dev/kmem. 38 * This ensures that the information in each msgid_ds, semid_ds or 39 * shmid_ds data structure that we obtain is complete and consistent, 40 * and allows us not to be a setgid-sys isaexec process. 41 */ 42 43 #include <sys/types.h> 44 #include <sys/ipc.h> 45 #include <sys/ipc_impl.h> 46 #include <sys/msg.h> 47 #include <sys/sem.h> 48 #include <sys/shm.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <time.h> 52 #include <grp.h> 53 #include <pwd.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <ctype.h> 57 #include <unistd.h> 58 #include <locale.h> 59 #include <langinfo.h> 60 #include <string.h> 61 #include <limits.h> 62 #include <project.h> 63 #include <zone.h> 64 65 #define USAGE \ 66 "usage: ipcs [-AabciJmopqstZ] [-D mtype] [-z zone]\n" 67 68 static char chdr[] = "T ID KEY MODE OWNER GROUP"; 69 /* common header format */ 70 static char chdr2[] = " CREATOR CGROUP"; /* c option header format */ 71 static char chdr3[] = " PROJECT"; /* J option header format */ 72 static char opts[] = "AabciJmopqstD:z:Z"; /* getopt options */ 73 74 static long mtype; /* -D: user-supplied message type */ 75 static zoneid_t zoneid; /* -z: user-supplied zone id */ 76 77 static int bflg, /* biggest size: */ 78 /* segsz on m; qbytes on q; nsems on s */ 79 cflg, /* creator's login and group names */ 80 Dflg, /* dump contents of message queues */ 81 iflg, /* ISM attaches */ 82 Jflg, /* dump project name */ 83 mflg, /* shared memory status */ 84 oflg, /* outstanding data: */ 85 /* nattch on m; cbytes, qnum on q */ 86 pflg, /* process id's: lrpid, lspid on q; */ 87 /* cpid, lpid on m */ 88 qflg, /* message queue status */ 89 sflg, /* semaphore status */ 90 tflg, /* times: atime, ctime, dtime on m; */ 91 /* ctime, rtime, stime on q; */ 92 /* ctime, otime on s */ 93 zflg, /* show only objects from specified zone */ 94 Zflg, /* display zone name */ 95 err; /* option error count */ 96 97 static void hp(char, char *, struct ipc_perm64 *, int); 98 static void jp(struct ipc_perm64 *); 99 static void tp(ipc_time_t); 100 static void dumpmsgq(int); 101 static void dumpmsg(long, char *, size_t); 102 static zoneid_t getzone(char *); 103 static void printzone(zoneid_t); 104 105 int 106 main(int argc, char *argv[]) 107 { 108 static int *ids; /* array of IPC identifiers from *ids() */ 109 static uint_t nids; /* number of entries in ids */ 110 111 int o; /* option flag */ 112 int id; /* IPC identifier */ 113 int i; 114 uint_t n; /* table size */ 115 time_t now; /* date */ 116 char tbuf[BUFSIZ]; 117 char *dfmt; /* date format pointer */ 118 char *endptr; /* terminator for strtol() */ 119 120 (void) setlocale(LC_ALL, ""); 121 (void) textdomain(TEXT_DOMAIN); 122 123 (void) memset(tbuf, 0, sizeof (tbuf)); 124 dfmt = nl_langinfo(_DATE_FMT); 125 126 zoneid = getzoneid(); /* default zone id if -z and -Z not used */ 127 128 /* Go through the options and set flags. */ 129 while ((o = getopt(argc, argv, opts)) != EOF) { 130 switch (o) { 131 case 'A': 132 bflg = cflg = iflg = oflg = pflg = tflg = Jflg = 1; 133 break; 134 case 'a': 135 bflg = cflg = oflg = pflg = tflg = 1; 136 break; 137 case 'b': 138 bflg = 1; 139 break; 140 case 'c': 141 cflg = 1; 142 break; 143 case 'D': 144 mtype = strtol(optarg, &endptr, 0); 145 if (endptr == optarg || *endptr != '\0') { 146 (void) fprintf(stderr, 147 gettext("ipcs: invalid message type: %s\n"), 148 optarg); 149 err++; 150 break; 151 } 152 Dflg = 1; 153 break; 154 case 'i': 155 iflg = 1; 156 break; 157 case 'J': 158 Jflg = 1; 159 break; 160 case 'm': 161 mflg = 1; 162 break; 163 case 'o': 164 oflg = 1; 165 break; 166 case 'p': 167 pflg = 1; 168 break; 169 case 'q': 170 qflg = 1; 171 break; 172 case 's': 173 sflg = 1; 174 break; 175 case 't': 176 tflg = 1; 177 break; 178 case 'z': 179 zflg = 1; 180 zoneid = getzone(optarg); 181 break; 182 case 'Z': 183 Zflg = 1; 184 break; 185 case '?': 186 err++; 187 break; 188 } 189 } 190 if (err || (optind < argc)) { 191 (void) fprintf(stderr, gettext(USAGE)); 192 exit(1); 193 } 194 195 if ((mflg + qflg + sflg) == 0) 196 mflg = qflg = sflg = 1; 197 198 now = time(NULL); 199 (void) strftime(tbuf, sizeof (tbuf), dfmt, localtime(&now)); 200 (void) printf(gettext("IPC status from <running system> as of %s\n"), 201 tbuf); 202 203 /* 204 * Print Message Queue status report. 205 */ 206 if (qflg) { 207 struct msqid_ds64 qds; 208 209 for (;;) { 210 if (msgids(ids, nids, &n) != 0) { 211 perror("msgids"); 212 exit(1); 213 } 214 if (n <= nids) 215 break; 216 ids = realloc(ids, (nids = n) * sizeof (int)); 217 } 218 219 (void) printf("%s%s%s%s%s%s%s%s\n", chdr, 220 cflg ? chdr2 : "", 221 oflg ? " CBYTES QNUM" : "", 222 bflg ? " QBYTES" : "", 223 pflg ? " LSPID LRPID" : "", 224 tflg ? " STIME RTIME CTIME " : "", 225 Jflg ? chdr3 : "", 226 Zflg ? " ZONE" : ""); 227 228 (void) printf(gettext("Message Queues:\n")); 229 230 for (i = 0; i < n; i++) { 231 id = ids[i]; 232 if (msgctl64(id, IPC_STAT64, &qds) < 0) 233 continue; 234 /* ignore zone if -Z was used and -z wasn't */ 235 if ((zflg || !Zflg) && 236 qds.msgx_perm.ipcx_zoneid != zoneid) 237 continue; 238 hp('q', "SRrw-rw-rw-", &qds.msgx_perm, id); 239 if (oflg) 240 (void) printf(" %6llu %5llu", 241 qds.msgx_cbytes, qds.msgx_qnum); 242 if (bflg) 243 (void) printf(" %6llu", qds.msgx_qbytes); 244 if (pflg) 245 (void) printf(" %5d %5d", 246 (int)qds.msgx_lspid, (int)qds.msgx_lrpid); 247 if (tflg) { 248 tp(qds.msgx_stime); 249 tp(qds.msgx_rtime); 250 tp(qds.msgx_ctime); 251 } 252 if (Jflg) 253 jp(&qds.msgx_perm); 254 if (Zflg) 255 printzone(qds.msgx_perm.ipcx_zoneid); 256 (void) printf("\n"); 257 if (Dflg) 258 dumpmsgq(id); 259 } 260 } 261 262 /* 263 * Print Shared Memory status report. 264 */ 265 if (mflg) { 266 struct shmid_ds64 mds; 267 268 for (;;) { 269 if (shmids(ids, nids, &n) != 0) { 270 perror("shmids"); 271 exit(1); 272 } 273 if (n <= nids) 274 break; 275 ids = realloc(ids, (nids = n) * sizeof (int)); 276 } 277 278 if (!qflg || oflg || bflg || pflg || tflg || iflg) 279 (void) printf("%s%s%s%s%s%s%s%s%s\n", chdr, 280 cflg ? chdr2 : "", 281 oflg ? " NATTCH" : "", 282 bflg ? " SEGSZ" : "", 283 pflg ? " CPID LPID" : "", 284 tflg ? " ATIME DTIME CTIME " : "", 285 iflg ? " ISMATTCH" : "", 286 Jflg ? chdr3 : "", 287 Zflg ? " ZONE" : ""); 288 289 (void) printf(gettext("Shared Memory:\n")); 290 291 for (i = 0; i < n; i++) { 292 id = ids[i]; 293 if (shmctl64(id, IPC_STAT64, &mds) < 0) 294 continue; 295 /* ignore zone if -Z was used and -z wasn't */ 296 if ((zflg || !Zflg) && 297 mds.shmx_perm.ipcx_zoneid != zoneid) 298 continue; 299 hp('m', "--rw-rw-rw-", &mds.shmx_perm, id); 300 if (oflg) 301 (void) printf(" %6llu", mds.shmx_nattch); 302 if (bflg) 303 (void) printf(" %10llu", mds.shmx_segsz); 304 if (pflg) 305 (void) printf(" %5d %5d", 306 (int)mds.shmx_cpid, (int)mds.shmx_lpid); 307 if (tflg) { 308 tp(mds.shmx_atime); 309 tp(mds.shmx_dtime); 310 tp(mds.shmx_ctime); 311 } 312 if (iflg) 313 (void) printf(" %8llu", mds.shmx_cnattch); 314 if (Jflg) 315 jp(&mds.shmx_perm); 316 if (Zflg) 317 printzone(mds.shmx_perm.ipcx_zoneid); 318 (void) printf("\n"); 319 } 320 } 321 322 /* 323 * Print Semaphore facility status. 324 */ 325 if (sflg) { 326 struct semid_ds64 sds; 327 union semun { 328 int val; 329 struct semid_ds64 *buf; 330 ushort_t *array; 331 } semarg; 332 semarg.buf = &sds; 333 334 for (;;) { 335 if (semids(ids, nids, &n) != 0) { 336 perror("semids"); 337 exit(1); 338 } 339 if (n <= nids) 340 break; 341 ids = realloc(ids, (nids = n) * sizeof (int)); 342 } 343 344 if (bflg || tflg || (!qflg && !mflg)) 345 (void) printf("%s%s%s%s%s%s\n", chdr, 346 cflg ? chdr2 : "", 347 bflg ? " NSEMS" : "", 348 tflg ? " OTIME CTIME " : "", 349 Jflg ? chdr3 : "", 350 Zflg ? " ZONE" : ""); 351 352 (void) printf(gettext("Semaphores:\n")); 353 354 for (i = 0; i < n; i++) { 355 id = ids[i]; 356 if (semctl64(id, 0, IPC_STAT64, semarg) < 0) 357 continue; 358 /* ignore zone if -Z was used and -z wasn't */ 359 if ((zflg || !Zflg) && 360 sds.semx_perm.ipcx_zoneid != zoneid) 361 continue; 362 hp('s', "--ra-ra-ra-", &sds.semx_perm, id); 363 if (bflg) 364 (void) printf(" %5u", sds.semx_nsems); 365 if (tflg) { 366 tp(sds.semx_otime); 367 tp(sds.semx_ctime); 368 } 369 if (Jflg) 370 jp(&sds.semx_perm); 371 if (Zflg) 372 printzone(sds.semx_perm.ipcx_zoneid); 373 (void) printf("\n"); 374 } 375 } 376 377 return (0); 378 } 379 380 /* 381 * hp - common header print 382 */ 383 static void 384 hp(char type, char *modesp, struct ipc_perm64 *permp, int slot) 385 { 386 int i; /* loop control */ 387 struct group *g; /* ptr to group group entry */ 388 struct passwd *u; /* ptr to user passwd entry */ 389 char keyfield[16]; 390 391 (void) snprintf(keyfield, sizeof (keyfield), " 0x%x", permp->ipcx_key); 392 (void) printf("%c %10d %-13s", type, slot, keyfield); 393 394 for (i = 02000; i; modesp++, i >>= 1) 395 (void) printf("%c", (permp->ipcx_mode & i) ? *modesp : '-'); 396 if ((u = getpwuid(permp->ipcx_uid)) == NULL) 397 (void) printf("%9d", (int)permp->ipcx_uid); 398 else 399 (void) printf("%9.8s", u->pw_name); 400 if ((g = getgrgid(permp->ipcx_gid)) == NULL) 401 (void) printf("%9d", (int)permp->ipcx_gid); 402 else 403 (void) printf("%9.8s", g->gr_name); 404 405 if (cflg) { 406 if ((u = getpwuid(permp->ipcx_cuid)) == NULL) 407 (void) printf("%9d", (int)permp->ipcx_cuid); 408 else 409 (void) printf("%9.8s", u->pw_name); 410 if ((g = getgrgid(permp->ipcx_cgid)) == NULL) 411 (void) printf("%9d", (int)permp->ipcx_cgid); 412 else 413 (void) printf("%9.8s", g->gr_name); 414 } 415 } 416 417 /* 418 * jp - project header print 419 */ 420 static void 421 jp(struct ipc_perm64 *permp) 422 { 423 struct project proj; 424 char buf[PROJECT_BUFSZ]; 425 426 if ((getprojbyid(permp->ipcx_projid, &proj, buf, 427 PROJECT_BUFSZ)) == NULL) 428 (void) printf("%16ld", permp->ipcx_projid); 429 else 430 (void) printf("%16.15s", proj.pj_name); 431 } 432 433 /* 434 * tp - time entry printer 435 */ 436 void 437 tp(ipc_time_t gmt64) 438 { 439 struct tm *t; /* ptr to converted time */ 440 time_t gmt = (time_t)gmt64; 441 442 if (gmt && gmt64 <= UINT_MAX) { 443 t = localtime(&gmt); 444 (void) printf(" %2d:%2.2d:%2.2d", 445 t->tm_hour, t->tm_min, t->tm_sec); 446 } else { 447 (void) printf("%9s", gettext(" no-entry")); 448 } 449 } 450 451 /* Round up to a sizeof (size_t) boundary */ 452 #define SZROUND(x) (((x) + sizeof (size_t) - 1) & ~(sizeof (size_t) - 1)) 453 454 /* 455 * dumpmsgq - dump all messages on a message queue 456 */ 457 void 458 dumpmsgq(int msqid) 459 { 460 static struct msgsnap_head *buf = NULL; 461 static size_t bufsize; 462 463 struct msgsnap_mhead *mhead; 464 size_t i; 465 466 /* allocate the minimum required buffer size on first time through */ 467 if (buf == NULL) 468 buf = malloc(bufsize = sizeof (struct msgsnap_head)); 469 470 /* 471 * Fetch all messages specified by mtype from 472 * the queue while leaving the queue intact. 473 */ 474 for (;;) { 475 if (msgsnap(msqid, buf, bufsize, mtype) != 0) { 476 /* 477 * Don't complain; either the user does not have 478 * read permission on msqid or msqid was deleted. 479 */ 480 return; 481 } 482 if (bufsize >= buf->msgsnap_size) { 483 /* we collected all of the messages */ 484 break; 485 } 486 /* The buffer is too small; allocate a bigger buffer */ 487 buf = realloc(buf, bufsize = buf->msgsnap_size); 488 } 489 490 /* 491 * Process each message in the queue (there may be none). 492 * The first message header starts just after the buffer header. 493 */ 494 mhead = (struct msgsnap_mhead *)(buf + 1); 495 for (i = 0; i < buf->msgsnap_nmsg; i++) { 496 size_t mlen = mhead->msgsnap_mlen; 497 498 dumpmsg(mhead->msgsnap_mtype, (char *)(mhead + 1), mlen); 499 500 /* advance to next message header */ 501 /* LINTED alignment */ 502 mhead = (struct msgsnap_mhead *) 503 ((caddr_t)(mhead + 1) + SZROUND(mlen)); 504 } 505 } 506 507 /* 508 * dumpmsg - dump one message from a message queue. 509 */ 510 void 511 dumpmsg(long type, char *msg, size_t msgsize) 512 { 513 size_t i, j, k; 514 int c; 515 516 (void) printf(gettext(" message type %ld, size %lu\n"), 517 type, (ulong_t)msgsize); 518 519 for (i = 0; i < msgsize; i += 16) { 520 /* first in hex */ 521 (void) printf(" %5ld: ", (ulong_t)i); 522 for (j = 0; j < 16; j++) { 523 if ((k = i + j) < msgsize) 524 (void) printf("%2.2x ", msg[k] & 0xff); 525 else 526 (void) printf(" "); 527 } 528 /* then in ascii */ 529 (void) printf(" "); 530 for (j = 0; j < 16; j++) { 531 if ((k = i + j) >= msgsize) 532 break; 533 c = msg[k] & 0xff; 534 if (isascii(c) && isprint(c)) 535 (void) printf("%c", c); 536 else 537 (void) printf("."); 538 } 539 (void) printf("\n"); 540 } 541 } 542 543 /* convert string containing zone name or id to a numeric id */ 544 static zoneid_t 545 getzone(char *arg) 546 { 547 zoneid_t zoneid; 548 549 if (zone_get_id(arg, &zoneid) != 0) { 550 (void) fprintf(stderr, 551 gettext("ipcs: unknown zone: %s\n"), arg); 552 exit(1); 553 } 554 return (zoneid); 555 } 556 557 static void 558 printzone(zoneid_t id) 559 { 560 char zone_name[ZONENAME_MAX]; 561 562 if (getzonenamebyid(id, zone_name, sizeof (zone_name)) < 0) 563 (void) printf("%9d", (int)id); 564 else 565 (void) printf("%9.8s", zone_name); 566 } 567