Convert to use the sysctl interface to obtain the data when operating

on a running system.  Using kvm is still supported, primarily for
postmortem analysis.

Reviewed by:	tmm
This commit is contained in:
Dima Dorfman 2001-05-31 22:30:39 +00:00
parent 7d1b125b93
commit b15abefff0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=77551
2 changed files with 239 additions and 51 deletions

View File

@ -37,7 +37,7 @@
.Nd report System V interprocess communication facilities status
.Sh SYNOPSIS
.Nm
.Op Fl abcmopqstMQST
.Op Fl abcmopqstMQSTy
.Op Fl C Ar system
.Op Fl N Ar core
.Sh DESCRIPTION
@ -101,12 +101,16 @@ or the last operation on a semaphore.
Extract the name list from the specified system instead of the
default
.Dq Pa /kernel .
Implies
.Fl y .
.It Fl M
Display system information about shared memory.
.It Fl N Ar core
Extract values associated with the name list from the specified
core instead of the default
.Dq Pa /dev/kmem .
Implies
.Fl y .
.It Fl Q
Display system information about messages queues.
.It Fl S
@ -114,6 +118,19 @@ Display system information about semaphores.
.It Fl T
Display system information about shared memory, message queues
and semaphores.
.It Fl y
Use the
.Xr kvm 3
interface instead of the
.Xr sysctl 3
interface to extract the required information.
If
.Nm
is to operate on the running system,
using
.Xr kvm 3
will require read privileges to
.Pa /dev/kmem .
.El
.Pp
If none of the

View File

