ipcs.c revision 90878
12731Sdfr/*
22738Sdfr * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
32738Sdfr * All rights reserved.
42738Sdfr *
52738Sdfr * Redistribution and use in source and binary forms, with or without
62738Sdfr * modification, are permitted provided that the following conditions
72738Sdfr * are met:
82738Sdfr * 1. Redistributions of source code must retain the above copyright
92738Sdfr *    notice, this list of conditions and the following disclaimer.
102738Sdfr * 2. Redistributions in binary form must reproduce the above copyright
112738Sdfr *    notice, this list of conditions and the following disclaimer in the
122738Sdfr *    documentation and/or other materials provided with the distribution.
132738Sdfr * 3. The name of the author may not be used to endorse or promote products
142738Sdfr *    derived from this software without specific prior written permission.
152738Sdfr *
162738Sdfr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
172738Sdfr * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
182738Sdfr * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
192738Sdfr * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
202738Sdfr * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
212738Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
222738Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
232738Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
242738Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
252738Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262731Sdfr */
272731Sdfr
2827421Scharnier#ifndef lint
2927421Scharnierstatic const char rcsid[] =
3050477Speter  "$FreeBSD: head/usr.bin/ipcs/ipcs.c 90878 2002-02-19 00:05:59Z imp $";
3127421Scharnier#endif /* not lint */
3227421Scharnier
3377551Sdd#include <assert.h>
3427421Scharnier#include <err.h>
3527421Scharnier#include <fcntl.h>
3690878Simp#include <grp.h>
3727421Scharnier#include <kvm.h>
3827421Scharnier#include <nlist.h>
3977551Sdd#include <limits.h>
4027421Scharnier#include <paths.h>
4190878Simp#include <pwd.h>
4277551Sdd#include <stddef.h>
432731Sdfr#include <stdio.h>
442731Sdfr#include <stdlib.h>
4578718Sdd#include <string.h>
462731Sdfr#include <unistd.h>
472731Sdfr
482731Sdfr#include <sys/types.h>
492731Sdfr#include <sys/param.h>
502738Sdfr#include <sys/time.h>
512731Sdfr#include <sys/proc.h>
5277551Sdd#include <sys/sysctl.h>
5355206Speter#define _KERNEL
542731Sdfr#include <sys/ipc.h>
552731Sdfr#include <sys/sem.h>
562731Sdfr#include <sys/shm.h>
572731Sdfr#include <sys/msg.h>
582731Sdfr
5977551Sdd/* SysCtlGatherStruct structure. */
6077551Sddstruct scgs_vector {
6177551Sdd	const char *sysctl;
6277551Sdd	off_t offset;
6377551Sdd	size_t size;
6477551Sdd};
6577551Sdd
6677551Sddint	use_sysctl = 1;
679499Sbdestruct semid_ds	*sema;
682890Sdgstruct seminfo	seminfo;
692890Sdgstruct msginfo	msginfo;
709499Sbdestruct msqid_ds	*msqids;
719499Sbdestruct shminfo	shminfo;
729499Sbdestruct shmid_ds	*shmsegs;
732890Sdg
7477551Sddvoid	sysctlgatherstruct __P((void *addr, size_t size,
7577551Sdd    struct scgs_vector *vec));
7677551Sddvoid	kget __P((int idx, void *addr, size_t size));
772738Sdfrvoid	usage __P((void));
782731Sdfr
792738Sdfrstatic struct nlist symbols[] = {
8077551Sdd	{"sema"},
812738Sdfr#define X_SEMA		0
8277551Sdd	{"seminfo"},
832738Sdfr#define X_SEMINFO	1
8477551Sdd	{"msginfo"},
8577551Sdd#define X_MSGINFO	2
8677551Sdd	{"msqids"},
8777551Sdd#define X_MSQIDS	3
8877551Sdd	{"shminfo"},
8977551Sdd#define X_SHMINFO	4
9077551Sdd	{"shmsegs"},
9177551Sdd#define X_SHMSEGS	5
922738Sdfr	{NULL}
932738Sdfr};
942731Sdfr
9577551Sdd#define	SHMINFO_XVEC				\
9677551SddX(shmmax, sizeof(int))				\
9777551SddX(shmmin, sizeof(int))				\
9877551SddX(shmmni, sizeof(int))				\
9977551SddX(shmseg, sizeof(int))				\
10077551SddX(shmall, sizeof(int))
10177551Sdd
10277551Sdd#define	SEMINFO_XVEC				\
10377551SddX(semmap, sizeof(int))				\
10477551SddX(semmni, sizeof(int))				\
10577551SddX(semmns, sizeof(int))				\
10677551SddX(semmnu, sizeof(int))				\
10777551SddX(semmsl, sizeof(int))				\
10877551SddX(semopm, sizeof(int))				\
10977551SddX(semume, sizeof(int))				\
11077551SddX(semusz, sizeof(int))				\
11177551SddX(semvmx, sizeof(int))				\
11277551SddX(semaem, sizeof(int))
11377551Sdd
11477551Sdd#define	MSGINFO_XVEC				\
11577551SddX(msgmax, sizeof(int))				\
11677551SddX(msgmni, sizeof(int))				\
11777551SddX(msgmnb, sizeof(int))				\
11877551SddX(msgtql, sizeof(int))				\
11977551SddX(msgssz, sizeof(int))				\
12077551SddX(msgseg, sizeof(int))
12177551Sdd
12277551Sdd#define	X(a, b)	{ "kern.ipc." #a, offsetof(TYPEC, a), (b) },
12377551Sdd#define	TYPEC	struct shminfo
12477551Sddstruct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { NULL } };
12577551Sdd#undef	TYPEC
12677551Sdd#define	TYPEC	struct seminfo
12777551Sddstruct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { NULL } };
12877551Sdd#undef	TYPEC
12977551Sdd#define	TYPEC	struct msginfo
13077551Sddstruct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { NULL } };
13177551Sdd#undef	TYPEC
13277551Sdd#undef	X
13377551Sdd
1342738Sdfrstatic kvm_t *kd;
1352738Sdfr
1362738Sdfrchar   *
1372738Sdfrfmt_perm(mode)
1382738Sdfr	u_short mode;
1392731Sdfr{
1402738Sdfr	static char buffer[100];
1412731Sdfr
1422738Sdfr	buffer[0] = '-';
1432738Sdfr	buffer[1] = '-';
1442738Sdfr	buffer[2] = ((mode & 0400) ? 'r' : '-');
1452738Sdfr	buffer[3] = ((mode & 0200) ? 'w' : '-');
1462738Sdfr	buffer[4] = ((mode & 0100) ? 'a' : '-');
1472738Sdfr	buffer[5] = ((mode & 0040) ? 'r' : '-');
1482738Sdfr	buffer[6] = ((mode & 0020) ? 'w' : '-');
1492738Sdfr	buffer[7] = ((mode & 0010) ? 'a' : '-');
1502738Sdfr	buffer[8] = ((mode & 0004) ? 'r' : '-');
1512738Sdfr	buffer[9] = ((mode & 0002) ? 'w' : '-');
1522738Sdfr	buffer[10] = ((mode & 0001) ? 'a' : '-');
1532738Sdfr	buffer[11] = '\0';
1542738Sdfr	return (&buffer[0]);
1552731Sdfr}
1562731Sdfr
1572731Sdfrvoid
1582738Sdfrcvt_time(t, buf)
1592738Sdfr	time_t  t;
1602738Sdfr	char   *buf;
1612731Sdfr{
1622738Sdfr	struct tm *tm;
1632731Sdfr
1642738Sdfr	if (t == 0) {
1652738Sdfr		strcpy(buf, "no-entry");
1662738Sdfr	} else {
1672738Sdfr		tm = localtime(&t);
1682738Sdfr		sprintf(buf, "%2d:%02d:%02d",
1692738Sdfr			tm->tm_hour, tm->tm_min, tm->tm_sec);
1702731Sdfr	}
1712731Sdfr}
1722738Sdfr#define	SHMINFO		1
1732738Sdfr#define	SHMTOTAL	2
1742738Sdfr#define	MSGINFO		4
1752738Sdfr#define	MSGTOTAL	8
1762738Sdfr#define	SEMINFO		16
1772738Sdfr#define	SEMTOTAL	32
1782731Sdfr
1792738Sdfr#define BIGGEST		1
1802738Sdfr#define CREATOR		2
1812738Sdfr#define OUTSTANDING	4
1822738Sdfr#define PID		8
1832738Sdfr#define TIME		16
1842731Sdfr
1852738Sdfrint
1862738Sdfrmain(argc, argv)
1872738Sdfr	int     argc;
1882738Sdfr	char   *argv[];
1892731Sdfr{
1902738Sdfr	int     display = SHMINFO | MSGINFO | SEMINFO;
1912738Sdfr	int     option = 0;
1922738Sdfr	char   *core = NULL, *namelist = NULL;
19377551Sdd	char	kvmoferr[_POSIX2_LINE_MAX];  /* Error buf for kvm_openfiles. */
1942738Sdfr	int     i;
1952731Sdfr
19677551Sdd	while ((i = getopt(argc, argv, "MmQqSsabC:cN:optTy")) != -1)
1972738Sdfr		switch (i) {
1982738Sdfr		case 'M':
1992738Sdfr			display = SHMTOTAL;
2002738Sdfr			break;
2012738Sdfr		case 'm':
2022738Sdfr			display = SHMINFO;
2032738Sdfr			break;
2042738Sdfr		case 'Q':
2052738Sdfr			display = MSGTOTAL;
2062738Sdfr			break;
2072738Sdfr		case 'q':
2082738Sdfr			display = MSGINFO;
2092738Sdfr			break;
2102738Sdfr		case 'S':
2112738Sdfr			display = SEMTOTAL;
2122738Sdfr			break;
2132738Sdfr		case 's':
2142738Sdfr			display = SEMINFO;
2152738Sdfr			break;
2162738Sdfr		case 'T':
2172738Sdfr			display = SHMTOTAL | MSGTOTAL | SEMTOTAL;
2182738Sdfr			break;
2192738Sdfr		case 'a':
2202738Sdfr			option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
2212738Sdfr			break;
2222738Sdfr		case 'b':
2232738Sdfr			option |= BIGGEST;
2242738Sdfr			break;
2252738Sdfr		case 'C':
2262738Sdfr			core = optarg;
2272738Sdfr			break;
2282738Sdfr		case 'c':
2292738Sdfr			option |= CREATOR;
2302738Sdfr			break;
2312738Sdfr		case 'N':
2322738Sdfr			namelist = optarg;
2332738Sdfr			break;
2342738Sdfr		case 'o':
2352738Sdfr			option |= OUTSTANDING;
2362738Sdfr			break;
2372738Sdfr		case 'p':
2382738Sdfr			option |= PID;
2392738Sdfr			break;
2402738Sdfr		case 't':
2412738Sdfr			option |= TIME;
2422738Sdfr			break;
24377551Sdd		case 'y':
24477551Sdd			use_sysctl = 0;
24577551Sdd			break;
2462738Sdfr		default:
2472738Sdfr			usage();
2482738Sdfr		}
24915990Spst
25015990Spst	/*
25177551Sdd	 * If paths to the exec file or core file were specified, we
25277551Sdd	 * aren't operating on the running kernel, so we can't use
25377551Sdd	 * sysctl.
25415990Spst	 */
25515990Spst	if (namelist != NULL || core != NULL)
25677551Sdd		use_sysctl = 0;
25715990Spst
25877551Sdd	if (!use_sysctl) {
25977551Sdd		kd = kvm_openfiles(namelist, core, NULL, O_RDONLY, kvmoferr);
26077551Sdd		if (kd == NULL)
26177551Sdd			errx(1, "kvm_openfiles: %s", kvmoferr);
26277551Sdd		switch (kvm_nlist(kd, symbols)) {
26377551Sdd		case 0:
26477551Sdd			break;
26577551Sdd		case -1:
26677551Sdd			errx(1, "unable to read kernel symbol table");
26777551Sdd		default:
2682738Sdfr#ifdef notdef		/* they'll be told more civilly later */
26977551Sdd			warnx("nlist failed");
27077551Sdd			for (i = 0; symbols[i].n_name != NULL; i++)
27177551Sdd				if (symbols[i].n_value == 0)
27277551Sdd					warnx("symbol %s not found",
27377551Sdd					    symbols[i].n_name);
27477551Sdd			break;
2752738Sdfr#endif
27677551Sdd		}
2772731Sdfr	}
2782731Sdfr
27977551Sdd	kget(X_MSGINFO, &msginfo, sizeof(msginfo));
28077551Sdd	if ((display & (MSGINFO | MSGTOTAL))) {
2812738Sdfr		if (display & MSGTOTAL) {
2822738Sdfr			printf("msginfo:\n");
2832738Sdfr			printf("\tmsgmax: %6d\t(max characters in a message)\n",
2842738Sdfr			    msginfo.msgmax);
2852738Sdfr			printf("\tmsgmni: %6d\t(# of message queues)\n",
2862738Sdfr			    msginfo.msgmni);
2872738Sdfr			printf("\tmsgmnb: %6d\t(max characters in a message queue)\n",
2882738Sdfr			    msginfo.msgmnb);
2892738Sdfr			printf("\tmsgtql: %6d\t(max # of messages in system)\n",
2902738Sdfr			    msginfo.msgtql);
2912738Sdfr			printf("\tmsgssz: %6d\t(size of a message segment)\n",
2922738Sdfr			    msginfo.msgssz);
2932738Sdfr			printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
2942738Sdfr			    msginfo.msgseg);
2952738Sdfr		}
2962738Sdfr		if (display & MSGINFO) {
2972738Sdfr			struct msqid_ds *xmsqids;
29877551Sdd			size_t xmsqids_len;
2992731Sdfr
3002731Sdfr
30177551Sdd			xmsqids_len = sizeof(struct msqid_ds) * msginfo.msgmni;
30277551Sdd			xmsqids = malloc(xmsqids_len);
30377551Sdd			kget(X_MSQIDS, xmsqids, xmsqids_len);
30477551Sdd
3052738Sdfr			printf("Message Queues:\n");
3062738Sdfr			printf("T     ID     KEY        MODE       OWNER    GROUP");
3072738Sdfr			if (option & CREATOR)
3082738Sdfr				printf("  CREATOR   CGROUP");
3092738Sdfr			if (option & OUTSTANDING)
3102738Sdfr				printf(" CBYTES  QNUM");
3112738Sdfr			if (option & BIGGEST)
3122738Sdfr				printf(" QBYTES");
3132738Sdfr			if (option & PID)
3142738Sdfr				printf(" LSPID LRPID");
3152738Sdfr			if (option & TIME)
3162738Sdfr				printf("   STIME    RTIME    CTIME");
3172738Sdfr			printf("\n");
3182738Sdfr			for (i = 0; i < msginfo.msgmni; i += 1) {
3192738Sdfr				if (xmsqids[i].msg_qbytes != 0) {
3202738Sdfr					char    stime_buf[100], rtime_buf[100],
3212738Sdfr					        ctime_buf[100];
3222738Sdfr					struct msqid_ds *msqptr = &xmsqids[i];
3232731Sdfr
3242738Sdfr					cvt_time(msqptr->msg_stime, stime_buf);
3252738Sdfr					cvt_time(msqptr->msg_rtime, rtime_buf);
3262738Sdfr					cvt_time(msqptr->msg_ctime, ctime_buf);
3272731Sdfr
3282738Sdfr					printf("q %6d %10d %s %8s %8s",
3292738Sdfr					    IXSEQ_TO_IPCID(i, msqptr->msg_perm),
3302738Sdfr					    msqptr->msg_perm.key,
3312738Sdfr					    fmt_perm(msqptr->msg_perm.mode),
3322738Sdfr					    user_from_uid(msqptr->msg_perm.uid, 0),
3332738Sdfr					    group_from_gid(msqptr->msg_perm.gid, 0));
3342731Sdfr
3352738Sdfr					if (option & CREATOR)
3362738Sdfr						printf(" %8s %8s",
3372738Sdfr						    user_from_uid(msqptr->msg_perm.cuid, 0),
3382738Sdfr						    group_from_gid(msqptr->msg_perm.cgid, 0));
3392731Sdfr
3402738Sdfr					if (option & OUTSTANDING)
3412738Sdfr						printf(" %6d %6d",
3422738Sdfr						    msqptr->msg_cbytes,
3432738Sdfr						    msqptr->msg_qnum);
3442731Sdfr
3452738Sdfr					if (option & BIGGEST)
3462738Sdfr						printf(" %6d",
3472738Sdfr						    msqptr->msg_qbytes);
3482731Sdfr
3492738Sdfr					if (option & PID)
3502738Sdfr						printf(" %6d %6d",
3512738Sdfr						    msqptr->msg_lspid,
3522738Sdfr						    msqptr->msg_lrpid);
3532731Sdfr
3542738Sdfr					if (option & TIME)
3552738Sdfr						printf("%s %s %s",
3562738Sdfr						    stime_buf,
3572738Sdfr						    rtime_buf,
3582738Sdfr						    ctime_buf);
3592731Sdfr
3602738Sdfr					printf("\n");
3612738Sdfr				}
3622738Sdfr			}
3632738Sdfr			printf("\n");
3642738Sdfr		}
3652738Sdfr	} else
3662738Sdfr		if (display & (MSGINFO | MSGTOTAL)) {
3672738Sdfr			fprintf(stderr,
3682738Sdfr			    "SVID messages facility not configured in the system\n");
3692738Sdfr		}
37077551Sdd
37177551Sdd	kget(X_SHMINFO, &shminfo, sizeof(shminfo));
37277551Sdd	if ((display & (SHMINFO | SHMTOTAL))) {
3732738Sdfr		if (display & SHMTOTAL) {
3742738Sdfr			printf("shminfo:\n");
3752738Sdfr			printf("\tshmmax: %7d\t(max shared memory segment size)\n",
3762738Sdfr			    shminfo.shmmax);
3772738Sdfr			printf("\tshmmin: %7d\t(min shared memory segment size)\n",
3782738Sdfr			    shminfo.shmmin);
3792738Sdfr			printf("\tshmmni: %7d\t(max number of shared memory identifiers)\n",
3802738Sdfr			    shminfo.shmmni);
3812738Sdfr			printf("\tshmseg: %7d\t(max shared memory segments per process)\n",
3822738Sdfr			    shminfo.shmseg);
3832738Sdfr			printf("\tshmall: %7d\t(max amount of shared memory in pages)\n\n",
3842738Sdfr			    shminfo.shmall);
3852738Sdfr		}
3862738Sdfr		if (display & SHMINFO) {
3872738Sdfr			struct shmid_ds *xshmids;
38877551Sdd			size_t xshmids_len;
3892731Sdfr
39077551Sdd			xshmids_len = sizeof(struct shmid_ds) * shminfo.shmmni;
39177551Sdd			xshmids = malloc(xshmids_len);
39277551Sdd			kget(X_SHMSEGS, xshmids, xshmids_len);
3932731Sdfr
3942738Sdfr			printf("Shared Memory:\n");
3952738Sdfr			printf("T     ID     KEY        MODE       OWNER    GROUP");
3962738Sdfr			if (option & CREATOR)
3972738Sdfr				printf("  CREATOR   CGROUP");
3982738Sdfr			if (option & OUTSTANDING)
3992738Sdfr				printf(" NATTCH");
4002738Sdfr			if (option & BIGGEST)
4012738Sdfr				printf("  SEGSZ");
4022738Sdfr			if (option & PID)
4032738Sdfr				printf("  CPID  LPID");
4042738Sdfr			if (option & TIME)
4052738Sdfr				printf("   ATIME    DTIME    CTIME");
4062738Sdfr			printf("\n");
4072738Sdfr			for (i = 0; i < shminfo.shmmni; i += 1) {
4082738Sdfr				if (xshmids[i].shm_perm.mode & 0x0800) {
4092738Sdfr					char    atime_buf[100], dtime_buf[100],
4102738Sdfr					        ctime_buf[100];
4112738Sdfr					struct shmid_ds *shmptr = &xshmids[i];
4122731Sdfr
4132738Sdfr					cvt_time(shmptr->shm_atime, atime_buf);
4142738Sdfr					cvt_time(shmptr->shm_dtime, dtime_buf);
4152738Sdfr					cvt_time(shmptr->shm_ctime, ctime_buf);
4162731Sdfr
4172738Sdfr					printf("m %6d %10d %s %8s %8s",
4182738Sdfr					    IXSEQ_TO_IPCID(i, shmptr->shm_perm),
4192738Sdfr					    shmptr->shm_perm.key,
4202738Sdfr					    fmt_perm(shmptr->shm_perm.mode),
4212738Sdfr					    user_from_uid(shmptr->shm_perm.uid, 0),
4222738Sdfr					    group_from_gid(shmptr->shm_perm.gid, 0));
4232731Sdfr
4242738Sdfr					if (option & CREATOR)
4252738Sdfr						printf(" %8s %8s",
4262738Sdfr						    user_from_uid(shmptr->shm_perm.cuid, 0),
4272738Sdfr						    group_from_gid(shmptr->shm_perm.cgid, 0));
4282731Sdfr
4292738Sdfr					if (option & OUTSTANDING)
4302738Sdfr						printf(" %6d",
4312738Sdfr						    shmptr->shm_nattch);
4322731Sdfr
4332738Sdfr					if (option & BIGGEST)
4342738Sdfr						printf(" %6d",
4352738Sdfr						    shmptr->shm_segsz);
4362731Sdfr
4372738Sdfr					if (option & PID)
4382738Sdfr						printf(" %6d %6d",
4392738Sdfr						    shmptr->shm_cpid,
4402738Sdfr						    shmptr->shm_lpid);
4412731Sdfr
4422738Sdfr					if (option & TIME)
4432738Sdfr						printf("%s %s %s",
4442738Sdfr						    atime_buf,
4452738Sdfr						    dtime_buf,
4462738Sdfr						    ctime_buf);
4472731Sdfr
4482738Sdfr					printf("\n");
4492738Sdfr				}
4502738Sdfr			}
4512738Sdfr			printf("\n");
4522738Sdfr		}
4532738Sdfr	} else
4542738Sdfr		if (display & (SHMINFO | SHMTOTAL)) {
4552738Sdfr			fprintf(stderr,
4562738Sdfr			    "SVID shared memory facility not configured in the system\n");
4572738Sdfr		}
45877551Sdd
45977551Sdd	kget(X_SEMINFO, &seminfo, sizeof(seminfo));
46077551Sdd	if ((display & (SEMINFO | SEMTOTAL))) {
4612738Sdfr		struct semid_ds *xsema;
46277551Sdd		size_t xsema_len;
4632731Sdfr
4642738Sdfr		if (display & SEMTOTAL) {
4652738Sdfr			printf("seminfo:\n");
4662738Sdfr			printf("\tsemmap: %6d\t(# of entries in semaphore map)\n",
4672738Sdfr			    seminfo.semmap);
4682738Sdfr			printf("\tsemmni: %6d\t(# of semaphore identifiers)\n",
4692738Sdfr			    seminfo.semmni);
4702738Sdfr			printf("\tsemmns: %6d\t(# of semaphores in system)\n",
4712738Sdfr			    seminfo.semmns);
4722738Sdfr			printf("\tsemmnu: %6d\t(# of undo structures in system)\n",
4732738Sdfr			    seminfo.semmnu);
4742738Sdfr			printf("\tsemmsl: %6d\t(max # of semaphores per id)\n",
4752738Sdfr			    seminfo.semmsl);
4762738Sdfr			printf("\tsemopm: %6d\t(max # of operations per semop call)\n",
4772738Sdfr			    seminfo.semopm);
4782738Sdfr			printf("\tsemume: %6d\t(max # of undo entries per process)\n",
4792738Sdfr			    seminfo.semume);
4802738Sdfr			printf("\tsemusz: %6d\t(size in bytes of undo structure)\n",
4812738Sdfr			    seminfo.semusz);
4822738Sdfr			printf("\tsemvmx: %6d\t(semaphore maximum value)\n",
4832738Sdfr			    seminfo.semvmx);
4842738Sdfr			printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
4852738Sdfr			    seminfo.semaem);
4862731Sdfr		}
4872738Sdfr		if (display & SEMINFO) {
48877551Sdd			xsema_len = sizeof(struct semid_ds) * seminfo.semmni;
48977551Sdd			xsema = malloc(xsema_len);
49077551Sdd			kget(X_SEMA, xsema, xsema_len);
4912731Sdfr
4922738Sdfr			printf("Semaphores:\n");
4932738Sdfr			printf("T     ID     KEY        MODE       OWNER    GROUP");
4942738Sdfr			if (option & CREATOR)
4952738Sdfr				printf("  CREATOR   CGROUP");
4962738Sdfr			if (option & BIGGEST)
4972738Sdfr				printf(" NSEMS");
4982738Sdfr			if (option & TIME)
4992738Sdfr				printf("   OTIME    CTIME");
5002738Sdfr			printf("\n");
5012738Sdfr			for (i = 0; i < seminfo.semmni; i += 1) {
5022738Sdfr				if ((xsema[i].sem_perm.mode & SEM_ALLOC) != 0) {
5032738Sdfr					char    ctime_buf[100], otime_buf[100];
5042738Sdfr					struct semid_ds *semaptr = &xsema[i];
5052731Sdfr
5062738Sdfr					cvt_time(semaptr->sem_otime, otime_buf);
5072738Sdfr					cvt_time(semaptr->sem_ctime, ctime_buf);
5082731Sdfr
5092738Sdfr					printf("s %6d %10d %s %8s %8s",
5102738Sdfr					    IXSEQ_TO_IPCID(i, semaptr->sem_perm),
5112738Sdfr					    semaptr->sem_perm.key,
5122738Sdfr					    fmt_perm(semaptr->sem_perm.mode),
5132738Sdfr					    user_from_uid(semaptr->sem_perm.uid, 0),
5142738Sdfr					    group_from_gid(semaptr->sem_perm.gid, 0));
5152731Sdfr
5162738Sdfr					if (option & CREATOR)
5172738Sdfr						printf(" %8s %8s",
5182738Sdfr						    user_from_uid(semaptr->sem_perm.cuid, 0),
5192738Sdfr						    group_from_gid(semaptr->sem_perm.cgid, 0));
5202731Sdfr
5212738Sdfr					if (option & BIGGEST)
5222738Sdfr						printf(" %6d",
5232738Sdfr						    semaptr->sem_nsems);
5242731Sdfr
5252738Sdfr					if (option & TIME)
5262738Sdfr						printf("%s %s",
5272738Sdfr						    otime_buf,
5282738Sdfr						    ctime_buf);
5292731Sdfr
5302738Sdfr					printf("\n");
5312738Sdfr				}
5322738Sdfr			}
5332731Sdfr
5342738Sdfr			printf("\n");
5352738Sdfr		}
5362738Sdfr	} else
5372738Sdfr		if (display & (SEMINFO | SEMTOTAL)) {
5382738Sdfr			fprintf(stderr, "SVID semaphores facility not configured in the system\n");
5392738Sdfr		}
54077551Sdd	if (!use_sysctl)
54177551Sdd		kvm_close(kd);
5422731Sdfr
5432738Sdfr	exit(0);
5442738Sdfr}
5452731Sdfr
5462738Sdfrvoid
54777551Sddsysctlgatherstruct(addr, size, vecarr)
54877551Sdd	void *addr;
54977551Sdd	size_t size;
55077551Sdd	struct scgs_vector *vecarr;
55177551Sdd{
55277551Sdd	struct scgs_vector *xp;
55377551Sdd	size_t tsiz;
55477551Sdd	int rv;
55577551Sdd
55677551Sdd	for (xp = vecarr; xp->sysctl != NULL; xp++) {
55777551Sdd		assert(xp->offset <= size);
55877551Sdd		tsiz = xp->size;
55977551Sdd		rv = sysctlbyname(xp->sysctl, (char *)addr + xp->offset,
56077551Sdd		    &tsiz, NULL, 0);
56177551Sdd		if (rv == -1)
56277551Sdd			errx(1, "sysctlbyname: %s", xp->sysctl);
56377551Sdd		if (tsiz != xp->size)
56477551Sdd			errx(1, "%s size mismatch (expected %d, got %d)",
56577551Sdd			    xp->sysctl, xp->size, tsiz);
56677551Sdd	}
56777551Sdd}
56877551Sdd
56977551Sddvoid
57077551Sddkget(idx, addr, size)
57177551Sdd	int idx;
57277551Sdd	void *addr;
57377551Sdd	size_t size;
57477551Sdd{
57577551Sdd	char *symn;			/* symbol name */
57677551Sdd	size_t tsiz;
57777551Sdd	int rv;
57877551Sdd	unsigned long kaddr;
57977551Sdd	const char *sym2sysctl[] = {	/* symbol to sysctl name table */
58077551Sdd		"kern.ipc.sema",
58177551Sdd		"kern.ipc.seminfo",
58277551Sdd		"kern.ipc.msginfo",
58377551Sdd		"kern.ipc.msqids",
58477551Sdd		"kern.ipc.shminfo",
58577551Sdd		"kern.ipc.shmsegs" };
58677551Sdd
58777551Sdd	assert((unsigned)idx <= sizeof(sym2sysctl) / sizeof(*sym2sysctl));
58877551Sdd	if (!use_sysctl) {
58977551Sdd		symn = symbols[idx].n_name;
59077551Sdd		if (*symn == '_')
59177551Sdd			symn++;
59277551Sdd		if (symbols[idx].n_type == 0 || symbols[idx].n_value == 0)
59377551Sdd			errx(1, "symbol %s undefined", symn);
59477551Sdd		/*
59577551Sdd		 * For some symbols, the value we retreieve is
59677551Sdd		 * actually a pointer; since we want the actual value,
59777551Sdd		 * we have to manually dereference it.
59877551Sdd		 */
59977551Sdd		switch (idx) {
60077551Sdd		case X_MSQIDS:
60177551Sdd			tsiz = sizeof(msqids);
60277551Sdd			rv = kvm_read(kd, symbols[idx].n_value,
60377551Sdd			    &msqids, tsiz);
60477551Sdd			kaddr = (u_long)msqids;
60577551Sdd			break;
60677551Sdd		case X_SHMSEGS:
60777551Sdd			tsiz = sizeof(shmsegs);
60877551Sdd			rv = kvm_read(kd, symbols[idx].n_value,
60977551Sdd			    &shmsegs, tsiz);
61077551Sdd			kaddr = (u_long)shmsegs;
61177551Sdd			break;
61277551Sdd		case X_SEMA:
61377551Sdd			tsiz = sizeof(sema);
61477551Sdd			rv = kvm_read(kd, symbols[idx].n_value,
61577551Sdd			    &sema, tsiz);
61677551Sdd			kaddr = (u_long)sema;
61777551Sdd			break;
61877551Sdd		default:
61977551Sdd			rv = tsiz = 0;
62077551Sdd			kaddr = symbols[idx].n_value;
62177551Sdd			break;
62277551Sdd		}
62377551Sdd		if ((unsigned)rv != tsiz)
62477551Sdd			errx(1, "%s: %s", symn, kvm_geterr(kd));
62577551Sdd		if ((unsigned)kvm_read(kd, kaddr, addr, size) != size)
62677551Sdd			errx(1, "%s: %s", symn, kvm_geterr(kd));
62777551Sdd	} else {
62877551Sdd		switch (idx) {
62977551Sdd		case X_SHMINFO:
63077551Sdd			sysctlgatherstruct(addr, size, shminfo_scgsv);
63177551Sdd			break;
63277551Sdd		case X_SEMINFO:
63377551Sdd			sysctlgatherstruct(addr, size, seminfo_scgsv);
63477551Sdd			break;
63577551Sdd		case X_MSGINFO:
63677551Sdd			sysctlgatherstruct(addr, size, msginfo_scgsv);
63777551Sdd			break;
63877551Sdd		default:
63977551Sdd			tsiz = size;
64077551Sdd			rv = sysctlbyname(sym2sysctl[idx], addr, &tsiz,
64177551Sdd			    NULL, 0);
64277551Sdd			if (rv == -1)
64377551Sdd				err(1, "sysctlbyname: %s", sym2sysctl[idx]);
64477551Sdd			if (tsiz != size)
64577551Sdd				errx(1, "%s size mismatch "
64677551Sdd				    "(expected %d, got %d)",
64777551Sdd				    sym2sysctl[idx], size, tsiz);
64877551Sdd			break;
64977551Sdd		}
65077551Sdd	}
65177551Sdd}
65277551Sdd
65377551Sddvoid
6542738Sdfrusage()
6552738Sdfr{
6562731Sdfr
6572738Sdfr	fprintf(stderr,
65877551Sdd	    "usage: ipcs [-abcmopqsty] [-C corefile] [-N namelist]\n");
6592738Sdfr	exit(1);
6602731Sdfr}
661