machine.c revision 74524
190285Sobrien/*
290285Sobrien * top - a top users display for Unix
390285Sobrien *
418334Speter * SYNOPSIS:  For FreeBSD-2.x and later
518334Speter *
618334Speter * DESCRIPTION:
718334Speter * Originally written for BSD4.4 system by Christos Zoulas.
818334Speter * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
918334Speter * Order support hacked in from top-3.5beta6/machine/m_aix41.c
1018334Speter *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
1118334Speter *
1218334Speter * This is the machine-dependent module for FreeBSD 2.2
1318334Speter * Works for:
1418334Speter *	FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x
1518334Speter *
1618334Speter * LIBS: -lkvm
1718334Speter *
1818334Speter * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
1918334Speter *          Steven Wallace  <swallace@freebsd.org>
2090285Sobrien *          Wolfram Schneider <wosch@FreeBSD.org>
2118334Speter *          Thomas Moestl <tmoestl@gmx.net>
2218334Speter *
2318334Speter * $FreeBSD: head/usr.bin/top/machine.c 74524 2001-03-20 16:02:16Z tmm $
2418334Speter */
2518334Speter
2618334Speter
2718334Speter#include <sys/time.h>
2818334Speter#include <sys/types.h>
2918334Speter#include <sys/signal.h>
3018334Speter#include <sys/param.h>
3118334Speter
3218334Speter#include "os.h"
3390285Sobrien#include <stdio.h>
3490285Sobrien#include <nlist.h>
3590285Sobrien#include <math.h>
3618334Speter#include <kvm.h>
3790285Sobrien#include <pwd.h>
3852295Sobrien#include <sys/errno.h>
3952295Sobrien#include <sys/sysctl.h>
4018334Speter#include <sys/dkstat.h>
4118334Speter#include <sys/file.h>
4218334Speter#include <sys/time.h>
4318334Speter#include <sys/proc.h>
4418334Speter#include <sys/user.h>
4518334Speter#include <sys/vmmeter.h>
4618334Speter#include <sys/resource.h>
4718334Speter#include <sys/rtprio.h>
4818334Speter
4990285Sobrien/* Swap */
5018334Speter#include <stdlib.h>
5190285Sobrien#include <sys/conf.h>
5218334Speter
5318334Speter#include <unistd.h>
5418334Speter#include <osreldate.h> /* for changes in kernel structures */
5550654Sobrien
5650654Sobrien#include "top.h"
5750654Sobrien#include "machine.h"
5890285Sobrien#include "screen.h"
5990285Sobrien#include "utils.h"
6090285Sobrien
6190285Sobrienstatic void getsysctl __P((char *, void *, size_t));
6290285Sobrien
6390285Sobrien#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
6490285Sobrien
6590285Sobrienextern char* printable __P((char *));
6690285Sobrienint swapmode __P((int *retavail, int *retfree));
6790285Sobrienstatic int smpmode;
6890285Sobrienstatic int namelength;
6990285Sobrienstatic int cmdlengthdelta;
7090285Sobrien
7190285Sobrien/* Prototypes for top internals */
7290285Sobrienvoid quit __P((int));
7390285Sobrien
7490285Sobrien/* get_process_info passes back a handle.  This is what it looks like: */
7590285Sobrien
7690285Sobrienstruct handle
7790285Sobrien{
7890285Sobrien    struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
7990285Sobrien    int remaining;		/* number of pointers remaining */
8090285Sobrien};
8190285Sobrien
8290285Sobrien/* declarations for load_avg */
8390285Sobrien#include "loadavg.h"
8490285Sobrien
8590285Sobrien/* define what weighted cpu is.  */
8690285Sobrien#define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \
8790285Sobrien			 ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu))))
8890285Sobrien
8990285Sobrien/* what we consider to be process size: */
9090285Sobrien#define PROCSIZE(pp) ((pp)->ki_size / 1024)
9190285Sobrien
9290285Sobrien/* definitions for indices in the nlist array */
9390285Sobrien
9490285Sobrien/*
9590285Sobrien *  These definitions control the format of the per-process area
9650654Sobrien */
9750654Sobrien
9890285Sobrienstatic char smp_header[] =
9950654Sobrien  "  PID %-*.*s PRI NICE   SIZE    RES STATE  C   TIME   WCPU    CPU COMMAND";
10018334Speter
10118334Speter#define smp_Proc_format \
10218334Speter	"%5d %-*.*s %3d %4d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s"
10318334Speter
10418334Speterstatic char up_header[] =
10518334Speter  "  PID %-*.*s PRI NICE   SIZE    RES STATE    TIME   WCPU    CPU COMMAND";
10618334Speter
10790285Sobrien#define up_Proc_format \
10818334Speter	"%5d %-*.*s %3d %4d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s"
10918334Speter
11018334Speter
11118334Speter
11218334Speter/* process state names for the "STATE" column of the display */
11390285Sobrien/* the extra nulls in the string "run" are for adding a slash and
11490285Sobrien   the processor number when needed */
11590285Sobrien
11690285Sobrienchar *state_abbrev[] =
11790285Sobrien{
11890285Sobrien    "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "MUTEX"
11990285Sobrien};
12090285Sobrien
12190285Sobrien
12290285Sobrienstatic kvm_t *kd;
12390285Sobrien
12490285Sobrien/* values that we stash away in _init and use in later routines */
12590285Sobrien
12690285Sobrienstatic double logcpu;
12790285Sobrien
12890285Sobrien/* these are retrieved from the kernel in _init */
12990285Sobrien
13090285Sobrienstatic load_avg  ccpu;
13190285Sobrien
13290285Sobrien/* these are used in the get_ functions */
13390285Sobrien
13490285Sobrienstatic int lastpid;
13590285Sobrien
13690285Sobrien/* these are for calculating cpu state percentages */
13790285Sobrien
13890285Sobrienstatic long cp_time[CPUSTATES];
13990285Sobrienstatic long cp_old[CPUSTATES];
14090285Sobrienstatic long cp_diff[CPUSTATES];
14118334Speter
14218334Speter/* these are for detailing the process states */
14318334Speter
14418334Speterint process_states[8];
14518334Speterchar *procstatenames[] = {
14618334Speter    "", " starting, ", " running, ", " sleeping, ", " stopped, ",
14718334Speter    " zombie, ", " waiting, ", " mutex, ",
14818334Speter    NULL
14918334Speter};
15018334Speter
15118334Speter/* these are for detailing the cpu states */
15218334Speter
15318334Speterint cpu_states[CPUSTATES];
15418334Speterchar *cpustatenames[] = {
15590285Sobrien    "user", "nice", "system", "interrupt", "idle", NULL
15690285Sobrien};
15790285Sobrien
15890285Sobrien/* these are for detailing the memory statistics */
15990285Sobrien
16090285Sobrienint memory_stats[7];
16190285Sobrienchar *memorynames[] = {
16218334Speter    "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
16318334Speter    NULL
16418334Speter};
16518334Speter
16618334Speterint swap_stats[7];
16718334Speterchar *swapnames[] = {
16818334Speter/*   0           1            2           3            4       5 */
16918334Speter    "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
17018334Speter    NULL
17118334Speter};
17218334Speter
17390285Sobrien
17418334Speter/* these are for keeping track of the proc array */
17518334Speter
17690285Sobrienstatic int nproc;
17790285Sobrienstatic int onproc = -1;
17890285Sobrienstatic int pref_len;
17990285Sobrienstatic struct kinfo_proc *pbase;
18090285Sobrienstatic struct kinfo_proc **pref;
18118334Speter
18218334Speter/* these are for getting the memory statistics */
18318334Speter
18418334Speterstatic int pageshift;		/* log base 2 of the pagesize */
18550654Sobrien
18690285Sobrien/* define pagetok in terms of pageshift */
18790285Sobrien
18850654Sobrien#define pagetok(size) ((size) << pageshift)
18918334Speter
19090285Sobrien/* useful externals */
19118334Speterlong percentages();
19218334Speter
19390285Sobrien#ifdef ORDER
19418334Speter/* sorting orders. first is default */
19590285Sobrienchar *ordernames[] = {
19690285Sobrien    "cpu", "size", "res", "time", "pri", NULL
19790285Sobrien};
19890285Sobrien#endif
19990285Sobrien
20090285Sobrienint
20190285Sobrienmachine_init(statics)
20290285Sobrien
20390285Sobrienstruct statics *statics;
20490285Sobrien
20518334Speter{
20650654Sobrien    register int pagesize;
20750654Sobrien    size_t modelen;
20850654Sobrien    struct passwd *pw;
20950654Sobrien
21052295Sobrien    modelen = sizeof(smpmode);
21190285Sobrien    if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 &&
21290285Sobrien         sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) ||
21352295Sobrien	modelen != sizeof(smpmode))
21452295Sobrien	    smpmode = 0;
21552295Sobrien
21652295Sobrien    while ((pw = getpwent()) != NULL) {
21790285Sobrien	if (strlen(pw->pw_name) > namelength)
21890285Sobrien	    namelength = strlen(pw->pw_name);
21990285Sobrien    }
22090285Sobrien    if (namelength < 8)
22190285Sobrien	namelength = 8;
22290285Sobrien    if (smpmode && namelength > 13)
22390285Sobrien	namelength = 13;
22490285Sobrien    else if (namelength > 15)
22590285Sobrien	namelength = 15;
22690285Sobrien
22790285Sobrien    if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open")) == NULL)
22890285Sobrien	return -1;
22996294Sobrien
23090285Sobrien    GETSYSCTL("kern.ccpu", ccpu);
23152295Sobrien
23252295Sobrien    /* this is used in calculating WCPU -- calculate it ahead of time */
23352295Sobrien    logcpu = log(loaddouble(ccpu));
23452295Sobrien
23552295Sobrien    pbase = NULL;
23652295Sobrien    pref = NULL;
23790285Sobrien    nproc = 0;
23890285Sobrien    onproc = -1;
23990285Sobrien    /* get the page size with "getpagesize" and calculate pageshift from it */
24052295Sobrien    pagesize = getpagesize();
24190285Sobrien    pageshift = 0;
24252295Sobrien    while (pagesize > 1)
24390285Sobrien    {
24490285Sobrien	pageshift++;
24590285Sobrien	pagesize >>= 1;
24690285Sobrien    }
24790285Sobrien
24890285Sobrien    /* we only need the amount of log(2)1024 for our conversion */
24990285Sobrien    pageshift -= LOG1024;
25090285Sobrien
25190285Sobrien    /* fill in the statics information */
25290285Sobrien    statics->procstate_names = procstatenames;
25390285Sobrien    statics->cpustate_names = cpustatenames;
25490285Sobrien    statics->memory_names = memorynames;
25590285Sobrien    statics->swap_names = swapnames;
25690285Sobrien#ifdef ORDER
25790285Sobrien    statics->order_names = ordernames;
25890285Sobrien#endif
25990285Sobrien
26090285Sobrien    /* all done! */
26190285Sobrien    return(0);
26290285Sobrien}
26390285Sobrien
26490285Sobrienchar *format_header(uname_field)
26590285Sobrien
26690285Sobrienregister char *uname_field;
26790285Sobrien
26890285Sobrien{
26990285Sobrien    static char Header[128];
27052295Sobrien
27150654Sobrien    snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header,
27218334Speter	     namelength, namelength, uname_field);
27390285Sobrien
27490285Sobrien    cmdlengthdelta = strlen(Header) - 7;
27518334Speter
27690285Sobrien    return Header;
27790285Sobrien}
27890285Sobrien
27990285Sobrienstatic int swappgsin = -1;
28090285Sobrienstatic int swappgsout = -1;
28190285Sobrienextern struct timeval timeout;
28290285Sobrien
28390285Sobrienvoid
28490285Sobrienget_system_info(si)
28590285Sobrien
28690285Sobrienstruct system_info *si;
28790285Sobrien
28890285Sobrien{
28996294Sobrien    long total;
29096294Sobrien    struct loadavg sysload;
29196294Sobrien    int mib[2];
29296294Sobrien    struct timeval boottime;
29396294Sobrien    size_t bt_size;
29490285Sobrien
29590285Sobrien    /* get the cp_time array */
29690285Sobrien    GETSYSCTL("kern.cp_time", cp_time);
29790285Sobrien    GETSYSCTL("vm.loadavg", sysload);
29890285Sobrien    GETSYSCTL("kern.lastpid", lastpid);
29990285Sobrien
30096294Sobrien    /* convert load averages to doubles */
30196294Sobrien    {
30296294Sobrien	register int i;
30396294Sobrien	register double *infoloadp;
30496294Sobrien
30596294Sobrien	infoloadp = si->load_avg;
30690285Sobrien	for (i = 0; i < 3; i++)
30790285Sobrien	{
30890285Sobrien#ifdef notyet
30990285Sobrien	    *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
31090285Sobrien#endif
31190285Sobrien	    *infoloadp++ = loaddouble(sysload.ldavg[i]);
31290285Sobrien	}
31390285Sobrien    }
31490285Sobrien
31590285Sobrien    /* convert cp_time counts to percentages */
31690285Sobrien    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
31790285Sobrien
31890285Sobrien    /* sum memory & swap statistics */
31990285Sobrien    {
32090285Sobrien	static unsigned int swap_delay = 0;
32190285Sobrien	static int swapavail = 0;
32290285Sobrien	static int swapfree = 0;
32390285Sobrien	static int bufspace = 0;
32490285Sobrien	static int nspgsin, nspgsout;
32590285Sobrien
32690285Sobrien	GETSYSCTL("vfs.bufspace", bufspace);
32790285Sobrien	GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]);
32890285Sobrien	GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]);
32990285Sobrien	GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]);
33090285Sobrien	GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]);
33190285Sobrien	GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]);
33290285Sobrien	GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin);
33390285Sobrien	GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout);
33490285Sobrien	/* convert memory stats to Kbytes */
33590285Sobrien	memory_stats[0] = pagetok(memory_stats[0]);
33690285Sobrien	memory_stats[1] = pagetok(memory_stats[1]);
33790285Sobrien	memory_stats[2] = pagetok(memory_stats[2]);
33890285Sobrien	memory_stats[3] = pagetok(memory_stats[3]);
33990285Sobrien	memory_stats[4] = bufspace / 1024;
34090285Sobrien	memory_stats[5] = pagetok(memory_stats[5]);
34190285Sobrien	memory_stats[6] = -1;
34290285Sobrien
34390285Sobrien	/* first interval */
34490285Sobrien        if (swappgsin < 0) {
34590285Sobrien	    swap_stats[4] = 0;
34690285Sobrien	    swap_stats[5] = 0;
34790285Sobrien	}
34890285Sobrien
34990285Sobrien	/* compute differences between old and new swap statistic */
35090285Sobrien	else {
35190285Sobrien	    swap_stats[4] = pagetok(((nspgsin - swappgsin)));
35290285Sobrien	    swap_stats[5] = pagetok(((nspgsout - swappgsout)));
35390285Sobrien	}
35490285Sobrien
35590285Sobrien        swappgsin = nspgsin;
35690285Sobrien	swappgsout = nspgsout;
35790285Sobrien
35890285Sobrien	/* call CPU heavy swapmode() only for changes */
35996294Sobrien        if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
36090285Sobrien	    swap_stats[3] = swapmode(&swapavail, &swapfree);
36190285Sobrien	    swap_stats[0] = swapavail;
36296294Sobrien	    swap_stats[1] = swapavail - swapfree;
36390285Sobrien	    swap_stats[2] = swapfree;
36490285Sobrien	}
36590285Sobrien        swap_delay = 1;
36690285Sobrien	swap_stats[6] = -1;
36796294Sobrien    }
36890285Sobrien
36990285Sobrien    /* set arrays and strings */
37090285Sobrien    si->cpustates = cpu_states;
37190285Sobrien    si->memory = memory_stats;
37296294Sobrien    si->swap = swap_stats;
37390285Sobrien
37490285Sobrien
37590285Sobrien    if(lastpid > 0) {
37690285Sobrien	si->last_pid = lastpid;
37790285Sobrien    } else {
37890285Sobrien	si->last_pid = -1;
37990285Sobrien    }
38090285Sobrien
38190285Sobrien    /*
38290285Sobrien     * Print how long system has been up.
38390285Sobrien     * (Found by looking getting "boottime" from the kernel)
38490285Sobrien     */
38590285Sobrien    mib[0] = CTL_KERN;
38690285Sobrien    mib[1] = KERN_BOOTTIME;
38790285Sobrien    bt_size = sizeof(boottime);
38890285Sobrien    if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 &&
38990285Sobrien	boottime.tv_sec != 0) {
39090285Sobrien	si->boottime = boottime;
39190285Sobrien    } else {
39290285Sobrien	si->boottime.tv_sec = -1;
39390285Sobrien    }
39490285Sobrien}
39590285Sobrien
39650654Sobrienstatic struct handle handle;
39750654Sobrien
39850654Sobriencaddr_t get_process_info(si, sel, compare)
39950654Sobrien
40090285Sobrienstruct system_info *si;
40190285Sobrienstruct process_select *sel;
40250654Sobrienint (*compare)();
40350654Sobrien
40452295Sobrien{
40590285Sobrien    register int i;
40690285Sobrien    register int total_procs;
40790285Sobrien    register int active_procs;
40890285Sobrien    register struct kinfo_proc **prefp;
40990285Sobrien    register struct kinfo_proc *pp;
41090285Sobrien
41190285Sobrien    /* these are copied out of sel for speed */
41290285Sobrien    int show_idle;
41390285Sobrien    int show_self;
41490285Sobrien    int show_system;
41550654Sobrien    int show_uid;
41650654Sobrien    int show_command;
41790285Sobrien
41850654Sobrien
41950654Sobrien    pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
42050654Sobrien    if (nproc > onproc)
42118334Speter	pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
42218334Speter		* (onproc = nproc));
42318334Speter    if (pref == NULL || pbase == NULL) {
42418334Speter	(void) fprintf(stderr, "top: Out of memory.\n");
42518334Speter	quit(23);
42618334Speter    }
42718334Speter    /* get a pointer to the states summary array */
42818334Speter    si->procstates = process_states;
42918334Speter
43090285Sobrien    /* set up flags which define what we are going to select */
43190285Sobrien    show_idle = sel->idle;
43290285Sobrien    show_self = sel->self;
43390285Sobrien    show_system = sel->system;
43490285Sobrien    show_uid = sel->uid != -1;
43590285Sobrien    show_command = sel->command != NULL;
43690285Sobrien
43790285Sobrien    /* count up process states and get pointers to interesting procs */
43890285Sobrien    total_procs = 0;
43990285Sobrien    active_procs = 0;
44090285Sobrien    memset((char *)process_states, 0, sizeof(process_states));
44190285Sobrien    prefp = pref;
44290285Sobrien    for (pp = pbase, i = 0; i < nproc; pp++, i++)
44390285Sobrien    {
44490285Sobrien	/*
44590285Sobrien	 *  Place pointers to each valid proc structure in pref[].
44690285Sobrien	 *  Process slots that are actually in use have a non-zero
44790285Sobrien	 *  status field.  Processes with P_SYSTEM set are system
44890285Sobrien	 *  processes---these get ignored unless show_sysprocs is set.
44990285Sobrien	 */
45090285Sobrien	if (pp->ki_stat != 0 &&
45190285Sobrien	    (show_self != pp->ki_pid) &&
45290285Sobrien	    (show_system || ((pp->ki_flag & P_SYSTEM) == 0)))
45396294Sobrien	{
45490285Sobrien	    total_procs++;
45596294Sobrien	    process_states[(unsigned char) pp->ki_stat]++;
45690285Sobrien	    if ((pp->ki_stat != SZOMB) &&
45790285Sobrien		(show_idle || (pp->ki_pctcpu != 0) ||
45890285Sobrien		 (pp->ki_stat == SRUN)) &&
45918334Speter		(!show_uid || pp->ki_ruid == (uid_t)sel->uid))
46018334Speter	    {
46118334Speter		*prefp++ = pp;
46218334Speter		active_procs++;
46318334Speter	    }
46418334Speter	}
46518334Speter    }
46618334Speter
46718334Speter    /* if requested, sort the "interesting" processes */
46818334Speter    if (compare != NULL)
46918334Speter    {
47018334Speter	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
47118334Speter    }
47218334Speter
47318334Speter    /* remember active and total counts */
47418334Speter    si->p_total = total_procs;
47518334Speter    si->p_active = pref_len = active_procs;
47650654Sobrien
47790285Sobrien    /* pass back a handle */
47890285Sobrien    handle.next_proc = pref;
47950654Sobrien    handle.remaining = active_procs;
48050654Sobrien    return((caddr_t)&handle);
48150654Sobrien}
48250654Sobrien
48350654Sobrienchar fmt[128];		/* static area where result is built */
48450654Sobrien
48590285Sobrienchar *format_next_process(handle, get_userid)
48690285Sobrien
48790285Sobriencaddr_t handle;
48890285Sobrienchar *(*get_userid)();
48990285Sobrien
49090285Sobrien{
49190285Sobrien    register struct kinfo_proc *pp;
49290285Sobrien    register long cputime;
49390285Sobrien    register double pct;
49490285Sobrien    struct handle *hp;
49590285Sobrien    char status[16];
49690285Sobrien    int state;
49750654Sobrien
49818334Speter    /* find and remember the next proc structure */
49990285Sobrien    hp = (struct handle *)handle;
50090285Sobrien    pp = *(hp->next_proc++);
50190285Sobrien    hp->remaining--;
50290285Sobrien
50390285Sobrien    /* get the process's command name */
50490285Sobrien    if ((pp->ki_sflag & PS_INMEM) == 0) {
50590285Sobrien	/*
50690285Sobrien	 * Print swapped processes as <pname>
50790285Sobrien	 */
50890285Sobrien	char *comm = pp->ki_comm;
50990285Sobrien#define COMSIZ sizeof(pp->ki_comm)
51090285Sobrien	char buf[COMSIZ];
51190285Sobrien	(void) strncpy(buf, comm, COMSIZ);
51250654Sobrien	comm[0] = '<';
51390285Sobrien	(void) strncpy(&comm[1], buf, COMSIZ - 2);
51490285Sobrien	comm[COMSIZ - 2] = '\0';
51590285Sobrien	(void) strncat(comm, ">", COMSIZ - 1);
51690285Sobrien	comm[COMSIZ - 1] = '\0';
51750654Sobrien    }
51890285Sobrien
51990285Sobrien    /*
52052295Sobrien     * Convert the process's runtime from microseconds to seconds.  This
52190285Sobrien     * time includes the interrupt time although that is not wanted here.
52290285Sobrien     * ps(1) is similarly sloppy.
52352295Sobrien     */
52490285Sobrien    cputime = (pp->ki_runtime + 500000) / 1000000;
52590285Sobrien
52650654Sobrien    /* calculate the base for cpu percentages */
52790285Sobrien    pct = pctdouble(pp->ki_pctcpu);
52890285Sobrien
52950654Sobrien    /* generate "STATE" field */
53090285Sobrien    switch (state = pp->ki_stat) {
53190285Sobrien	case SRUN:
53290285Sobrien	    if (smpmode && pp->ki_oncpu != 0xff)
53390285Sobrien		sprintf(status, "CPU%d", pp->ki_oncpu);
53490285Sobrien	    else
53590285Sobrien		strcpy(status, "RUN");
53690285Sobrien	    break;
53790285Sobrien	case SMTX:
53890285Sobrien	    if (pp->ki_kiflag & KI_MTXBLOCK) {
53990285Sobrien		sprintf(status, "*%.6s", pp->ki_mtxname);
54090285Sobrien	        break;
54190285Sobrien	    }
54290285Sobrien	    /* fall through */
54390285Sobrien	case SSLEEP:
54490285Sobrien	    if (pp->ki_wmesg != NULL) {
54590285Sobrien		sprintf(status, "%.6s", pp->ki_wmesg);
54690285Sobrien		break;
54790285Sobrien	    }
54890285Sobrien	    /* fall through */
54990285Sobrien	default:
55090285Sobrien
55190285Sobrien	    if (state >= 0 &&
55290285Sobrien	        state < sizeof(state_abbrev) / sizeof(*state_abbrev))
55390285Sobrien		    sprintf(status, "%.6s", state_abbrev[(unsigned char) state]);
55490285Sobrien	    else
55590285Sobrien		    sprintf(status, "?%5d", state);
55652295Sobrien	    break;
55790285Sobrien    }
55850654Sobrien
55950654Sobrien    /* format this entry */
56050654Sobrien    sprintf(fmt,
56190285Sobrien	    smpmode ? smp_Proc_format : up_Proc_format,
56290285Sobrien	    pp->ki_pid,
56390285Sobrien	    namelength, namelength,
56490285Sobrien	    (*get_userid)(pp->ki_ruid),
56590285Sobrien	    pp->ki_pri.pri_level - PZERO,
56690285Sobrien
56790285Sobrien	    /*
56890285Sobrien	     * normal time      -> nice value -20 - +20
56990285Sobrien	     * real time 0 - 31 -> nice value -52 - -21
57090285Sobrien	     * idle time 0 - 31 -> nice value +21 - +52
57190285Sobrien	     */
57290285Sobrien	    (pp->ki_pri.pri_class ==  PRI_TIMESHARE ?
57390285Sobrien	    	pp->ki_nice - NZERO :
57490285Sobrien	    	(PRI_IS_REALTIME(pp->ki_pri.pri_class) ?
57590285Sobrien		    (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) :
57690285Sobrien		    (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))),
57790285Sobrien	    format_k2(PROCSIZE(pp)),
57890285Sobrien	    format_k2(pagetok(pp->ki_rssize)),
57990285Sobrien	    status,
58090285Sobrien	    smpmode ? pp->ki_lastcpu : 0,
58190285Sobrien	    format_time(cputime),
58290285Sobrien	    100.0 * weighted_cpu(pct, pp),
58390285Sobrien	    100.0 * pct,
58490285Sobrien	    screen_width > cmdlengthdelta ?
58590285Sobrien		screen_width - cmdlengthdelta :
58690285Sobrien		0,
58790285Sobrien	    printable(pp->ki_comm));
58890285Sobrien
58990285Sobrien    /* return the result */
59090285Sobrien    return(fmt);
59190285Sobrien}
59290285Sobrien
59390285Sobrienstatic void getsysctl (name, ptr, len)
59490285Sobrien
59590285Sobrienchar *name;
59690285Sobrienvoid *ptr;
59790285Sobriensize_t len;
59890285Sobrien
59990285Sobrien{
60090285Sobrien    size_t nlen = len;
60190285Sobrien    if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
60290285Sobrien	    fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name,
60390285Sobrien		strerror(errno));
60490285Sobrien	    quit(23);
60590285Sobrien    }
60690285Sobrien    if (nlen != len) {
60790285Sobrien	    fprintf(stderr, "top: sysctl(%s...) expected %d, got %d\n", name,
60890285Sobrien		len, nlen);
60990285Sobrien	    quit(23);
61090285Sobrien    }
61190285Sobrien}
61290285Sobrien
61390285Sobrien/* comparison routines for qsort */
61490285Sobrien
61590285Sobrien/*
61690285Sobrien *  proc_compare - comparison function for "qsort"
61790285Sobrien *	Compares the resource consumption of two processes using five
61890285Sobrien *  	distinct keys.  The keys (in descending order of importance) are:
61996294Sobrien *  	percent cpu, cpu ticks, state, resident set size, total virtual
62090285Sobrien *  	memory usage.  The process states are ordered as follows (from least
62190285Sobrien *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
62296294Sobrien *  	array declaration below maps a process state index into a number
62390285Sobrien *  	that reflects this ordering.
62490285Sobrien */
62590285Sobrien
62690285Sobrienstatic unsigned char sorted_state[] =
62790285Sobrien{
62890285Sobrien    0,	/* not used		*/
62950654Sobrien    3,	/* sleep		*/
63090285Sobrien    1,	/* ABANDONED (WAIT)	*/
63190285Sobrien    6,	/* run			*/
63290285Sobrien    5,	/* start		*/
63390285Sobrien    2,	/* zombie		*/
63490285Sobrien    4	/* stop			*/
63550654Sobrien};
63690285Sobrien
63790285Sobrien
63890285Sobrien#define ORDERKEY_PCTCPU \
63990285Sobrien  if (lresult = (long) p2->ki_pctcpu - (long) p1->ki_pctcpu, \
64090285Sobrien     (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
64190285Sobrien
64290285Sobrien#define ORDERKEY_CPTICKS \
64390285Sobrien  if ((result = p2->ki_runtime > p1->ki_runtime ? 1 : \
64450654Sobrien                p2->ki_runtime < p1->ki_runtime ? -1 : 0) == 0)
64550654Sobrien
64690285Sobrien#define ORDERKEY_STATE \
64750654Sobrien  if ((result = sorted_state[(unsigned char) p2->ki_stat] - \
64850654Sobrien                sorted_state[(unsigned char) p1->ki_stat]) == 0)
64950654Sobrien
65050654Sobrien#define ORDERKEY_PRIO \
65150654Sobrien  if ((result = p2->ki_pri.pri_level - p1->ki_pri.pri_level) == 0)
65250654Sobrien
65350654Sobrien#define ORDERKEY_RSSIZE \
65450654Sobrien  if ((result = p2->ki_rssize - p1->ki_rssize) == 0)
65550654Sobrien
65650654Sobrien#define ORDERKEY_MEM \
65750654Sobrien  if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
65850654Sobrien
65950654Sobrien/* compare_cpu - the comparison function for sorting by cpu percentage */
66050654Sobrien
66150654Sobrienint
66250654Sobrien#ifdef ORDER
66350654Sobriencompare_cpu(pp1, pp2)
66450654Sobrien#else
66550654Sobrienproc_compare(pp1, pp2)
66690285Sobrien#endif
66790285Sobrien
66890285Sobrienstruct proc **pp1;
66990285Sobrienstruct proc **pp2;
67090285Sobrien
67150654Sobrien{
67250654Sobrien    register struct kinfo_proc *p1;
67350654Sobrien    register struct kinfo_proc *p2;
67418334Speter    register int result;
67518334Speter    register pctcpu lresult;
67690285Sobrien
67790285Sobrien    /* remove one level of indirection */
67890285Sobrien    p1 = *(struct kinfo_proc **) pp1;
67990285Sobrien    p2 = *(struct kinfo_proc **) pp2;
68090285Sobrien
68190285Sobrien    ORDERKEY_PCTCPU
68290285Sobrien    ORDERKEY_CPTICKS
68390285Sobrien    ORDERKEY_STATE
68490285Sobrien    ORDERKEY_PRIO
68590285Sobrien    ORDERKEY_RSSIZE
68690285Sobrien    ORDERKEY_MEM
68790285Sobrien    ;
68890285Sobrien
68990285Sobrien    return(result);
69090285Sobrien}
69190285Sobrien
69218334Speter#ifdef ORDER
69390285Sobrien/* compare routines */
69490285Sobrienint compare_size(), compare_res(), compare_time(), compare_prio();
69590285Sobrien
69690285Sobrienint (*proc_compares[])() = {
69790285Sobrien    compare_cpu,
69890285Sobrien    compare_size,
69990285Sobrien    compare_res,
70090285Sobrien    compare_time,
70190285Sobrien    compare_prio,
70290285Sobrien    NULL
70390285Sobrien};
70490285Sobrien
70590285Sobrien/* compare_size - the comparison function for sorting by total memory usage */
70690285Sobrien
70790285Sobrienint
70890285Sobriencompare_size(pp1, pp2)
70990285Sobrien
71018334Speterstruct proc **pp1;
71118334Speterstruct proc **pp2;
71290285Sobrien
71318334Speter{
71418334Speter    register struct kinfo_proc *p1;
71518334Speter    register struct kinfo_proc *p2;
71618334Speter    register int result;
71718334Speter    register pctcpu lresult;
71818334Speter
71918334Speter    /* remove one level of indirection */
72018334Speter    p1 = *(struct kinfo_proc **) pp1;
72118334Speter    p2 = *(struct kinfo_proc **) pp2;
72218334Speter
72318334Speter    ORDERKEY_MEM
72418334Speter    ORDERKEY_RSSIZE
72518334Speter    ORDERKEY_PCTCPU
72618334Speter    ORDERKEY_CPTICKS
72718334Speter    ORDERKEY_STATE
72818334Speter    ORDERKEY_PRIO
72918334Speter    ;
73018334Speter
73118334Speter    return(result);
73218334Speter}
73318334Speter
73418334Speter/* compare_res - the comparison function for sorting by resident set size */
73518334Speter
73690285Sobrienint
73718334Spetercompare_res(pp1, pp2)
73818334Speter
73990285Sobrienstruct proc **pp1;
74090285Sobrienstruct proc **pp2;
74118334Speter
74218334Speter{
74318334Speter    register struct kinfo_proc *p1;
74490285Sobrien    register struct kinfo_proc *p2;
74518334Speter    register int result;
74618334Speter    register pctcpu lresult;
74790285Sobrien
74818334Speter    /* remove one level of indirection */
74990285Sobrien    p1 = *(struct kinfo_proc **) pp1;
75090285Sobrien    p2 = *(struct kinfo_proc **) pp2;
75118334Speter
75252295Sobrien    ORDERKEY_RSSIZE
75352295Sobrien    ORDERKEY_MEM
75490285Sobrien    ORDERKEY_PCTCPU
75552295Sobrien    ORDERKEY_CPTICKS
75690285Sobrien    ORDERKEY_STATE
75790285Sobrien    ORDERKEY_PRIO
75890285Sobrien    ;
75990285Sobrien
76090285Sobrien    return(result);
76190285Sobrien}
76218334Speter
76390285Sobrien/* compare_time - the comparison function for sorting by total cpu time */
76490285Sobrien
76518334Speterint
76690285Sobriencompare_time(pp1, pp2)
76718334Speter
76890285Sobrienstruct proc **pp1;
76990285Sobrienstruct proc **pp2;
77018334Speter
77118334Speter{
77218334Speter    register struct kinfo_proc *p1;
77390285Sobrien    register struct kinfo_proc *p2;
77490285Sobrien    register int result;
77590285Sobrien    register pctcpu lresult;
77690285Sobrien
77718334Speter    /* remove one level of indirection */
77890285Sobrien    p1 = *(struct kinfo_proc **) pp1;
77990285Sobrien    p2 = *(struct kinfo_proc **) pp2;
78090285Sobrien
78190285Sobrien    ORDERKEY_CPTICKS
78290285Sobrien    ORDERKEY_PCTCPU
78390285Sobrien    ORDERKEY_STATE
78490285Sobrien    ORDERKEY_PRIO
78590285Sobrien    ORDERKEY_RSSIZE
78690285Sobrien    ORDERKEY_MEM
78790285Sobrien    ;
78890285Sobrien
78990285Sobrien      return(result);
79090285Sobrien  }
79190285Sobrien
79290285Sobrien/* compare_prio - the comparison function for sorting by cpu percentage */
79390285Sobrien
79490285Sobrienint
79590285Sobriencompare_prio(pp1, pp2)
79650654Sobrien
79790285Sobrienstruct proc **pp1;
79850654Sobrienstruct proc **pp2;
79950654Sobrien
80050654Sobrien{
80150654Sobrien    register struct kinfo_proc *p1;
80250654Sobrien    register struct kinfo_proc *p2;
80350654Sobrien    register int result;
80450654Sobrien    register pctcpu lresult;
80550654Sobrien
80650654Sobrien    /* remove one level of indirection */
80750654Sobrien    p1 = *(struct kinfo_proc **) pp1;
80890285Sobrien    p2 = *(struct kinfo_proc **) pp2;
80950654Sobrien
81050654Sobrien    ORDERKEY_PRIO
81150654Sobrien    ORDERKEY_CPTICKS
81250654Sobrien    ORDERKEY_PCTCPU
81350654Sobrien    ORDERKEY_STATE
81450654Sobrien    ORDERKEY_RSSIZE
81550654Sobrien    ORDERKEY_MEM
81650654Sobrien    ;
81750654Sobrien
81850654Sobrien    return(result);
81950654Sobrien}
82050654Sobrien#endif
82150654Sobrien
82290285Sobrien/*
82350654Sobrien * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
82452295Sobrien *		the process does not exist.
82552295Sobrien *		It is EXTREMLY IMPORTANT that this function work correctly.
82652295Sobrien *		If top runs setuid root (as in SVR4), then this function
82752295Sobrien *		is the only thing that stands in the way of a serious
82852295Sobrien *		security problem.  It validates requests for the "kill"
82952295Sobrien *		and "renice" commands.
83052295Sobrien */
83152295Sobrien
83252295Sobrienint proc_owner(pid)
83352295Sobrien
83490285Sobrienint pid;
83552295Sobrien
83690285Sobrien{
83790285Sobrien    register int cnt;
83890285Sobrien    register struct kinfo_proc **prefp;
83990285Sobrien    register struct kinfo_proc *pp;
84090285Sobrien
84190285Sobrien    prefp = pref;
84290285Sobrien    cnt = pref_len;
84318334Speter    while (--cnt >= 0)
84418334Speter    {
84518334Speter	pp = *prefp++;
84618334Speter	if (pp->ki_pid == (pid_t)pid)
84718334Speter	{
84818334Speter	    return((int)pp->ki_ruid);
84918334Speter	}
85018334Speter    }
85118334Speter    return(-1);
85218334Speter}
85318334Speter
85418334Speterint
85590285Sobrienswapmode(retavail, retfree)
85618334Speter	int *retavail;
85718334Speter	int *retfree;
85890285Sobrien{
85990285Sobrien	int n;
86090285Sobrien	int pagesize = getpagesize();
86118334Speter	struct kvm_swap swapary[1];
86218334Speter
86318334Speter	*retavail = 0;
86418334Speter	*retfree = 0;
86518334Speter
86618334Speter#define CONVERT(v)	((quad_t)(v) * pagesize / 1024)
86718334Speter
86818334Speter	n = kvm_getswapinfo(kd, swapary, 1, 0);
86918334Speter	if (n < 0 || swapary[0].ksw_total == 0)
87018334Speter		return(0);
87118334Speter
87218334Speter	*retavail = CONVERT(swapary[0].ksw_total);
87318334Speter	*retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
87418334Speter
87518334Speter	n = (int)((double)swapary[0].ksw_used * 100.0 /
87690285Sobrien	    (double)swapary[0].ksw_total);
87718334Speter	return(n);
87890285Sobrien}
87918334Speter
88090285Sobrien