@ -30,11 +30,14 @@ static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <assert.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <nlist.h>
#include <limits.h>
#include <paths.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -43,12 +46,21 @@ static const char rcsid[] =
#include <sys/param.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#define _KERNEL
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
/* SysCtlGatherStruct structure. */
struct scgs_vector {
const char *sysctl;
off_t offset;
size_t size;
};
int use_sysctl = 1;
struct semid_ds *sema;
struct seminfo seminfo;
struct msginfo msginfo;
@ -56,26 +68,66 @@ struct msqid_ds *msqids;
struct shminfo shminfo;
struct shmid_ds *shmsegs;
void sysctlgatherstruct __P((void *addr, size_t size,
struct scgs_vector *vec));
void kget __P((int idx, void *addr, size_t size));
void usage __P((void));
static struct nlist symbols[] = {
{"_sema"},
{"sema"},
#define X_SEMA 0
{"_seminfo"},
{"seminfo"},
#define X_SEMINFO 1
{"_semu"},
#define X_SEMU 2
{"_msginfo"},
#define X_MSGINFO 3
{"_msqids"},
#define X_MSQIDS 4
{"_shminfo"},
#define X_SHMINFO 5
{"_shmsegs"},
#define X_SHMSEGS 6
{"msginfo"},
#define X_MSGINFO 2
{"msqids"},
#define X_MSQIDS 3
{"shminfo"},
#define X_SHMINFO 4
{"shmsegs"},
#define X_SHMSEGS 5
{NULL}
};
#define SHMINFO_XVEC \
X(shmmax, sizeof(int)) \
X(shmmin, sizeof(int)) \
X(shmmni, sizeof(int)) \
X(shmseg, sizeof(int)) \
X(shmall, sizeof(int))
#define SEMINFO_XVEC \
X(semmap, sizeof(int)) \
X(semmni, sizeof(int)) \
X(semmns, sizeof(int)) \
X(semmnu, sizeof(int)) \
X(semmsl, sizeof(int)) \
X(semopm, sizeof(int)) \
X(semume, sizeof(int)) \
X(semusz, sizeof(int)) \
X(semvmx, sizeof(int)) \
X(semaem, sizeof(int))
#define MSGINFO_XVEC \
X(msgmax, sizeof(int)) \
X(msgmni, sizeof(int)) \
X(msgmnb, sizeof(int)) \
X(msgtql, sizeof(int)) \
X(msgssz, sizeof(int)) \
X(msgseg, sizeof(int))
#define X(a, b) { "kern.ipc." #a, offsetof(TYPEC, a), (b) },
#define TYPEC struct shminfo
struct scgs_vector shminfo_scgsv[] = { SHMINFO_XVEC { NULL } };
#undef TYPEC
#define TYPEC struct seminfo
struct scgs_vector seminfo_scgsv[] = { SEMINFO_XVEC { NULL } };
#undef TYPEC
#define TYPEC struct msginfo
struct scgs_vector msginfo_scgsv[] = { MSGINFO_XVEC { NULL } };
#undef TYPEC
#undef X
static kvm_t *kd;
char *
@ -135,9 +187,10 @@ main(argc, argv)
int display = SHMINFO | MSGINFO | SEMINFO;
int option = 0;
char *core = NULL, *namelist = NULL;
char kvmoferr[_POSIX2_LINE_MAX]; /* Error buf for kvm_openfiles. */
int i;
while ((i = getopt(argc, argv, "MmQqSsabC:cN:optT")) != -1)
while ((i = getopt(argc, argv, "MmQqSsabC:cN:optTy")) != -1)
switch (i) {
case 'M':
display = SHMTOTAL;
@ -184,39 +237,44 @@ main(argc, argv)
case 't':
option |= TIME;
break;
case 'y':
use_sysctl = 0;
break;
default:
usage();
}
/*
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
* If paths to the exec file or core file were specified, we
* aren't operating on the running kernel, so we can't use
* sysctl.
*/
if (namelist != NULL || core != NULL)
setgid(getgid());
use_sysctl = 0;
if ((kd = kvm_open(namelist, core, NULL, O_RDONLY, "ipcs")) == NULL)
exit(1);
switch (kvm_nlist(kd, symbols)) {
case 0:
break;
case -1:
errx(1, "unable to read kernel symbol table");
default:
if (!use_sysctl) {
kd = kvm_openfiles(namelist, core, NULL, O_RDONLY, kvmoferr);
if (kd == NULL)
errx(1, "kvm_openfiles: %s", kvmoferr);
switch (kvm_nlist(kd, symbols)) {
case 0:
break;
case -1:
errx(1, "unable to read kernel symbol table");
default:
#ifdef notdef /* they'll be told more civilly later */
warnx("nlist failed");
for (i = 0; symbols[i].n_name != NULL; i++)
if (symbols[i].n_value == 0)
warnx("symbol %s not found",
symbols[i].n_name);
break;
warnx("nlist failed");
for (i = 0; symbols[i].n_name != NULL; i++)
if (symbols[i].n_value == 0)
warnx("symbol %s not found",
symbols[i].n_name);
break;
#endif
}
}
if ((display & (MSGINFO | MSGTOTAL)) &&
kvm_read(kd, symbols[X_MSGINFO].n_value, &msginfo, sizeof(msginfo))== sizeof(msginfo)) {
kget(X_MSGINFO, &msginfo, sizeof(msginfo));
if ((display & (MSGINFO | MSGTOTAL))) {
if (display & MSGTOTAL) {
printf("msginfo:\n");
printf("\tmsgmax: %6d\t(max characters in a message)\n",
@ -234,10 +292,12 @@ main(argc, argv)
}
if (display & MSGINFO) {
struct msqid_ds *xmsqids;
size_t xmsqids_len;
kvm_read(kd, symbols[X_MSQIDS].n_value, &msqids, sizeof(msqids));
xmsqids = malloc(sizeof(struct msqid_ds) * msginfo.msgmni);
kvm_read(kd, (u_long) msqids, xmsqids, sizeof(struct msqid_ds) * msginfo.msgmni);
xmsqids_len = sizeof(struct msqid_ds) * msginfo.msgmni;
xmsqids = malloc(xmsqids_len);
kget(X_MSQIDS, xmsqids, xmsqids_len);
printf("Message Queues:\n");
printf("T ID KEY MODE OWNER GROUP");
@ -304,8 +364,9 @@ main(argc, argv)
fprintf(stderr,
"SVID messages facility not configured in the system\n");
}
if ((display & (SHMINFO | SHMTOTAL)) &&
kvm_read(kd, symbols[X_SHMINFO].n_value, &shminfo, sizeof(shminfo))) {
kget(X_SHMINFO, &shminfo, sizeof(shminfo));
if ((display & (SHMINFO | SHMTOTAL))) {
if (display & SHMTOTAL) {
printf("shminfo:\n");
printf("\tshmmax: %7d\t(max shared memory segment size)\n",
@ -321,11 +382,11 @@ main(argc, argv)
}
if (display & SHMINFO) {
struct shmid_ds *xshmids;
size_t xshmids_len;
kvm_read(kd, symbols[X_SHMSEGS].n_value, &shmsegs, sizeof(shmsegs));
xshmids = malloc(sizeof(struct shmid_ds) * shminfo.shmmni);
kvm_read(kd, (u_long) shmsegs, xshmids, sizeof(struct shmid_ds) *
shminfo.shmmni);
xshmids_len = sizeof(struct shmid_ds) * shminfo.shmmni;
xshmids = malloc(xshmids_len);
kget(X_SHMSEGS, xshmids, xshmids_len);
printf("Shared Memory:\n");
printf("T ID KEY MODE OWNER GROUP");
@ -391,9 +452,11 @@ main(argc, argv)
fprintf(stderr,
"SVID shared memory facility not configured in the system\n");
}
if ((display & (SEMINFO | SEMTOTAL)) &&
kvm_read(kd, symbols[X_SEMINFO].n_value, &seminfo, sizeof(seminfo))) {
kget(X_SEMINFO, &seminfo, sizeof(seminfo));
if ((display & (SEMINFO | SEMTOTAL))) {
struct semid_ds *xsema;
size_t xsema_len;
if (display & SEMTOTAL) {
printf("seminfo:\n");
@ -419,9 +482,9 @@ main(argc, argv)
seminfo.semaem);
}
if (display & SEMINFO) {
kvm_read(kd, symbols[X_SEMA].n_value, &sema, sizeof(sema));
xsema = malloc(sizeof(struct semid_ds) * seminfo.semmni);
kvm_read(kd, (u_long) sema, xsema, sizeof(struct semid_ds) * seminfo.semmni);
xsema_len = sizeof(struct semid_ds) * seminfo.semmni;
xsema = malloc(xsema_len);
kget(X_SEMA, xsema, xsema_len);
printf("Semaphores:\n");
printf("T ID KEY MODE OWNER GROUP");
@ -471,16 +534,124 @@ main(argc, argv)
if (display & (SEMINFO | SEMTOTAL)) {
fprintf(stderr, "SVID semaphores facility not configured in the system\n");
}
kvm_close(kd);
if (!use_sysctl)
kvm_close(kd);
exit(0);
}
void
sysctlgatherstruct(addr, size, vecarr)
void *addr;
size_t size;
struct scgs_vector *vecarr;
{
struct scgs_vector *xp;
size_t tsiz;
int rv;
for (xp = vecarr; xp->sysctl != NULL; xp++) {
assert(xp->offset <= size);
tsiz = xp->size;
rv = sysctlbyname(xp->sysctl, (char *)addr + xp->offset,
&tsiz, NULL, 0);
if (rv == -1)
errx(1, "sysctlbyname: %s", xp->sysctl);
if (tsiz != xp->size)
errx(1, "%s size mismatch (expected %d, got %d)",
xp->sysctl, xp->size, tsiz);
}
}
void
kget(idx, addr, size)
int idx;
void *addr;
size_t size;
{
char *symn; /* symbol name */
size_t tsiz;
int rv;
unsigned long kaddr;
const char *sym2sysctl[] = { /* symbol to sysctl name table */
"kern.ipc.sema",
"kern.ipc.seminfo",
"kern.ipc.msginfo",
"kern.ipc.msqids",
"kern.ipc.shminfo",
"kern.ipc.shmsegs" };
assert((unsigned)idx <= sizeof(sym2sysctl) / sizeof(*sym2sysctl));
if (!use_sysctl) {
symn = symbols[idx].n_name;
if (*symn == '_')
symn++;
if (symbols[idx].n_type == 0 || symbols[idx].n_value == 0)
errx(1, "symbol %s undefined", symn);
/*
* For some symbols, the value we retreieve is
* actually a pointer; since we want the actual value,
* we have to manually dereference it.
*/
switch (idx) {
case X_MSQIDS:
tsiz = sizeof(msqids);
rv = kvm_read(kd, symbols[idx].n_value,
&msqids, tsiz);
kaddr = (u_long)msqids;
break;
case X_SHMSEGS:
tsiz = sizeof(shmsegs);
rv = kvm_read(kd, symbols[idx].n_value,
&shmsegs, tsiz);
kaddr = (u_long)shmsegs;
break;
case X_SEMA:
tsiz = sizeof(sema);
rv = kvm_read(kd, symbols[idx].n_value,
&sema, tsiz);
kaddr = (u_long)sema;
break;
default:
rv = tsiz = 0;
kaddr = symbols[idx].n_value;
break;
}
if ((unsigned)rv != tsiz)
errx(1, "%s: %s", symn, kvm_geterr(kd));
if ((unsigned)kvm_read(kd, kaddr, addr, size) != size)
errx(1, "%s: %s", symn, kvm_geterr(kd));
} else {
switch (idx) {
case X_SHMINFO:
sysctlgatherstruct(addr, size, shminfo_scgsv);
break;
case X_SEMINFO:
sysctlgatherstruct(addr, size, seminfo_scgsv);
break;
case X_MSGINFO:
sysctlgatherstruct(addr, size, msginfo_scgsv);
break;
default:
tsiz = size;
rv = sysctlbyname(sym2sysctl[idx], addr, &tsiz,
NULL, 0);
if (rv == -1)
err(1, "sysctlbyname: %s", sym2sysctl[idx]);
if (tsiz != size)
errx(1, "%s size mismatch "
"(expected %d, got %d)",
sym2sysctl[idx], size, tsiz);
break;
}
}
}
void
usage()
{
fprintf(stderr,
"usage: ipcs [-abcmopqst] [-C corefile] [-N namelist]\n");
"usage: ipcs [-abcmopqsty] [-C corefile] [-N namelist]\n");
exit(1);
}