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
main(int argc,char * argv[])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
hp(char type,char * modesp,struct ipc_perm64 * permp,int slot)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
jp(struct ipc_perm64 * permp)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
tp(ipc_time_t gmt64)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
dumpmsgq(int msqid)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
dumpmsg(long type,char * msg,size_t msgsize)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
getzone(char * arg)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
printzone(zoneid_t id)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