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