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