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