xref: /netbsd-src/usr.bin/ipcs/ipcs.c (revision 7fa608457b817eca6e0977b37f758ae064f3c99c)
1 /*	$NetBSD: ipcs.c,v 1.37 2006/11/25 21:40:06 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Simon Burge.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
41  * All rights reserved.
42  *
43  * Redistribution and use in source and binary forms, with or without
44  * modification, are permitted provided that the following conditions
45  * are met:
46  * 1. Redistributions of source code must retain the above copyright
47  *    notice, this list of conditions and the following disclaimer.
48  * 2. Redistributions in binary form must reproduce the above copyright
49  *    notice, this list of conditions and the following disclaimer in the
50  *    documentation and/or other materials provided with the distribution.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/param.h>
65 #include <sys/sysctl.h>
66 #include <sys/ipc.h>
67 #include <sys/sem.h>
68 #include <sys/shm.h>
69 #include <sys/msg.h>
70 
71 #include <err.h>
72 #include <fcntl.h>
73 #include <grp.h>
74 #include <kvm.h>
75 #include <limits.h>
76 #include <nlist.h>
77 #include <paths.h>
78 #include <pwd.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include <string.h>
82 #include <time.h>
83 #include <unistd.h>
84 
85 #define	SHMINFO		1
86 #define	SHMTOTAL	2
87 #define	MSGINFO		4
88 #define	MSGTOTAL	8
89 #define	SEMINFO		16
90 #define	SEMTOTAL	32
91 
92 #define BIGGEST		1
93 #define CREATOR		2
94 #define OUTSTANDING	4
95 #define PID		8
96 #define TIME		16
97 
98 static char	*core = NULL, *namelist = NULL;
99 static int	display = 0;
100 static int	option = 0;
101 
102 static void	cvt_time(time_t, char *, size_t);
103 static char    *fmt_perm(u_short);
104 static void	ipcs_kvm(void);
105 static void	msg_sysctl(void);
106 static void	sem_sysctl(void);
107 static void	shm_sysctl(void);
108 static void	show_msginfo(time_t, time_t, time_t, int, u_int64_t, mode_t,
109     uid_t, gid_t, uid_t, gid_t, u_int64_t, u_int64_t, u_int64_t, pid_t, pid_t);
110 static void	show_msginfo_hdr(void);
111 static void	show_msgtotal(struct msginfo *);
112 static void	show_seminfo_hdr(void);
113 static void	show_seminfo(time_t, time_t, int, u_int64_t, mode_t, uid_t,
114     gid_t, uid_t, gid_t, int16_t);
115 static void	show_semtotal(struct seminfo *);
116 static void	show_shminfo(time_t, time_t, time_t, int, u_int64_t, mode_t,
117     uid_t, gid_t, uid_t, gid_t, u_int32_t, u_int64_t, pid_t, pid_t);
118 static void	show_shminfo_hdr(void);
119 static void	show_shmtotal(struct shminfo *);
120 static void	usage(void) __attribute__((__noreturn__));
121 static void	unconfsem(void);
122 static void	unconfmsg(void);
123 static void	unconfshm(void);
124 
125 static void
126 unconfsem(void)
127 {
128 	warnx("SVID semaphores facility not configured in the system");
129 }
130 
131 static void
132 unconfmsg(void)
133 {
134 	warnx("SVID messages facility not configured in the system");
135 }
136 
137 static void
138 unconfshm(void)
139 {
140 	warnx("SVID shared memory facility not configured in the system");
141 }
142 
143 static char *
144 fmt_perm(u_short mode)
145 {
146 	static char buffer[12];
147 
148 	buffer[0] = '-';
149 	buffer[1] = '-';
150 	buffer[2] = ((mode & 0400) ? 'r' : '-');
151 	buffer[3] = ((mode & 0200) ? 'w' : '-');
152 	buffer[4] = ((mode & 0100) ? 'a' : '-');
153 	buffer[5] = ((mode & 0040) ? 'r' : '-');
154 	buffer[6] = ((mode & 0020) ? 'w' : '-');
155 	buffer[7] = ((mode & 0010) ? 'a' : '-');
156 	buffer[8] = ((mode & 0004) ? 'r' : '-');
157 	buffer[9] = ((mode & 0002) ? 'w' : '-');
158 	buffer[10] = ((mode & 0001) ? 'a' : '-');
159 	buffer[11] = '\0';
160 	return (&buffer[0]);
161 }
162 
163 static void
164 cvt_time(time_t t, char *buf, size_t buflen)
165 {
166 	struct tm *tm;
167 
168 	if (t == 0)
169 		(void)strlcpy(buf, "no-entry", buflen);
170 	else {
171 		tm = localtime(&t);
172 		(void)snprintf(buf, buflen, "%2d:%02d:%02d",
173 			tm->tm_hour, tm->tm_min, tm->tm_sec);
174 	}
175 }
176 int
177 main(int argc, char *argv[])
178 {
179 	int i;
180 	time_t now;
181 
182 	while ((i = getopt(argc, argv, "MmQqSsabC:cN:optT")) != -1)
183 		switch (i) {
184 		case 'M':
185 			display |= SHMTOTAL;
186 			break;
187 		case 'm':
188 			display |= SHMINFO;
189 			break;
190 		case 'Q':
191 			display |= MSGTOTAL;
192 			break;
193 		case 'q':
194 			display |= MSGINFO;
195 			break;
196 		case 'S':
197 			display |= SEMTOTAL;
198 			break;
199 		case 's':
200 			display |= SEMINFO;
201 			break;
202 		case 'T':
203 			display |= SHMTOTAL | MSGTOTAL | SEMTOTAL;
204 			break;
205 		case 'a':
206 			option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
207 			break;
208 		case 'b':
209 			option |= BIGGEST;
210 			break;
211 		case 'C':
212 			core = optarg;
213 			break;
214 		case 'c':
215 			option |= CREATOR;
216 			break;
217 		case 'N':
218 			namelist = optarg;
219 			break;
220 		case 'o':
221 			option |= OUTSTANDING;
222 			break;
223 		case 'p':
224 			option |= PID;
225 			break;
226 		case 't':
227 			option |= TIME;
228 			break;
229 		default:
230 			usage();
231 		}
232 
233 	if (argc - optind > 0)
234 		usage();
235 
236 	(void)time(&now);
237 	(void)printf("IPC status from %s as of %s\n",
238 	    /* and extra \n from ctime(3) */
239 	    core == NULL ? "<running system>" : core, ctime(&now));
240 
241         if (display == 0)
242 		display = SHMINFO | MSGINFO | SEMINFO;
243 
244 	if (core == NULL) {
245 		if (display & (MSGINFO | MSGTOTAL))
246 			msg_sysctl();
247 		if (display & (SHMINFO | SHMTOTAL))
248 			shm_sysctl();
249 		if (display & (SEMINFO | SEMTOTAL))
250 			sem_sysctl();
251 	} else
252 		ipcs_kvm();
253 	return 0;
254 }
255 
256 static void
257 show_msgtotal(struct msginfo *msginfo)
258 {
259 	(void)printf("msginfo:\n");
260 	(void)printf("\tmsgmax: %6d\t(max characters in a message)\n",
261 	    msginfo->msgmax);
262 	(void)printf("\tmsgmni: %6d\t(# of message queues)\n",
263 	    msginfo->msgmni);
264 	(void)printf("\tmsgmnb: %6d\t(max characters in a message queue)\n",
265 	    msginfo->msgmnb);
266 	(void)printf("\tmsgtql: %6d\t(max # of messages in system)\n",
267 	    msginfo->msgtql);
268 	(void)printf("\tmsgssz: %6d\t(size of a message segment)\n",
269 	    msginfo->msgssz);
270 	(void)printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
271 	    msginfo->msgseg);
272 }
273 
274 static void
275 show_shmtotal(struct shminfo *shminfo)
276 {
277 	(void)printf("shminfo:\n");
278 	(void)printf("\tshmmax: %7d\t(max shared memory segment size)\n",
279 	    shminfo->shmmax);
280 	(void)printf("\tshmmin: %7d\t(min shared memory segment size)\n",
281 	    shminfo->shmmin);
282 	(void)printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n",
283 	    shminfo->shmmni);
284 	(void)printf("\tshmseg: %7d\t(max shared memory segments per process)\n",
285 	    shminfo->shmseg);
286 	(void)printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n",
287 	    shminfo->shmall);
288 }
289 
290 static void
291 show_semtotal(struct seminfo *seminfo)
292 {
293 	(void)printf("seminfo:\n");
294 	(void)printf("\tsemmap: %6d\t(# of entries in semaphore map)\n",
295 	    seminfo->semmap);
296 	(void)printf("\tsemmni: %6d\t(# of semaphore identifiers)\n",
297 	    seminfo->semmni);
298 	(void)printf("\tsemmns: %6d\t(# of semaphores in system)\n",
299 	    seminfo->semmns);
300 	(void)printf("\tsemmnu: %6d\t(# of undo structures in system)\n",
301 	    seminfo->semmnu);
302 	(void)printf("\tsemmsl: %6d\t(max # of semaphores per id)\n",
303 	    seminfo->semmsl);
304 	(void)printf("\tsemopm: %6d\t(max # of operations per semop call)\n",
305 	    seminfo->semopm);
306 	(void)printf("\tsemume: %6d\t(max # of undo entries per process)\n",
307 	    seminfo->semume);
308 	(void)printf("\tsemusz: %6d\t(size in bytes of undo structure)\n",
309 	    seminfo->semusz);
310 	(void)printf("\tsemvmx: %6d\t(semaphore maximum value)\n",
311 	    seminfo->semvmx);
312 	(void)printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
313 	    seminfo->semaem);
314 }
315 
316 static void
317 show_msginfo_hdr(void)
318 {
319 	(void)printf("Message Queues:\n");
320 	(void)printf("T        ID     KEY        MODE       OWNER    GROUP");
321 	if (option & CREATOR)
322 		(void)printf("  CREATOR   CGROUP");
323 	if (option & OUTSTANDING)
324 		(void)printf(" CBYTES  QNUM");
325 	if (option & BIGGEST)
326 		(void)printf(" QBYTES");
327 	if (option & PID)
328 		(void)printf(" LSPID LRPID");
329 	if (option & TIME)
330 		(void)printf("    STIME    RTIME    CTIME");
331 	(void)printf("\n");
332 }
333 
334 static void
335 show_msginfo(time_t s_time, time_t r_time, time_t c_time, int ipcid,
336     u_int64_t key,
337     mode_t mode, uid_t uid, gid_t gid, uid_t cuid, gid_t cgid,
338     u_int64_t cbytes, u_int64_t qnum, u_int64_t qbytes, pid_t lspid,
339     pid_t lrpid)
340 {
341 	char s_time_buf[100], r_time_buf[100], c_time_buf[100];
342 
343 	if (option & TIME) {
344 		cvt_time(s_time, s_time_buf, sizeof(s_time_buf));
345 		cvt_time(r_time, r_time_buf, sizeof(r_time_buf));
346 		cvt_time(c_time, c_time_buf, sizeof(c_time_buf));
347 	}
348 
349 	(void)printf("q %9d %10lld %s %8s %8s", ipcid, (long long)key, fmt_perm(mode),
350 	    user_from_uid(uid, 0), group_from_gid(gid, 0));
351 
352 	if (option & CREATOR)
353 		(void)printf(" %8s %8s", user_from_uid(cuid, 0),
354 		    group_from_gid(cgid, 0));
355 
356 	if (option & OUTSTANDING)
357 		(void)printf(" %6lld %5lld", (long long)cbytes, (long long)qnum);
358 
359 	if (option & BIGGEST)
360 		(void)printf(" %6lld", (long long)qbytes);
361 
362 	if (option & PID)
363 		(void)printf(" %5d %5d", lspid, lrpid);
364 
365 	if (option & TIME)
366 		(void)printf(" %s %s %s", s_time_buf, r_time_buf, c_time_buf);
367 
368 	(void)printf("\n");
369 }
370 
371 static void
372 show_shminfo_hdr(void)
373 {
374 	(void)printf("Shared Memory:\n");
375 	(void)printf("T        ID     KEY        MODE       OWNER    GROUP");
376 	if (option & CREATOR)
377 		(void)printf("  CREATOR   CGROUP");
378 	if (option & OUTSTANDING)
379 		(void)printf(" NATTCH");
380 	if (option & BIGGEST)
381 		(void)printf("   SEGSZ");
382 	if (option & PID)
383 		(void)printf("  CPID  LPID");
384 	if (option & TIME)
385 		(void)printf("    ATIME    DTIME    CTIME");
386 	(void)printf("\n");
387 }
388 
389 static void
390 show_shminfo(time_t atime, time_t dtime, time_t c_time, int ipcid, u_int64_t key,
391     mode_t mode, uid_t uid, gid_t gid, uid_t cuid, gid_t cgid,
392     u_int32_t nattch, u_int64_t segsz, pid_t cpid, pid_t lpid)
393 {
394 	char atime_buf[100], dtime_buf[100], c_time_buf[100];
395 
396 	if (option & TIME) {
397 		cvt_time(atime, atime_buf, sizeof(atime_buf));
398 		cvt_time(dtime, dtime_buf, sizeof(dtime_buf));
399 		cvt_time(c_time, c_time_buf, sizeof(c_time_buf));
400 	}
401 
402 	(void)printf("m %9d %10lld %s %8s %8s", ipcid, (long long)key, fmt_perm(mode),
403 	    user_from_uid(uid, 0), group_from_gid(gid, 0));
404 
405 	if (option & CREATOR)
406 		(void)printf(" %8s %8s", user_from_uid(cuid, 0),
407 		    group_from_gid(cgid, 0));
408 
409 	if (option & OUTSTANDING)
410 		(void)printf(" %6d", nattch);
411 
412 	if (option & BIGGEST)
413 		(void)printf(" %7llu", (long long)segsz);
414 
415 	if (option & PID)
416 		(void)printf(" %5d %5d", cpid, lpid);
417 
418 	if (option & TIME)
419 		(void)printf(" %s %s %s",
420 		    atime_buf,
421 		    dtime_buf,
422 		    c_time_buf);
423 
424 	(void)printf("\n");
425 }
426 
427 static void
428 show_seminfo_hdr(void)
429 {
430 	(void)printf("Semaphores:\n");
431 	(void)printf("T        ID     KEY        MODE       OWNER    GROUP");
432 	if (option & CREATOR)
433 		(void)printf("  CREATOR   CGROUP");
434 	if (option & BIGGEST)
435 		(void)printf(" NSEMS");
436 	if (option & TIME)
437 		(void)printf("    OTIME    CTIME");
438 	(void)printf("\n");
439 }
440 
441 static void
442 show_seminfo(time_t otime, time_t c_time, int ipcid, u_int64_t key, mode_t mode,
443     uid_t uid, gid_t gid, uid_t cuid, gid_t cgid, int16_t nsems)
444 {
445 	char c_time_buf[100], otime_buf[100];
446 
447 	if (option & TIME) {
448 		cvt_time(otime, otime_buf, sizeof(otime_buf));
449 		cvt_time(c_time, c_time_buf, sizeof(c_time_buf));
450 	}
451 
452 	(void)printf("s %9d %10lld %s %8s %8s", ipcid, (long long)key, fmt_perm(mode),
453 	    user_from_uid(uid, 0), group_from_gid(gid, 0));
454 
455 	if (option & CREATOR)
456 		(void)printf(" %8s %8s", user_from_uid(cuid, 0),
457 		    group_from_gid(cgid, 0));
458 
459 	if (option & BIGGEST)
460 		(void)printf(" %5d", nsems);
461 
462 	if (option & TIME)
463 		(void)printf(" %s %s", otime_buf, c_time_buf);
464 
465 	(void)printf("\n");
466 }
467 
468 static void
469 msg_sysctl(void)
470 {
471 	struct msg_sysctl_info *msgsi;
472 	void *buf;
473 	int mib[4];
474 	size_t len;
475 	int i, valid;
476 
477 	mib[0] = CTL_KERN;
478 	mib[1] = KERN_SYSVIPC;
479 	mib[2] = KERN_SYSVIPC_MSG;
480 	len = sizeof(valid);
481 	if (sysctl(mib, 3, &valid, &len, NULL, 0) < 0) {
482 		warn("sysctl(KERN_SYSVIPC_MSG)");
483 		return;
484 	}
485 	if (!valid) {
486 		unconfmsg();
487 		return;
488 	}
489 
490 	mib[0] = CTL_KERN;
491 	mib[1] = KERN_SYSVIPC;
492 	mib[2] = KERN_SYSVIPC_INFO;
493 	mib[3] = KERN_SYSVIPC_MSG_INFO;
494 
495 	if (!(display & MSGINFO)) {
496 		/* totals only */
497 		len = sizeof(struct msginfo);
498 	} else {
499 		if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
500 			warn("sysctl(KERN_SYSVIPC_MSG_INFO)");
501 			return;
502 		}
503 	}
504 
505 	if ((buf = malloc(len)) == NULL)
506 		err(1, "malloc");
507 	msgsi = (struct msg_sysctl_info *)buf;
508 	if (sysctl(mib, 4, msgsi, &len, NULL, 0) < 0) {
509 		warn("sysctl(KERN_SYSVIPC_MSG_INFO)");
510 		goto done;
511 	}
512 
513 	if (display & MSGTOTAL)
514 		show_msgtotal(&msgsi->msginfo);
515 
516 	if (display & MSGINFO) {
517 		show_msginfo_hdr();
518 		for (i = 0; i < msgsi->msginfo.msgmni; i++) {
519 			struct msgid_ds_sysctl *msqptr = &msgsi->msgids[i];
520 			if (msqptr->msg_qbytes != 0)
521 				show_msginfo(msqptr->msg_stime,
522 				    msqptr->msg_rtime,
523 				    msqptr->msg_ctime,
524 				    IXSEQ_TO_IPCID(i, msqptr->msg_perm),
525 				    msqptr->msg_perm._key,
526 				    msqptr->msg_perm.mode,
527 				    msqptr->msg_perm.uid,
528 				    msqptr->msg_perm.gid,
529 				    msqptr->msg_perm.cuid,
530 				    msqptr->msg_perm.cgid,
531 				    msqptr->_msg_cbytes,
532 				    msqptr->msg_qnum,
533 				    msqptr->msg_qbytes,
534 				    msqptr->msg_lspid,
535 				    msqptr->msg_lrpid);
536 		}
537 		(void)printf("\n");
538 	}
539 done:
540 	free(buf);
541 }
542 
543 static void
544 shm_sysctl(void)
545 {
546 	struct shm_sysctl_info *shmsi;
547 	void *buf;
548 	int mib[4];
549 	size_t len;
550 	int i /*, valid */;
551 	long valid;
552 
553 	mib[0] = CTL_KERN;
554 	mib[1] = KERN_SYSVIPC;
555 	mib[2] = KERN_SYSVIPC_SHM;
556 	len = sizeof(valid);
557 	if (sysctl(mib, 3, &valid, &len, NULL, 0) < 0) {
558 		warn("sysctl(KERN_SYSVIPC_SHM)");
559 		return;
560 	}
561 	if (!valid) {
562 		unconfshm();
563 		return;
564 	}
565 
566 	mib[0] = CTL_KERN;
567 	mib[1] = KERN_SYSVIPC;
568 	mib[2] = KERN_SYSVIPC_INFO;
569 	mib[3] = KERN_SYSVIPC_SHM_INFO;
570 
571 	if (!(display & SHMINFO)) {
572 		/* totals only */
573 		len = sizeof(struct shminfo);
574 	} else {
575 		if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
576 			warn("sysctl(KERN_SYSVIPC_SHM_INFO)");
577 			return;
578 		}
579 	}
580 
581 	if ((buf = malloc(len)) == NULL)
582 		err(1, "malloc");
583 	shmsi = (struct shm_sysctl_info *)buf;
584 	if (sysctl(mib, 4, shmsi, &len, NULL, 0) < 0) {
585 		warn("sysctl(KERN_SYSVIPC_SHM_INFO)");
586 		goto done;
587 	}
588 
589 	if (display & SHMTOTAL)
590 		show_shmtotal(&shmsi->shminfo);
591 
592 	if (display & SHMINFO) {
593 		show_shminfo_hdr();
594 		for (i = 0; i < shmsi->shminfo.shmmni; i++) {
595 			struct shmid_ds_sysctl *shmptr = &shmsi->shmids[i];
596 			if (shmptr->shm_perm.mode & 0x0800)
597 				show_shminfo(shmptr->shm_atime,
598 				    shmptr->shm_dtime,
599 				    shmptr->shm_ctime,
600 				    IXSEQ_TO_IPCID(i, shmptr->shm_perm),
601 				    shmptr->shm_perm._key,
602 				    shmptr->shm_perm.mode,
603 				    shmptr->shm_perm.uid,
604 				    shmptr->shm_perm.gid,
605 				    shmptr->shm_perm.cuid,
606 				    shmptr->shm_perm.cgid,
607 				    shmptr->shm_nattch,
608 				    shmptr->shm_segsz,
609 				    shmptr->shm_cpid,
610 				    shmptr->shm_lpid);
611 		}
612 		(void)printf("\n");
613 	}
614 done:
615 	free(buf);
616 }
617 
618 static void
619 sem_sysctl(void)
620 {
621 	struct sem_sysctl_info *semsi;
622 	void *buf;
623 	int mib[4];
624 	size_t len;
625 	int i, valid;
626 
627 	mib[0] = CTL_KERN;
628 	mib[1] = KERN_SYSVIPC;
629 	mib[2] = KERN_SYSVIPC_SEM;
630 	len = sizeof(valid);
631 	if (sysctl(mib, 3, &valid, &len, NULL, 0) < 0) {
632 		warn("sysctl(KERN_SYSVIPC_SEM)");
633 		return;
634 	}
635 	if (!valid) {
636 		unconfsem();
637 		return;
638 	}
639 
640 	mib[0] = CTL_KERN;
641 	mib[1] = KERN_SYSVIPC;
642 	mib[2] = KERN_SYSVIPC_INFO;
643 	mib[3] = KERN_SYSVIPC_SEM_INFO;
644 
645 	if (!(display & SEMINFO)) {
646 		/* totals only */
647 		len = sizeof(struct seminfo);
648 	} else {
649 		if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) {
650 			warn("sysctl(KERN_SYSVIPC_SEM_INFO)");
651 			return;
652 		}
653 	}
654 
655 	if ((buf = malloc(len)) == NULL)
656 		err(1, "malloc");
657 	semsi = (struct sem_sysctl_info *)buf;
658 	if (sysctl(mib, 4, semsi, &len, NULL, 0) < 0) {
659 		warn("sysctl(KERN_SYSVIPC_SEM_INFO)");
660 		goto done;
661 	}
662 
663 	if (display & SEMTOTAL)
664 		show_semtotal(&semsi->seminfo);
665 
666 	if (display & SEMINFO) {
667 		show_seminfo_hdr();
668 		for (i = 0; i < semsi->seminfo.semmni; i++) {
669 			struct semid_ds_sysctl *semaptr = &semsi->semids[i];
670 			if ((semaptr->sem_perm.mode & SEM_ALLOC) != 0)
671 				show_seminfo(semaptr->sem_otime,
672 				    semaptr->sem_ctime,
673 				    IXSEQ_TO_IPCID(i, semaptr->sem_perm),
674 				    semaptr->sem_perm._key,
675 				    semaptr->sem_perm.mode,
676 				    semaptr->sem_perm.uid,
677 				    semaptr->sem_perm.gid,
678 				    semaptr->sem_perm.cuid,
679 				    semaptr->sem_perm.cgid,
680 				    semaptr->sem_nsems);
681 		}
682 		(void)printf("\n");
683 	}
684 done:
685 	free(buf);
686 }
687 
688 static struct nlist symbols[] = {
689 	{ .n_name = "_sema" },
690 #define X_SEMA		0
691 	{ .n_name = "_seminfo" },
692 #define X_SEMINFO	1
693 	{ .n_name = "_semu" },
694 #define X_SEMU		2
695 	{ .n_name = "_msginfo" },
696 #define X_MSGINFO	3
697 	{ .n_name = "_msqids" },
698 #define X_MSQIDS	4
699 	{ .n_name = "_shminfo" },
700 #define X_SHMINFO	5
701 	{ .n_name = "_shmsegs" },
702 #define X_SHMSEGS	6
703 	{ .n_name = NULL }
704 };
705 
706 static void
707 ipcs_kvm(void)
708 {
709 	struct msginfo msginfo;
710 	struct msqid_ds *msqids;
711 	struct seminfo seminfo;
712 	struct semid_ds *sema;
713 	struct shminfo shminfo;
714 	struct shmid_ds *shmsegs;
715 	kvm_t *kd;
716 	char errbuf[_POSIX2_LINE_MAX];
717 	int i;
718 
719 	if ((kd = kvm_openfiles(namelist, core, NULL, O_RDONLY,
720 	    errbuf)) == NULL)
721 		errx(1, "can't open kvm: %s", errbuf);
722 
723 
724 	switch (kvm_nlist(kd, symbols)) {
725 	case 0:
726 		break;
727 	case -1:
728 		errx(1, "%s: unable to read symbol table.",
729 		    namelist == NULL ? _PATH_UNIX : namelist);
730 		/* NOTREACHED */
731 	default:
732 #ifdef notdef		/* they'll be told more civilly later */
733 		warnx("nlist failed");
734 		for (i = 0; symbols[i].n_name != NULL; i++)
735 			if (symbols[i].n_value == 0)
736 				warnx("symbol %s not found",
737 				    symbols[i].n_name);
738 #endif
739 		break;
740 	}
741 
742 	if ((display & (MSGINFO | MSGTOTAL)) &&
743 	    (kvm_read(kd, symbols[X_MSGINFO].n_value,
744 	     &msginfo, sizeof(msginfo)) == sizeof(msginfo))) {
745 
746 		if (display & MSGTOTAL)
747 			show_msgtotal(&msginfo);
748 
749 		if (display & MSGINFO) {
750 			struct msqid_ds *xmsqids;
751 
752 			if (kvm_read(kd, symbols[X_MSQIDS].n_value,
753 			    &msqids, sizeof(msqids)) != sizeof(msqids))
754 				errx(1, "kvm_read (%s): %s",
755 				    symbols[X_MSQIDS].n_name, kvm_geterr(kd));
756 
757 			xmsqids = malloc(sizeof(struct msqid_ds) *
758 			    msginfo.msgmni);
759 
760 			if (kvm_read(kd, (u_long)msqids, xmsqids,
761 			    sizeof(struct msqid_ds) * msginfo.msgmni) !=
762 			    sizeof(struct msqid_ds) * msginfo.msgmni)
763 				errx(1, "kvm_read (msqids): %s",
764 				    kvm_geterr(kd));
765 
766 			show_msginfo_hdr();
767 			for (i = 0; i < msginfo.msgmni; i++) {
768 				struct msqid_ds *msqptr = &xmsqids[i];
769 				if (msqptr->msg_qbytes != 0)
770 					show_msginfo(msqptr->msg_stime,
771 					    msqptr->msg_rtime,
772 					    msqptr->msg_ctime,
773 					    IXSEQ_TO_IPCID(i, msqptr->msg_perm),
774 					    (u_int64_t)msqptr->msg_perm._key,
775 					    msqptr->msg_perm.mode,
776 					    msqptr->msg_perm.uid,
777 					    msqptr->msg_perm.gid,
778 					    msqptr->msg_perm.cuid,
779 					    msqptr->msg_perm.cgid,
780 					    (u_int64_t)msqptr->_msg_cbytes,
781 					    (u_int64_t)msqptr->msg_qnum,
782 					    (u_int64_t)msqptr->msg_qbytes,
783 					    msqptr->msg_lspid,
784 					    msqptr->msg_lrpid);
785 			}
786 			(void)printf("\n");
787 			free(xmsqids);
788 		}
789 	} else
790 		if (display & (MSGINFO | MSGTOTAL))
791 			unconfmsg();
792 	if ((display & (SHMINFO | SHMTOTAL)) &&
793 	    (kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo,
794 	     sizeof(shminfo)) == sizeof(shminfo))) {
795 
796 		if (display & SHMTOTAL)
797 			show_shmtotal(&shminfo);
798 
799 		if (display & SHMINFO) {
800 			struct shmid_ds *xshmids;
801 
802 			if (kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs,
803 			    sizeof(shmsegs)) != sizeof(shmsegs))
804 				errx(1, "kvm_read (%s): %s",
805 				    symbols[X_SHMSEGS].n_name, kvm_geterr(kd));
806 
807 			xshmids = malloc(sizeof(struct shmid_ds) *
808 			    shminfo.shmmni);
809 
810 			if (kvm_read(kd, (u_long)shmsegs, xshmids,
811 			    sizeof(struct shmid_ds) * shminfo.shmmni) !=
812 			    sizeof(struct shmid_ds) * shminfo.shmmni)
813 				errx(1, "kvm_read (shmsegs): %s",
814 				    kvm_geterr(kd));
815 
816 			show_shminfo_hdr();
817 			for (i = 0; i < shminfo.shmmni; i++) {
818 				struct shmid_ds *shmptr = &xshmids[i];
819 				if (shmptr->shm_perm.mode & 0x0800)
820 					show_shminfo(shmptr->shm_atime,
821 					    shmptr->shm_dtime,
822 					    shmptr->shm_ctime,
823 					    IXSEQ_TO_IPCID(i, shmptr->shm_perm),
824 					    (u_int64_t)shmptr->shm_perm._key,
825 					    shmptr->shm_perm.mode,
826 					    shmptr->shm_perm.uid,
827 					    shmptr->shm_perm.gid,
828 					    shmptr->shm_perm.cuid,
829 					    shmptr->shm_perm.cgid,
830 					    shmptr->shm_nattch,
831 					    (u_int64_t)shmptr->shm_segsz,
832 					    shmptr->shm_cpid,
833 					    shmptr->shm_lpid);
834 			}
835 			(void)printf("\n");
836 			free(xshmids);
837 		}
838 	} else
839 		if (display & (SHMINFO | SHMTOTAL))
840 			unconfshm();
841 	if ((display & (SEMINFO | SEMTOTAL)) &&
842 	    (kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo,
843 	     sizeof(seminfo)) == sizeof(seminfo))) {
844 		struct semid_ds *xsema;
845 
846 		if (display & SEMTOTAL)
847 			show_semtotal(&seminfo);
848 
849 		if (display & SEMINFO) {
850 			if (kvm_read(kd, symbols[X_SEMA].n_value, &sema,
851 			    sizeof(sema)) != sizeof(sema))
852 				errx(1, "kvm_read (%s): %s",
853 				    symbols[X_SEMA].n_name, kvm_geterr(kd));
854 
855 			xsema = malloc(sizeof(struct semid_ds) *
856 			    seminfo.semmni);
857 
858 			if (kvm_read(kd, (u_long)sema, xsema,
859 			    sizeof(struct semid_ds) * seminfo.semmni) !=
860 			    sizeof(struct semid_ds) * seminfo.semmni)
861 				errx(1, "kvm_read (sema): %s",
862 				    kvm_geterr(kd));
863 
864 			show_seminfo_hdr();
865 			for (i = 0; i < seminfo.semmni; i++) {
866 				struct semid_ds *semaptr = &xsema[i];
867 				if ((semaptr->sem_perm.mode & SEM_ALLOC) != 0)
868 					show_seminfo(semaptr->sem_otime,
869 					    semaptr->sem_ctime,
870 					    IXSEQ_TO_IPCID(i, semaptr->sem_perm),
871 					    (u_int64_t)semaptr->sem_perm._key,
872 					    semaptr->sem_perm.mode,
873 					    semaptr->sem_perm.uid,
874 					    semaptr->sem_perm.gid,
875 					    semaptr->sem_perm.cuid,
876 					    semaptr->sem_perm.cgid,
877 					    semaptr->sem_nsems);
878 			}
879 
880 			(void)printf("\n");
881 			free(xsema);
882 		}
883 	} else
884 		if (display & (SEMINFO | SEMTOTAL))
885 			unconfsem();
886 	(void)kvm_close(kd);
887 }
888 
889 static void
890 usage(void)
891 {
892 
893 	(void)fprintf(stderr,
894 	    "Usage: %s [-abcmopqstMQST] [-C corefile] [-N namelist]\n",
895 	    getprogname());
896 	exit(1);
897 }
898