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