Adapt the top utility to not use kmem_read to retrieve variables now

available via sysctl().  As a result, top should now be able to run without
setgid kmem.

Submitted by:	Thomas Moestl <tmoestl@gmx.net>
Reviewed by:	freebsd-audit
This commit is contained in:
Robert Watson 2001-02-23 18:52:37 +00:00
parent ae3a37ad44
commit 39d513ecdd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=72951

View File

@ -18,6 +18,7 @@
* AUTHOR: Christos Zoulas <christos@ee.cornell.edu>
* Steven Wallace <swallace@freebsd.org>
* Wolfram Schneider <wosch@FreeBSD.org>
* Thomas Moestl <tmoestl@gmx.net>
*
* $FreeBSD$
*/
@ -49,20 +50,26 @@
#include <stdlib.h>
#include <sys/conf.h>
#include <unistd.h>
#include <osreldate.h> /* for changes in kernel structures */
#include "top.h"
#include "machine.h"
#include "screen.h"
#include "utils.h"
static void getsysctl __P((char *, void *, int));
#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
static int check_nlist __P((struct nlist *));
static int getkval __P((unsigned long, int *, int, char *));
extern char* printable __P((char *));
int swapmode __P((int *retavail, int *retfree));
static int smpmode;
static int namelength;
static int cmdlengthdelta;
/* Prototypes for top internals */
void quit __P((int));
/* get_process_info passes back a handle. This is what it looks like: */
@ -84,25 +91,6 @@ struct handle
/* definitions for indices in the nlist array */
static struct nlist nlst[] = {
#define X_CCPU 0
{ "_ccpu" },
#define X_CP_TIME 1
{ "_cp_time" },
#define X_AVENRUN 2
{ "_averunnable" },
#define X_BUFSPACE 3
{ "_bufspace" }, /* K in buffer cache */
#define X_CNT 4
{ "_cnt" }, /* struct vmmeter cnt */
/* Last pid */
#define X_LASTPID 5
{ "_nextpid" },
{ 0 }
};
/*
* These definitions control the format of the per-process area
*/
@ -141,15 +129,9 @@ static double logcpu;
static load_avg ccpu;
/* these are offsets obtained via nlist and used in the get_ functions */
/* these are used in the get_ functions */
static unsigned long cp_time_offset;
static unsigned long avenrun_offset;
static unsigned long lastpid_offset;
static long lastpid;
static unsigned long cnt_offset;
static unsigned long bufspace_offset;
static long cnt;
static int lastpid;
/* these are for calculating cpu state percentages */
@ -221,7 +203,6 @@ machine_init(statics)
struct statics *statics;
{
register int i = 0;
register int pagesize;
int modelen;
struct passwd *pw;
@ -241,33 +222,10 @@ struct statics *statics;
if (namelength > 15)
namelength = 15;
if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open")) == NULL)
return -1;
/* get the list of symbols we want to access in the kernel */
(void) kvm_nlist(kd, nlst);
if (nlst[0].n_type == 0)
{
fprintf(stderr, "top: nlist failed\n");
return(-1);
}
/* make sure they were all found */
if (i > 0 && check_nlist(nlst) > 0)
{
return(-1);
}
(void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu),
nlst[X_CCPU].n_name);
/* stash away certain offsets for later use */
cp_time_offset = nlst[X_CP_TIME].n_value;
avenrun_offset = nlst[X_AVENRUN].n_value;
lastpid_offset = nlst[X_LASTPID].n_value;
cnt_offset = nlst[X_CNT].n_value;
bufspace_offset = nlst[X_BUFSPACE].n_value;
GETSYSCTL("kern.ccpu", ccpu);
/* this is used in calculating WCPU -- calculate it ahead of time */
logcpu = log(loaddouble(ccpu));
@ -306,7 +264,6 @@ char *format_header(uname_field)
register char *uname_field;
{
register char *ptr;
static char Header[128];
snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header,
@ -328,19 +285,15 @@ struct system_info *si;
{
long total;
load_avg avenrun[3];
load_avg avenrun[4]; /* 3 values and FSCALE. */
int mib[2];
struct timeval boottime;
size_t bt_size;
/* get the cp_time array */
(void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
nlst[X_CP_TIME].n_name);
(void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
nlst[X_AVENRUN].n_name);
(void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
"!");
GETSYSCTL("kern.cp_time", cp_time);
GETSYSCTL("vm.loadavg", avenrun);
GETSYSCTL("kern.lastpid", lastpid);
/* convert load averages to doubles */
{
@ -370,24 +323,22 @@ struct system_info *si;
/* sum memory & swap statistics */
{
struct vmmeter sum;
static unsigned int swap_delay = 0;
static int swapavail = 0;
static int swapfree = 0;
static int bufspace = 0;
static int nspgsin, nspgsout;
(void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
"_cnt");
(void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace),
"_bufspace");
GETSYSCTL("vfs.bufspace", bufspace);
GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]);
GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]);
GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]);
GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]);
GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]);
GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin);
GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout);
/* convert memory stats to Kbytes */
memory_stats[0] = pagetok(sum.v_active_count);
memory_stats[1] = pagetok(sum.v_inactive_count);
memory_stats[2] = pagetok(sum.v_wire_count);
memory_stats[3] = pagetok(sum.v_cache_count);
memory_stats[4] = bufspace / 1024;
memory_stats[5] = pagetok(sum.v_free_count);
memory_stats[6] = -1;
/* first interval */
@ -398,12 +349,12 @@ struct system_info *si;
/* compute differences between old and new swap statistic */
else {
swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin)));
swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout)));
swap_stats[4] = pagetok(((nspgsin - swappgsin)));
swap_stats[5] = pagetok(((nspgsout - swappgsout)));
}
swappgsin = sum.v_swappgsin;
swappgsout = sum.v_swappgsout;
swappgsin = nspgsin;
swappgsout = nspgsout;
/* call CPU heavy swapmode() only for changes */
if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
@ -640,77 +591,26 @@ char *(*get_userid)();
return(fmt);
}
static void getsysctl (name, ptr, len)
/*
* check_nlist(nlst) - checks the nlist to see if any symbols were not
* found. For every symbol that was not found, a one-line
* message is printed to stderr. The routine returns the
* number of symbols NOT found.
*/
static int check_nlist(nlst)
register struct nlist *nlst;
char *name;
void *ptr;
int len;
{
register int i;
/* check to see if we got ALL the symbols we requested */
/* this will write one line to stderr for every symbol not found */
i = 0;
while (nlst->n_name != NULL)
{
if (nlst->n_type == 0)
{
/* this one wasn't found */
(void) fprintf(stderr, "kernel: no symbol named `%s'\n",
nlst->n_name);
i = 1;
}
nlst++;
}
return(i);
}
/*
* getkval(offset, ptr, size, refstr) - get a value out of the kernel.
* "offset" is the byte offset into the kernel for the desired value,
* "ptr" points to a buffer into which the value is retrieved,
* "size" is the size of the buffer (and the object to retrieve),
* "refstr" is a reference string used when printing error meessages,
* if "refstr" starts with a '!', then a failure on read will not
* be fatal (this may seem like a silly way to do things, but I
* really didn't want the overhead of another argument).
*
*/
static int getkval(offset, ptr, size, refstr)
unsigned long offset;
int *ptr;
int size;
char *refstr;
{
if (kvm_read(kd, offset, (char *) ptr, size) != size)
{
if (*refstr == '!')
{
return(0);
}
else
{
fprintf(stderr, "top: kvm_read for %s: %s\n",
refstr, strerror(errno));
int nlen = len;
if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name,
strerror(errno));
quit(23);
}
if (nlen != len) {
fprintf(stderr, "top: sysctl(%s...) expected %d, got %d\n", name,
len, nlen);
quit(23);
}
}
return(1);
}
/* comparison routines for qsort */
/*
@ -952,29 +852,6 @@ int pid;
return(-1);
}
/*
* swapmode is based on a program called swapinfo written
* by Kevin Lahey <kml@rokkaku.atl.ga.us>.
*/
#define SVAR(var) __STRING(var) /* to force expansion */
#define KGET(idx, var) \
KGET1(idx, &var, sizeof(var), SVAR(var))
#define KGET1(idx, p, s, msg) \
KGET2(nlst[idx].n_value, p, s, msg)
#define KGET2(addr, p, s, msg) \
if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
return (0); \
}
#define KGETRET(addr, p, s, msg) \
if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
return (0); \
}
int
swapmode(retavail, retfree)
int *retavail;