mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-20 16:54:02 +00:00
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:
parent
7d1b125b93
commit
b15abefff0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=77551
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue