From 5d0075dbe15c41b6bc433c4cebdb7e9c54db1d96 Mon Sep 17 00:00:00 2001 From: dd Date: Thu, 31 May 2001 22:30:39 +0000 Subject: 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 --- usr.bin/ipcs/ipcs.1 | 19 +++- usr.bin/ipcs/ipcs.c | 273 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 240 insertions(+), 52 deletions(-) (limited to 'usr.bin/ipcs') diff --git a/usr.bin/ipcs/ipcs.1 b/usr.bin/ipcs/ipcs.1 index aafbb27..71989ae 100644 --- a/usr.bin/ipcs/ipcs.1 +++ b/usr.bin/ipcs/ipcs.1 @@ -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 diff --git a/usr.bin/ipcs/ipcs.c b/usr.bin/ipcs/ipcs.c index 8fd1b47..a5b80af 100644 --- a/usr.bin/ipcs/ipcs.c +++ b/usr.bin/ipcs/ipcs.c @@ -30,11 +30,14 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#include #include #include #include #include +#include #include +#include #include #include #include @@ -43,12 +46,21 @@ static const char rcsid[] = #include #include #include +#include #define _KERNEL #include #include #include #include +/* 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()); - - 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: + use_sysctl = 0; + + 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); } -- cgit v1.1