118781Sgibbs/*	$NetBSD: m_netbsd.c,v 1.15 2011/04/15 02:05:53 christos Exp $	*/
218781Sgibbs
318781Sgibbs/*
455945Sgibbs * top - a top users display for Unix
518781Sgibbs *
618781Sgibbs * SYNOPSIS:  For a NetBSD-1.5 (or later) system
718781Sgibbs *
818781Sgibbs * DESCRIPTION:
918781Sgibbs * Originally written for BSD4.4 system by Christos Zoulas.
1018781Sgibbs * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider.
1139217Sgibbs * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn.
1239217Sgibbs * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green.
1318781Sgibbs * NetBSD-1.4/UVM port by matthew green.
1418781Sgibbs * NetBSD-1.5 port by Simon Burge.
1518781Sgibbs * NetBSD-1.6/UBC port by Tomas Svensson.
1618781Sgibbs * -
1718781Sgibbs * This is the machine-dependent module for NetBSD-1.5 and later
1818781Sgibbs * works for:
1918781Sgibbs *	NetBSD-1.6ZC
2018781Sgibbs * and should work for:
2118781Sgibbs *	NetBSD-2.0	(when released)
2218781Sgibbs * -
2318781Sgibbs * top does not need to be installed setuid or setgid with this module.
2418781Sgibbs *
2518781Sgibbs * LIBS: -lkvm
2618781Sgibbs *
2718781Sgibbs * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR
2818781Sgibbs *
2918781Sgibbs * AUTHORS:	Christos Zoulas <christos@ee.cornell.edu>
3018781Sgibbs *		Steven Wallace <swallace@freebsd.org>
3150477Speter *		Wolfram Schneider <wosch@cs.tu-berlin.de>
3218781Sgibbs *		Arne Helme <arne@acm.org>
3318781Sgibbs *		Luke Mewburn <lukem@NetBSD.org>
3418781Sgibbs *		matthew green <mrg@eterna.com.au>
3518781Sgibbs *		Simon Burge <simonb@NetBSD.org>
3618781Sgibbs *		Tomas Svensson <ts@unix1.net>
3718781Sgibbs *		Andrew Doran <ad@NetBSD.org>
3818781Sgibbs *
3918781Sgibbs *
4018781Sgibbs * $Id: m_netbsd.c,v 1.16 2011/10/08 08:45:37 njoly Exp $
4118781Sgibbs */
4218781Sgibbs#include <sys/cdefs.h>
4318781Sgibbs
4418781Sgibbs#ifndef lint
4518781Sgibbs__RCSID("$NetBSD: m_netbsd.c,v 1.15 2011/04/15 02:05:53 christos Exp $");
4618781Sgibbs#endif
4745846Sgibbs
4818781Sgibbs#include <sys/param.h>
4918781Sgibbs#include <sys/sysctl.h>
5039217Sgibbs#include <sys/sched.h>
5139217Sgibbs#include <sys/swap.h>
5259082Snyan
5359082Snyan#include <uvm/uvm_extern.h>
5459082Snyan
5518781Sgibbs#include <err.h>
5639217Sgibbs#include <errno.h>
5739217Sgibbs#include <kvm.h>
5839217Sgibbs#include <math.h>
5939217Sgibbs#include <nlist.h>
6018781Sgibbs#include <stdio.h>
6139217Sgibbs#include <stdlib.h>
6239217Sgibbs#include <string.h>
6339217Sgibbs#include <unistd.h>
6439217Sgibbs
6539217Sgibbs#include "os.h"
6618781Sgibbs#include "top.h"
6718781Sgibbs#include "machine.h"
6818781Sgibbs#include "utils.h"
6918781Sgibbs#include "display.h"
7039217Sgibbs#include "loadavg.h"
7118781Sgibbs#include "username.h"
7218781Sgibbs
7339217Sgibbsstatic void percentages64(int, int *, u_int64_t *, u_int64_t *,
7439217Sgibbs    u_int64_t *);
7539217Sgibbs
7639217Sgibbs/* get_process_info passes back a handle.  This is what it looks like: */
7739217Sgibbs
7839217Sgibbsstruct handle {
7939217Sgibbs	struct process_select *sel;
8039217Sgibbs	struct kinfo_proc2 **next_proc;	/* points to next valid proc pointer */
8139217Sgibbs	int remaining;		/* number of pointers remaining */
8239217Sgibbs};
8339217Sgibbs
8439217Sgibbs/* define what weighted CPU is. */
8539217Sgibbs#define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \
8639217Sgibbs			 ((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu))))
8739217Sgibbs
8839217Sgibbs/* what we consider to be process size: */
8939217Sgibbs/* NetBSD introduced p_vm_msize with RLIMIT_AS */
9039217Sgibbs#ifdef RLIMIT_AS
9139217Sgibbs#define PROCSIZE(pp) \
9239217Sgibbs    ((pp)->p_vm_msize)
9339217Sgibbs#else
9439217Sgibbs#define PROCSIZE(pp) \
9539217Sgibbs    ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
9639217Sgibbs#endif
9739217Sgibbs
9839217Sgibbs
9939217Sgibbs/*
10039217Sgibbs * These definitions control the format of the per-process area
10139217Sgibbs */
10239217Sgibbs
10339217Sgibbsstatic char Proc_header[] =
10439217Sgibbs  "  PID X        PRI NICE   SIZE   RES STATE      TIME   WCPU    CPU COMMAND";
10539217Sgibbs/* 0123456   -- field to fill in starts at header+6 */
10639217Sgibbs#define PROC_UNAME_START 6
10739217Sgibbs#define Proc_format \
10839217Sgibbs	"%5d %-8.8s %3d %4d%7s %5s %-8.8s%7s %5.*f%% %5.*f%% %s"
10939217Sgibbs
11039217Sgibbsstatic char Thread_header[] =
11139217Sgibbs  "  PID   LID X        PRI STATE      TIME   WCPU    CPU NAME      COMMAND";
11239217Sgibbs/* 0123456   -- field to fill in starts at header+6 */
11339217Sgibbs#define THREAD_UNAME_START 12
11439217Sgibbs#define Thread_format \
11539217Sgibbs        "%5d %5d %-8.8s %3d %-8.8s%7s %5.2f%% %5.2f%% %-9.9s %s"
11639217Sgibbs
11739217Sgibbs/*
11839217Sgibbs * Process state names for the "STATE" column of the display.
11939217Sgibbs */
12039217Sgibbs
12139217Sgibbsconst char *state_abbrev[] = {
12239217Sgibbs	"", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
12339217Sgibbs};
12439217Sgibbs
12518781Sgibbsstatic kvm_t *kd;
12618781Sgibbs
12718781Sgibbsstatic char *(*userprint)(int);
12845575Seivind
12918781Sgibbs/* these are retrieved from the kernel in _init */
13018781Sgibbs
13118781Sgibbsstatic double logcpu;
13218781Sgibbsstatic int hz;
13318781Sgibbsstatic int ccpu;
13418781Sgibbs
13518781Sgibbs/* these are for calculating CPU state percentages */
13618781Sgibbs
13718781Sgibbsstatic int ncpu = 0;
13818781Sgibbsstatic u_int64_t *cp_time;
13918781Sgibbsstatic u_int64_t *cp_old;
14045575Seivindstatic u_int64_t *cp_diff;
14139217Sgibbs
14239217Sgibbs/* these are for detailing the process states */
14339217Sgibbs
14439217Sgibbsint process_states[8];
14539217Sgibbsconst char *procstatenames[] = {
14639217Sgibbs	"", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
14739217Sgibbs	" zombie, ", " dead, ", " on CPU, ",
14839217Sgibbs	NULL
14939217Sgibbs};
15039217Sgibbs
15139217Sgibbs/* these are for detailing the CPU states */
15239217Sgibbs
15339217Sgibbsint *cpu_states;
15439217Sgibbsconst char *cpustatenames[] = {
15539217Sgibbs	"user", "nice", "system", "interrupt", "idle", NULL
15639217Sgibbs};
15739217Sgibbs
15818781Sgibbs/* these are for detailing the memory statistics */
15918781Sgibbs
16039217Sgibbslong memory_stats[7];
16139217Sgibbsconst char *memorynames[] = {
16239217Sgibbs	"K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
16339217Sgibbs	"K Free, ",
16439217Sgibbs	NULL
16539217Sgibbs};
16639217Sgibbs
16739217Sgibbslong swap_stats[4];
16839217Sgibbsconst char *swapnames[] = {
16939217Sgibbs	"K Total, ", "K Used, ", "K Free, ",
17039217Sgibbs	NULL
17139217Sgibbs};
17239217Sgibbs
17339217Sgibbs
17439217Sgibbs/* these are names given to allowed sorting orders -- first is default */
17539217Sgibbsconst char *ordernames[] = {
17639217Sgibbs	"cpu",
17739217Sgibbs	"pri",
17839217Sgibbs	"res",
17939217Sgibbs	"size",
18039217Sgibbs	"state",
18139217Sgibbs	"time",
18239217Sgibbs	"pid",
18339217Sgibbs	"command",
18439217Sgibbs	"username",
18539217Sgibbs	NULL
18639217Sgibbs};
18718781Sgibbs
18818781Sgibbs/* forward definitions for comparison functions */
18939217Sgibbsstatic int compare_cpu(struct proc **, struct proc **);
19018781Sgibbsstatic int compare_prio(struct proc **, struct proc **);
19139217Sgibbsstatic int compare_res(struct proc **, struct proc **);
19218781Sgibbsstatic int compare_size(struct proc **, struct proc **);
19318781Sgibbsstatic int compare_state(struct proc **, struct proc **);
19439217Sgibbsstatic int compare_time(struct proc **, struct proc **);
19539217Sgibbsstatic int compare_pid(struct proc **, struct proc **);
19639217Sgibbsstatic int compare_command(struct proc **, struct proc **);
19739217Sgibbsstatic int compare_username(struct proc **, struct proc **);
19839217Sgibbs
19939217Sgibbsint (*proc_compares[])(struct proc **, struct proc **) = {
20039217Sgibbs	compare_cpu,
20139217Sgibbs	compare_prio,
20239217Sgibbs	compare_res,
20318781Sgibbs	compare_size,
20439217Sgibbs	compare_state,
20539217Sgibbs	compare_time,
20639217Sgibbs	compare_pid,
20718781Sgibbs	compare_command,
20818781Sgibbs	compare_username,
20939217Sgibbs	NULL
21039217Sgibbs};
21139217Sgibbs
21239217Sgibbsstatic char *format_next_lwp(caddr_t, char *(*)(int));
21339217Sgibbsstatic char *format_next_proc(caddr_t, char *(*)(int));
21418781Sgibbs
21518781Sgibbsstatic caddr_t get_proc_info(struct system_info *, struct process_select *,
21639217Sgibbs			     int (*)(struct proc **, struct proc **));
21739217Sgibbsstatic caddr_t get_lwp_info(struct system_info *, struct process_select *,
21839217Sgibbs			    int (*)(struct proc **, struct proc **));
21939217Sgibbs
22039217Sgibbs/* these are for keeping track of the proc array */
22139217Sgibbs
22239217Sgibbsstatic int nproc;
22318781Sgibbsstatic int onproc = -1;
22418781Sgibbsstatic int nlwp;
22539217Sgibbsstatic int onlwp = -1;
22639217Sgibbsstatic int pref_len;
22718781Sgibbsstatic int lref_len;
22839217Sgibbsstatic struct kinfo_proc2 *pbase;
22939217Sgibbsstatic struct kinfo_lwp *lbase;
23039217Sgibbsstatic struct kinfo_proc2 **pref;
23139217Sgibbsstatic struct kinfo_lwp **lref;
23239217Sgibbsstatic int maxswap;
23318781Sgibbsstatic void *swapp;
23439217Sgibbsstatic int procgen;
23539217Sgibbsstatic int thread_nproc;
23639217Sgibbsstatic int thread_onproc = -1;
23718781Sgibbsstatic struct kinfo_proc2 *thread_pbase;
23818781Sgibbs
23939217Sgibbs/* these are for getting the memory statistics */
24039217Sgibbs
24118781Sgibbsstatic int pageshift;		/* log base 2 of the pagesize */
24239217Sgibbs
24318781Sgibbsint threadmode;
24418781Sgibbs
24518781Sgibbs/* define pagetok in terms of pageshift */
24640027Sgibbs
24740027Sgibbs#define pagetok(size) ((size) << pageshift)
24840027Sgibbs
24940027Sgibbs/*
25040027Sgibbs * Print swapped processes as <pname> and
25140027Sgibbs * system processes as [pname]
25240027Sgibbs */
25340027Sgibbsstatic const char *
25440027Sgibbsget_pretty(const struct kinfo_proc2 *pp)
25540027Sgibbs{
25640027Sgibbs	if ((pp->p_flag & P_SYSTEM) != 0)
25740027Sgibbs		return "[]";
25840027Sgibbs	if ((pp->p_flag & P_INMEM) == 0)
25940027Sgibbs		return "<>";
260111409Sobrien	return "";
261111342Sobrien}
262111342Sobrien
263111409Sobrienstatic const char *
26439217Sgibbsget_command(const struct process_select *sel, struct kinfo_proc2 *pp)
26539217Sgibbs{
26639217Sgibbs	static char cmdbuf[128];
26739217Sgibbs	const char *pretty;
26839217Sgibbs	char **argv;
26939217Sgibbs	if (pp == NULL)
27039217Sgibbs		return "<gone>";
27139217Sgibbs	pretty = get_pretty(pp);
27239217Sgibbs
27339217Sgibbs	if (sel->fullcmd == 0 || kd == NULL || (argv = kvm_getargv2(kd, pp,
27439217Sgibbs	    sizeof(cmdbuf))) == NULL) {
27539217Sgibbs		if (pretty[0] != '\0' && pp->p_comm[0] != pretty[0])
27639217Sgibbs			snprintf(cmdbuf, sizeof(cmdbuf), "%c%s%c", pretty[0],
27739217Sgibbs			    printable(pp->p_comm), pretty[1]);
27839217Sgibbs		else
27939217Sgibbs			strlcpy(cmdbuf, printable(pp->p_comm), sizeof(cmdbuf));
28039217Sgibbs	} else {
28118781Sgibbs		char *d = cmdbuf;
28239217Sgibbs		if (pretty[0] != '\0' && argv[0][0] != pretty[0])
28339217Sgibbs			*d++ = pretty[0];
28439217Sgibbs		while (*argv) {
28539217Sgibbs			const char *s = printable(*argv++);
28639217Sgibbs			while (d < cmdbuf + sizeof(cmdbuf) - 2 &&
28739217Sgibbs			    (*d++ = *s++) != '\0')
28839217Sgibbs				continue;
28939217Sgibbs			if (d > cmdbuf && d < cmdbuf + sizeof(cmdbuf) - 2 &&
29039217Sgibbs			    d[-1] == '\0')
29118781Sgibbs				d[-1] = ' ';
29218781Sgibbs		}
29319426Sgibbs		if (pretty[0] != '\0' && pretty[0] == cmdbuf[0])
29418781Sgibbs			*d++ = pretty[1];
29539217Sgibbs		*d++ = '\0';
29639217Sgibbs	}
29739217Sgibbs	return cmdbuf;
29818781Sgibbs}
29939217Sgibbs
30039217Sgibbsint
30139217Sgibbsmachine_init(statics)
30239217Sgibbs	struct statics *statics;
30339217Sgibbs{
30439217Sgibbs	int pagesize;
30539217Sgibbs	int mib[2];
30639217Sgibbs	size_t size;
30739217Sgibbs	struct clockinfo clockinfo;
30839217Sgibbs	struct timeval boottime;
30939217Sgibbs
31039217Sgibbs	if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
31139217Sgibbs		return -1;
31239217Sgibbs
31339217Sgibbs	mib[0] = CTL_HW;
31439217Sgibbs	mib[1] = HW_NCPU;
31539217Sgibbs	size = sizeof(ncpu);
31639217Sgibbs	if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) {
31739217Sgibbs		fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n",
31839217Sgibbs		    strerror(errno));
31939217Sgibbs		return(-1);
32039217Sgibbs	}
32139217Sgibbs	statics->ncpu = ncpu;
32239217Sgibbs	cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu);
32339217Sgibbs	mib[0] = CTL_KERN;
32439217Sgibbs	mib[1] = KERN_CP_TIME;
32539217Sgibbs	size = sizeof(cp_time[0]) * CPUSTATES * ncpu;
32639217Sgibbs	if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) {
32739217Sgibbs		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
32839217Sgibbs		    strerror(errno));
32939217Sgibbs		return(-1);
33039217Sgibbs	}
33139217Sgibbs
33239217Sgibbs	/* Handle old call that returned only aggregate */
33339217Sgibbs	if (size == sizeof(cp_time[0]) * CPUSTATES)
33439217Sgibbs		ncpu = 1;
33539217Sgibbs
33639217Sgibbs	cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu);
33739217Sgibbs	cp_old = malloc(sizeof(cp_old[0]) * CPUSTATES * ncpu);
33839217Sgibbs	cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu);
33939217Sgibbs	if (cpu_states == NULL || cp_time == NULL || cp_old == NULL ||
34039217Sgibbs	    cp_diff == NULL) {
34139217Sgibbs		fprintf(stderr, "top: machine_init: %s\n",
34239217Sgibbs		    strerror(errno));
34339217Sgibbs		return(-1);
34439217Sgibbs	}
34539217Sgibbs
34639217Sgibbs	mib[0] = CTL_KERN;
34739217Sgibbs	mib[1] = KERN_CCPU;
34839217Sgibbs	size = sizeof(ccpu);
34939217Sgibbs	if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) {
35039217Sgibbs		fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n",
35139217Sgibbs		    strerror(errno));
35239217Sgibbs		return(-1);
35339217Sgibbs	}
35439217Sgibbs
35539217Sgibbs	mib[0] = CTL_KERN;
35639217Sgibbs	mib[1] = KERN_CLOCKRATE;
35739217Sgibbs	size = sizeof(clockinfo);
35839217Sgibbs	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) {
35939217Sgibbs		fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n",
36039217Sgibbs		    strerror(errno));
36139217Sgibbs		return(-1);
36239217Sgibbs	}
36339217Sgibbs	hz = clockinfo.stathz;
36439217Sgibbs
36539217Sgibbs	/* this is used in calculating WCPU -- calculate it ahead of time */
36639217Sgibbs	logcpu = log(loaddouble(ccpu));
36739217Sgibbs
36839217Sgibbs	pbase = NULL;
36939217Sgibbs	lbase = NULL;
37039217Sgibbs	pref = NULL;
37139217Sgibbs	nproc = 0;
37239217Sgibbs	onproc = -1;
37339217Sgibbs	nlwp = 0;
37439217Sgibbs	onlwp = -1;
37539217Sgibbs	/* get the page size with "getpagesize" and calculate pageshift from it */
37639217Sgibbs	pagesize = getpagesize();
37739217Sgibbs	pageshift = 0;
37839217Sgibbs	while (pagesize > 1) {
37939217Sgibbs		pageshift++;
38039217Sgibbs		pagesize >>= 1;
38118781Sgibbs	}
38239217Sgibbs
38339217Sgibbs	/* we only need the amount of log(2)1024 for our conversion */
38439217Sgibbs	pageshift -= LOG1024;
38539217Sgibbs
38639217Sgibbs	/* fill in the statics information */
38739217Sgibbs#ifdef notyet
38839217Sgibbs	statics->ncpu = ncpu;
38939217Sgibbs#endif
39039217Sgibbs	statics->procstate_names = procstatenames;
39139217Sgibbs	statics->cpustate_names = cpustatenames;
39239217Sgibbs	statics->memory_names = memorynames;
39339217Sgibbs	statics->swap_names = swapnames;
39439217Sgibbs	statics->order_names = ordernames;
39539217Sgibbs	statics->flags.threads = 1;
39639217Sgibbs	statics->flags.fullcmds = 1;
39739217Sgibbs
39839217Sgibbs	mib[0] = CTL_KERN;
39939217Sgibbs	mib[1] = KERN_BOOTTIME;
40039217Sgibbs	size = sizeof(boottime);
40139217Sgibbs	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
40218781Sgibbs    	    boottime.tv_sec != 0)
40318781Sgibbs		statics->boottime = boottime.tv_sec;
40418781Sgibbs	else
40518781Sgibbs		statics->boottime = 0;
40618781Sgibbs	/* all done! */
40718781Sgibbs	return(0);
40818781Sgibbs}
40918781Sgibbs
41018781Sgibbschar *
41118781Sgibbsformat_process_header(struct process_select *sel, caddr_t handle, int count)
41218781Sgibbs
41318781Sgibbs{
41418781Sgibbs	char *header;
41518781Sgibbs	char *ptr;
41618781Sgibbs	const char *uname_field = sel->usernames ? "USERNAME" : "    UID ";
41718781Sgibbs
41818781Sgibbs	if (sel->threads) {
41918781Sgibbs		header = Thread_header;
42018781Sgibbs		ptr = header + THREAD_UNAME_START;
42118781Sgibbs	} else {
42218781Sgibbs		header = Proc_header;
42318781Sgibbs		ptr = header + PROC_UNAME_START;
42418781Sgibbs	}
42518781Sgibbs
42618781Sgibbs	while (*uname_field != '\0') {
42739217Sgibbs		*ptr++ = *uname_field++;
42818781Sgibbs	}
42918781Sgibbs
43018781Sgibbs	return(header);
43118781Sgibbs}
43218781Sgibbs
43318781Sgibbschar *
43418781Sgibbsformat_header(char *uname_field)
43518781Sgibbs{
43618781Sgibbs	char *header = Proc_header;
43718781Sgibbs	char *ptr = header + PROC_UNAME_START;
43818781Sgibbs
43918781Sgibbs	while (*uname_field != '\0') {
44018781Sgibbs		*ptr++ = *uname_field++;
44118781Sgibbs	}
44218781Sgibbs
44318781Sgibbs	return(header);
44439217Sgibbs}
44518781Sgibbs
44618781Sgibbsvoid
44718781Sgibbsget_system_info(struct system_info *si)
44818781Sgibbs{
44918781Sgibbs	size_t ssize;
45018781Sgibbs	int mib[2];
45139217Sgibbs	struct uvmexp_sysctl uvmexp;
45218781Sgibbs	struct swapent *sep;
45318781Sgibbs	u_int64_t totalsize, totalinuse;
45418781Sgibbs	int size, inuse, ncounted, i;
45518781Sgibbs	int rnswap, nswap;
45618781Sgibbs
45718781Sgibbs	mib[0] = CTL_KERN;
45839217Sgibbs	mib[1] = KERN_CP_TIME;
45939217Sgibbs	ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu;
46039217Sgibbs	if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) {
46118781Sgibbs		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
46239217Sgibbs		    strerror(errno));
46339217Sgibbs		quit(23);
46439217Sgibbs	}
46539217Sgibbs
46639217Sgibbs	if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) {
46739217Sgibbs		int j;
46839217Sgibbs
46939217Sgibbs		warn("can't getloadavg");
47039217Sgibbs		for (j = 0; j < NUM_AVERAGES; j++)
47139217Sgibbs			si->load_avg[j] = 0.0;
47239217Sgibbs	}
47339217Sgibbs
47439217Sgibbs	/* convert cp_time counts to percentages */
47539217Sgibbs	for (i = 0; i < ncpu; i++) {
47618781Sgibbs	    int j = i * CPUSTATES;
47739217Sgibbs	    percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j,
47818781Sgibbs		cp_diff + j);
47939217Sgibbs	}
48039217Sgibbs
48139217Sgibbs	mib[0] = CTL_VM;
48239217Sgibbs	mib[1] = VM_UVMEXP2;
48339217Sgibbs	ssize = sizeof(uvmexp);
48439217Sgibbs	if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) {
48539217Sgibbs		fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n",
48618781Sgibbs		    strerror(errno));
48718781Sgibbs		quit(23);
48818781Sgibbs	}
48939217Sgibbs
49039217Sgibbs	/* convert memory stats to Kbytes */
49118781Sgibbs	memory_stats[0] = pagetok(uvmexp.active);
49218781Sgibbs	memory_stats[1] = pagetok(uvmexp.inactive);
49318781Sgibbs	memory_stats[2] = pagetok(uvmexp.wired);
49418781Sgibbs	memory_stats[3] = pagetok(uvmexp.execpages);
49518781Sgibbs	memory_stats[4] = pagetok(uvmexp.filepages);
49618781Sgibbs	memory_stats[5] = pagetok(uvmexp.free);
49718781Sgibbs
49818781Sgibbs	swap_stats[0] = swap_stats[1] = swap_stats[2] = 0;
49918781Sgibbs
50018781Sgibbs	do {
50118781Sgibbs		nswap = swapctl(SWAP_NSWAP, 0, 0);
50218781Sgibbs		if (nswap < 1)
50318781Sgibbs			break;
50418781Sgibbs		if (nswap > maxswap) {
50518781Sgibbs			if (swapp)
50618781Sgibbs				free(swapp);
50718781Sgibbs			swapp = sep = malloc(nswap * sizeof(*sep));
50818781Sgibbs			if (sep == NULL)
50918781Sgibbs				break;
51018781Sgibbs			maxswap = nswap;
51118781Sgibbs		} else
51218781Sgibbs			sep = swapp;
51318781Sgibbs		rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
51418781Sgibbs		if (nswap != rnswap)
51518781Sgibbs			break;
51618781Sgibbs
51718781Sgibbs		totalsize = totalinuse = ncounted = 0;
51818781Sgibbs		for (; rnswap-- > 0; sep++) {
51918781Sgibbs			ncounted++;
52018781Sgibbs			size = sep->se_nblks;
52118781Sgibbs			inuse = sep->se_inuse;
52218781Sgibbs			totalsize += size;
52318781Sgibbs			totalinuse += inuse;
52418781Sgibbs		}
52518781Sgibbs		swap_stats[0] = dbtob(totalsize) / 1024;
52639217Sgibbs		swap_stats[1] = dbtob(totalinuse) / 1024;
52739217Sgibbs		swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1];
52818781Sgibbs	} while (0);
52918781Sgibbs
53018781Sgibbs	memory_stats[6] = -1;
53118781Sgibbs	swap_stats[3] = -1;
53218781Sgibbs
53318781Sgibbs	/* set arrays and strings */
53418781Sgibbs	si->cpustates = cpu_states;
53518781Sgibbs	si->memory = memory_stats;
53618781Sgibbs	si->swap = swap_stats;
53718781Sgibbs	si->last_pid = -1;
53818781Sgibbs
53918781Sgibbs}
54018781Sgibbs
54118781Sgibbsstatic struct kinfo_proc2 *
54218781Sgibbsproc_from_thread(struct kinfo_lwp *pl)
54318781Sgibbs{
54455945Sgibbs	struct kinfo_proc2 *pp = thread_pbase;
54518781Sgibbs	int i;
54618781Sgibbs
54755945Sgibbs	for (i = 0; i < thread_nproc; i++, pp++)
54855945Sgibbs		if ((pid_t)pp->p_pid == (pid_t)pl->l_pid)
54955945Sgibbs			return pp;
55018781Sgibbs	return NULL;
55118781Sgibbs}
55218781Sgibbs
55318781Sgibbsstatic int
55455945Sgibbsuid_from_thread(struct kinfo_lwp *pl)
55555945Sgibbs{
55655945Sgibbs	struct kinfo_proc2 *pp;
55718781Sgibbs
55855945Sgibbs	if ((pp = proc_from_thread(pl)) == NULL)
55955945Sgibbs		return -1;
56055945Sgibbs	return pp->p_ruid;
56155945Sgibbs}
56255945Sgibbs
56318781Sgibbscaddr_t
56418781Sgibbsget_process_info(struct system_info *si, struct process_select *sel, int c)
56518781Sgibbs{
56618781Sgibbs	userprint = sel->usernames ? username : itoa7;
56739217Sgibbs
56818781Sgibbs	if ((threadmode = sel->threads) != 0)
56918781Sgibbs		return get_lwp_info(si, sel, proc_compares[c]);
57018781Sgibbs	else
57118781Sgibbs		return get_proc_info(si, sel, proc_compares[c]);
57218781Sgibbs}
57318781Sgibbs
57418781Sgibbsstatic caddr_t
57518781Sgibbsget_proc_info(struct system_info *si, struct process_select *sel,
57618781Sgibbs	      int (*compare)(struct proc **, struct proc **))
57718781Sgibbs{
57818781Sgibbs	int i;
57918781Sgibbs	int total_procs;
58018781Sgibbs	int active_procs;
58118781Sgibbs	struct kinfo_proc2 **prefp, **n;
58218781Sgibbs	struct kinfo_proc2 *pp;
58318781Sgibbs	int op, arg;
58418781Sgibbs
58518781Sgibbs	/* these are copied out of sel for speed */
58639217Sgibbs	int show_idle;
58718781Sgibbs	int show_system;
58818781Sgibbs	int show_uid;
58939217Sgibbs	int show_command;
59018781Sgibbs
59118781Sgibbs	static struct handle handle;
59218781Sgibbs
59318781Sgibbs	procgen++;
59439217Sgibbs
59539217Sgibbs	if (sel->pid == (pid_t)-1) {
59618781Sgibbs		op = KERN_PROC_ALL;
59718781Sgibbs		arg = 0;
59818781Sgibbs	} else {
59918781Sgibbs		op = KERN_PROC_PID;
60018781Sgibbs		arg = sel->pid;
60118781Sgibbs	}
60218781Sgibbs
60318781Sgibbs	pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc);
60418781Sgibbs	if (pbase == NULL) {
60518781Sgibbs		if (sel->pid != (pid_t)-1) {
60618781Sgibbs			nproc = 0;
60718781Sgibbs		} else {
60818781Sgibbs			(void) fprintf(stderr, "top: Out of memory.\n");
60918781Sgibbs			quit(23);
61039217Sgibbs		}
61118781Sgibbs	}
61218781Sgibbs	if (nproc > onproc) {
61318781Sgibbs		n = (struct kinfo_proc2 **) realloc(pref,
61418781Sgibbs		    sizeof(struct kinfo_proc2 *) * nproc);
61518781Sgibbs		if (n == NULL) {
61618781Sgibbs			(void) fprintf(stderr, "top: Out of memory.\n");
61718781Sgibbs			quit(23);
61818781Sgibbs		}
61918781Sgibbs		pref = n;
62018781Sgibbs		onproc = nproc;
62118781Sgibbs	}
62218781Sgibbs	/* get a pointer to the states summary array */
62318781Sgibbs	si->procstates = process_states;
62418781Sgibbs
62518781Sgibbs	/* set up flags which define what we are going to select */
62618781Sgibbs	show_idle = sel->idle;
62718781Sgibbs	show_system = sel->system;
62818781Sgibbs	show_uid = sel->uid != -1;
62918781Sgibbs	show_command = sel->command != NULL;
63018781Sgibbs
63118781Sgibbs	/* count up process states and get pointers to interesting procs */
63218781Sgibbs	total_procs = 0;
63339217Sgibbs	active_procs = 0;
63418781Sgibbs	memset((char *)process_states, 0, sizeof(process_states));
63518781Sgibbs	prefp = pref;
63618781Sgibbs	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
63718781Sgibbs
63818781Sgibbs		/*
63939217Sgibbs		 * Place pointers to each valid proc structure in pref[].
64039217Sgibbs		 * Process slots that are actually in use have a non-zero
64118781Sgibbs		 * status field.  Processes with P_SYSTEM set are system
64218781Sgibbs		 * processes---these get ignored unless show_sysprocs is set.
64318781Sgibbs		 */
64418781Sgibbs		if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) {
64518781Sgibbs			total_procs++;
64618781Sgibbs			process_states[(unsigned char) pp->p_stat]++;
64718781Sgibbs			if (pp->p_stat != LSZOMB &&
64818781Sgibbs			    (show_idle || (pp->p_pctcpu != 0) ||
64918781Sgibbs			    (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) &&
65018781Sgibbs			    (!show_uid || pp->p_ruid == (uid_t)sel->uid)) {
65118781Sgibbs				*prefp++ = pp;
65218781Sgibbs				active_procs++;
65318781Sgibbs			}
65418781Sgibbs		}
65518781Sgibbs	}
65618781Sgibbs
65718781Sgibbs	/* if requested, sort the "interesting" processes */
65818781Sgibbs	if (compare != NULL) {
65918781Sgibbs		qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *),
66018781Sgibbs		    (int (*)(const void *, const void *))compare);
66118781Sgibbs	}
66218781Sgibbs
66318781Sgibbs	/* remember active and total counts */
66418781Sgibbs	si->p_total = total_procs;
66518781Sgibbs	si->p_active = pref_len = active_procs;
66639217Sgibbs
66739217Sgibbs	/* pass back a handle */
66839217Sgibbs	handle.next_proc = pref;
66939217Sgibbs	handle.remaining = active_procs;
67039217Sgibbs	handle.sel = sel;
67139217Sgibbs	return((caddr_t)&handle);
67239217Sgibbs}
67339217Sgibbs
67439217Sgibbsstatic caddr_t
67539217Sgibbsget_lwp_info(struct system_info *si, struct process_select *sel,
67639217Sgibbs	     int (*compare)(struct proc **, struct proc **))
67739217Sgibbs{
67839217Sgibbs	int i;
67918781Sgibbs	int total_lwps;
68039217Sgibbs	int active_lwps;
68139217Sgibbs	struct kinfo_lwp **lrefp, **n;
68218781Sgibbs	struct kinfo_lwp *lp;
68339217Sgibbs	struct kinfo_proc2 *pp;
68439217Sgibbs
68539217Sgibbs	/* these are copied out of sel for speed */
68639217Sgibbs	int show_idle;
68718781Sgibbs	int show_system;
68818781Sgibbs	int show_uid;
68918781Sgibbs	int show_command;
69018781Sgibbs
69118781Sgibbs	static struct handle handle;
69218781Sgibbs
69318781Sgibbs	pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
69418781Sgibbs	    &thread_nproc);
69518781Sgibbs	if (pp == NULL) {
69618781Sgibbs		(void) fprintf(stderr, "top: Out of memory.\n");
69718781Sgibbs		quit(23);
69818781Sgibbs	}
69939217Sgibbs	if (thread_pbase == NULL || thread_nproc != thread_onproc) {
70018781Sgibbs		free(thread_pbase);
70139217Sgibbs		thread_onproc = thread_nproc;
70239217Sgibbs		thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc);
70339217Sgibbs		if (thread_pbase == NULL) {
70439217Sgibbs			(void) fprintf(stderr, "top: Out of memory.\n");
70539217Sgibbs			quit(23);
70639217Sgibbs		}
70739217Sgibbs	}
70839217Sgibbs	memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc);
70918781Sgibbs
71018781Sgibbs	lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp);
71118781Sgibbs	if (lbase == NULL) {
71218781Sgibbs#ifdef notyet
71318781Sgibbs		if (sel->pid != (pid_t)-1) {
71418781Sgibbs			nproc = 0;
71518781Sgibbs			nlwp = 0;
71618781Sgibbs		}
71718781Sgibbs		else
71818781Sgibbs#endif
71939217Sgibbs		{
72039217Sgibbs			(void) fprintf(stderr, "top: Out of memory.\n");
72118781Sgibbs			quit(23);
72218781Sgibbs		}
72339217Sgibbs	}
72439217Sgibbs	if (nlwp > onlwp) {
72518781Sgibbs		n = (struct kinfo_lwp **) realloc(lref,
72655945Sgibbs		    sizeof(struct kinfo_lwp *) * nlwp);
72739505Sgibbs		if (n == NULL) {
72839505Sgibbs			(void) fprintf(stderr, "top: Out of memory.\n");
72918781Sgibbs			quit(23);
73018781Sgibbs		}
73118781Sgibbs		lref = n;
73218781Sgibbs		onlwp = nlwp;
73318781Sgibbs	}
73439217Sgibbs	/* get a pointer to the states summary array */
73539217Sgibbs	si->procstates = process_states;
73618781Sgibbs
73718781Sgibbs	/* set up flags which define what we are going to select */
73818781Sgibbs	show_idle = sel->idle;
73939217Sgibbs	show_system = sel->system;
74039217Sgibbs	show_uid = sel->uid != -1;
74139217Sgibbs	show_command = sel->command != NULL;
74239217Sgibbs
74318781Sgibbs	/* count up thread states and get pointers to interesting threads */
74418781Sgibbs	total_lwps = 0;
74518781Sgibbs	active_lwps = 0;
74618781Sgibbs	memset((char *)process_states, 0, sizeof(process_states));
74718781Sgibbs	lrefp = lref;
74818781Sgibbs	for (lp = lbase, i = 0; i < nlwp; lp++, i++) {
74918781Sgibbs		if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid)
75018781Sgibbs			continue;
75118781Sgibbs
75239217Sgibbs		/*
75339217Sgibbs		 * Place pointers to each valid lwp structure in lref[].
75439217Sgibbs		 * thread slots that are actually in use have a non-zero
75539217Sgibbs		 * status field.  threads with L_SYSTEM set are system
75639217Sgibbs		 * threads---these get ignored unless show_sysprocs is set.
75739217Sgibbs		 */
75839217Sgibbs		if (lp->l_stat != 0 && (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) {
75939217Sgibbs			total_lwps++;
76039217Sgibbs			process_states[(unsigned char) lp->l_stat]++;
76139217Sgibbs			if (lp->l_stat != LSZOMB &&
76239217Sgibbs			    (show_idle || (lp->l_pctcpu != 0) ||
76339217Sgibbs			    (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) &&
76439217Sgibbs			    (!show_uid || uid_from_thread(lp) == sel->uid)) {
76539217Sgibbs				*lrefp++ = lp;
76639217Sgibbs				active_lwps++;
76739217Sgibbs			}
76839217Sgibbs		}
76939217Sgibbs	}
77018781Sgibbs
77118781Sgibbs	/* if requested, sort the "interesting" threads */
77218781Sgibbs	if (compare != NULL) {
77318781Sgibbs		qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *),
77439217Sgibbs		    (int (*)(const void *, const void *))compare);
77539217Sgibbs	}
77639217Sgibbs
77739217Sgibbs	/* remember active and total counts */
77839217Sgibbs	si->p_total = total_lwps;
77939217Sgibbs	si->p_active = lref_len = active_lwps;
78039217Sgibbs
78139217Sgibbs	/* pass back a handle */
78239217Sgibbs	handle.next_proc = (struct kinfo_proc2 **)lref;
78339217Sgibbs	handle.remaining = active_lwps;
78439217Sgibbs	handle.sel = sel;
78539217Sgibbs
78639217Sgibbs	return((caddr_t)&handle);
78739217Sgibbs}
78839217Sgibbs
78939217Sgibbschar *
79039217Sgibbsformat_next_process(caddr_t handle, char *(*get_userid)(int))
79139217Sgibbs{
79239217Sgibbs
79339217Sgibbs	if (threadmode)
79439217Sgibbs		return format_next_lwp(handle, get_userid);
79539217Sgibbs	else
79639217Sgibbs		return format_next_proc(handle, get_userid);
79718781Sgibbs}
79839217Sgibbs
79918781Sgibbs
80018781Sgibbschar *
80118781Sgibbsformat_next_proc(caddr_t handle, char *(*get_userid)(int))
80218781Sgibbs{
80318781Sgibbs	struct kinfo_proc2 *pp;
80418781Sgibbs	long cputime;
80518781Sgibbs	double pct, wcpu, cpu;
80639217Sgibbs	struct handle *hp;
80739217Sgibbs	const char *statep;
80818781Sgibbs#ifdef KI_NOCPU
80939217Sgibbs	char state[10];
81039217Sgibbs#endif
81118781Sgibbs	char wmesg[KI_WMESGLEN + 1];
81218781Sgibbs	static char fmt[MAX_COLS];		/* static area where result is built */
81318781Sgibbs
81418781Sgibbs	/* find and remember the next proc structure */
81518781Sgibbs	hp = (struct handle *)handle;
81618781Sgibbs	pp = *(hp->next_proc++);
81718781Sgibbs	hp->remaining--;
81818781Sgibbs
81918781Sgibbs	/* get the process's user struct and set cputime */
82018781Sgibbs
82118781Sgibbs#if 0
82218781Sgibbs	/* This does not produce the correct results */
82318781Sgibbs	cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
82418781Sgibbs#else
82518781Sgibbs	cputime = pp->p_rtime_sec;	/* This does not count interrupts */
82618781Sgibbs#endif
82718781Sgibbs
82818781Sgibbs	/* calculate the base for CPU percentages */
82918781Sgibbs	pct = pctdouble(pp->p_pctcpu);
83039217Sgibbs
83118781Sgibbs	if (pp->p_stat == LSSLEEP) {
83240133Sgibbs		strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg));
83355945Sgibbs		statep = wmesg;
83455945Sgibbs	} else
83540133Sgibbs		statep = state_abbrev[(unsigned)pp->p_stat];
83639217Sgibbs
83740133Sgibbs#ifdef KI_NOCPU
83855945Sgibbs	/* Post-1.5 change: add CPU number if appropriate */
83955945Sgibbs	if (pp->p_cpuid != KI_NOCPU && ncpu > 1) {
84055945Sgibbs		switch (pp->p_stat) {
84118781Sgibbs		case LSONPROC:
84218781Sgibbs		case LSRUN:
84318781Sgibbs		case LSSLEEP:
84418781Sgibbs		case LSIDL:
84518781Sgibbs			(void)snprintf(state, sizeof(state), "%.6s/%u",
84618781Sgibbs			     statep, (unsigned int)pp->p_cpuid);
84718781Sgibbs			statep = state;
84818781Sgibbs			break;
84918781Sgibbs		}
85018781Sgibbs	}
85139217Sgibbs#endif
85218781Sgibbs	wcpu = 100.0 * weighted_cpu(p_, pct, pp);
85339217Sgibbs	cpu = 100.0 * pct;
85439217Sgibbs
85539217Sgibbs	/* format this entry */
85639217Sgibbs	sprintf(fmt,
85739217Sgibbs	    Proc_format,
85839217Sgibbs	    pp->p_pid,
85939217Sgibbs	    (*userprint)(pp->p_ruid),
86039217Sgibbs	    pp->p_priority,
86139217Sgibbs	    pp->p_nice - NZERO,
86218781Sgibbs	    format_k(pagetok(PROCSIZE(pp))),
86318781Sgibbs	    format_k(pagetok(pp->p_vm_rssize)),
86418781Sgibbs	    statep,
86518781Sgibbs	    format_time(cputime),
86618781Sgibbs	    (wcpu >= 100.0) ? 0 : 2, wcpu,
86718781Sgibbs	    (cpu >= 100.0) ? 0 : 2, cpu,
86818781Sgibbs	    get_command(hp->sel, pp));
86918781Sgibbs
87018781Sgibbs	/* return the result */
87118781Sgibbs	return(fmt);
87218781Sgibbs}
87318781Sgibbs
87418781Sgibbsstatic char *
87518781Sgibbsformat_next_lwp(caddr_t handle, char *(*get_userid)(int))
87618781Sgibbs{
87718781Sgibbs	struct kinfo_proc2 *pp;
87818781Sgibbs	struct kinfo_lwp *pl;
87918781Sgibbs	long cputime;
88039217Sgibbs	double pct;
88118781Sgibbs	struct handle *hp;
88218781Sgibbs	const char *statep;
88318781Sgibbs#ifdef KI_NOCPU
88418781Sgibbs	char state[10];
88518781Sgibbs#endif
88618781Sgibbs	char wmesg[KI_WMESGLEN + 1];
88718781Sgibbs	static char fmt[MAX_COLS];		/* static area where result is built */
88818781Sgibbs	int uid;
88918781Sgibbs
89018781Sgibbs	/* find and remember the next proc structure */
89118781Sgibbs	hp = (struct handle *)handle;
89218781Sgibbs	pl = (struct kinfo_lwp *)*(hp->next_proc++);
89318781Sgibbs	hp->remaining--;
89418781Sgibbs	pp = proc_from_thread(pl);
89539217Sgibbs
89618781Sgibbs	/* get the process's user struct and set cputime */
89718781Sgibbs	uid = pp ? pp->p_ruid : 0;
89818781Sgibbs
89918781Sgibbs	cputime = pl->l_rtime_sec;
90018781Sgibbs
90118781Sgibbs	/* calculate the base for CPU percentages */
90218781Sgibbs	pct = pctdouble(pl->l_pctcpu);
90318781Sgibbs
90418781Sgibbs	if (pl->l_stat == LSSLEEP) {
90518781Sgibbs		strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg));
90618781Sgibbs		statep = wmesg;
90718781Sgibbs	} else
90818781Sgibbs		statep = state_abbrev[(unsigned)pl->l_stat];
90918781Sgibbs
91018781Sgibbs#ifdef KI_NOCPU
91118781Sgibbs	/* Post-1.5 change: add CPU number if appropriate */
91218781Sgibbs	if (pl->l_cpuid != KI_NOCPU && ncpu > 1) {
91318781Sgibbs		switch (pl->l_stat) {
91418781Sgibbs		case LSONPROC:
91518781Sgibbs		case LSRUN:
91618781Sgibbs		case LSSLEEP:
91718781Sgibbs		case LSIDL:
91818781Sgibbs			(void)snprintf(state, sizeof(state), "%.6s/%u",
91918781Sgibbs			     statep, (unsigned int)pl->l_cpuid);
92018781Sgibbs			statep = state;
92118781Sgibbs			break;
92218781Sgibbs		}
92318781Sgibbs	}
92418781Sgibbs#endif
92518781Sgibbs
92618781Sgibbs	if (pl->l_name[0] == '\0') {
92718781Sgibbs		pl->l_name[0] = '-';
92818781Sgibbs		pl->l_name[1] = '\0';
92918781Sgibbs	}
93039217Sgibbs
93118781Sgibbs	/* format this entry */
93218781Sgibbs	sprintf(fmt,
93339217Sgibbs	    Thread_format,
93439217Sgibbs	    pl->l_pid,
93539217Sgibbs	    pl->l_lid,
93618781Sgibbs	    (*userprint)(uid),
93718781Sgibbs	    pl->l_priority,
93818781Sgibbs	    statep,
93918781Sgibbs	    format_time(cputime),
94018781Sgibbs	    100.0 * weighted_cpu(l_, pct, pl),
94118781Sgibbs	    100.0 * pct,
94218781Sgibbs	    printable(pl->l_name),
94318781Sgibbs	    get_command(hp->sel, pp));
94418781Sgibbs
94518781Sgibbs	/* return the result */
94618781Sgibbs	return(fmt);
94739217Sgibbs}
94839217Sgibbs
94918781Sgibbs/* comparison routines for qsort */
95039217Sgibbs
95139217Sgibbs/*
95239217Sgibbs * There are currently four possible comparison routines.  main selects
95339217Sgibbs * one of these by indexing in to the array proc_compares.
95418781Sgibbs *
95539217Sgibbs * Possible keys are defined as macros below.  Currently these keys are
95639217Sgibbs * defined:  percent CPU, CPU ticks, process state, resident set size,
95739217Sgibbs * total virtual memory usage.  The process states are ordered as follows
95839217Sgibbs * (from least to most important):  WAIT, zombie, sleep, stop, start, run.
95939217Sgibbs * The array declaration below maps a process state index into a number
96039217Sgibbs * that reflects this ordering.
96139217Sgibbs */
96239217Sgibbs
96339217Sgibbs/*
96439217Sgibbs * First, the possible comparison keys.  These are defined in such a way
96539217Sgibbs * that they can be merely listed in the source code to define the actual
96639217Sgibbs * desired ordering.
96718781Sgibbs */
96855945Sgibbs
96955945Sgibbs#define ORDERKEY_PCTCPU(pfx) \
97055945Sgibbs	if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
97155945Sgibbs	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
97255945Sgibbs
97318781Sgibbs#define ORDERKEY_CPTICKS(pfx) \
97439217Sgibbs	if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
97518781Sgibbs		    - (pctcpu)(p1)->pfx ## rtime_sec,\
97618781Sgibbs	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
97739217Sgibbs
97839217Sgibbs#define ORDERKEY_STATE(pfx) \
97939217Sgibbs	if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
98039217Sgibbs		      sorted_state[(int)(p1)->pfx ## stat] ) == 0)
98139217Sgibbs
98239217Sgibbs#define ORDERKEY_PRIO(pfx) \
98339217Sgibbs	if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
98418781Sgibbs
98518781Sgibbs#define ORDERKEY_RSSIZE \
98618781Sgibbs	if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
98718781Sgibbs
98818781Sgibbs#define ORDERKEY_MEM	\
98939217Sgibbs	if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
99039217Sgibbs#define ORDERKEY_SIZE(v1, v2)	\
99139217Sgibbs	if ((result = (v2 - v1)) == 0)
99239217Sgibbs
99318781Sgibbs/*
99439217Sgibbs * Now the array that maps process state to a weight.
99539217Sgibbs * The order of the elements should match those in state_abbrev[]
99639217Sgibbs */
99739217Sgibbs
99839217Sgibbsstatic int sorted_state[] = {
99939217Sgibbs	0,	/*  (not used)	  ?	*/
100039217Sgibbs	1,	/* "start"	SIDL	*/
100139217Sgibbs	4,	/* "run"	SRUN	*/
100239217Sgibbs	3,	/* "sleep"	SSLEEP	*/
100318781Sgibbs	3,	/* "stop"	SSTOP	*/
100439217Sgibbs	2,	/* "dead"	SDEAD	*/
100539217Sgibbs	1,	/* "zomb"	SZOMB	*/
100639217Sgibbs	5,	/* "onproc"	SONPROC	*/
100739217Sgibbs};
100839217Sgibbs
100955945Sgibbs/* compare_cpu - the comparison function for sorting by CPU percentage */
101055945Sgibbs
101155945Sgibbsstatic int
101239217Sgibbscompare_cpu(pp1, pp2)
101339217Sgibbs	struct proc **pp1, **pp2;
101439217Sgibbs{
101539217Sgibbs	int result;
101639217Sgibbs	pctcpu lresult;
101718781Sgibbs
101839217Sgibbs	if (threadmode) {
101918781Sgibbs		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
102045846Sgibbs		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
102145846Sgibbs
102245846Sgibbs		ORDERKEY_PCTCPU(l_)
102345846Sgibbs		ORDERKEY_CPTICKS(l_)
102445846Sgibbs		ORDERKEY_STATE(l_)
102545846Sgibbs		ORDERKEY_PRIO(l_)
102645846Sgibbs		return result;
102718781Sgibbs	} else {
102839217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
102918781Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
103018781Sgibbs
103118781Sgibbs		ORDERKEY_PCTCPU(p_)
103218781Sgibbs		ORDERKEY_CPTICKS(p_)
103318781Sgibbs		ORDERKEY_STATE(p_)
103439217Sgibbs		ORDERKEY_PRIO(p_)
103539217Sgibbs		ORDERKEY_RSSIZE
103639217Sgibbs		ORDERKEY_MEM
103718781Sgibbs		return result;
103839217Sgibbs	}
103939217Sgibbs
104039217Sgibbs	return (result);
104139217Sgibbs}
104218781Sgibbs
104318781Sgibbs/* compare_prio - the comparison function for sorting by process priority */
104418781Sgibbs
104518781Sgibbsstatic int
104639217Sgibbscompare_prio(pp1, pp2)
104739217Sgibbs	struct proc **pp1, **pp2;
104855945Sgibbs{
104939217Sgibbs	int result;
105039217Sgibbs	pctcpu lresult;
105139217Sgibbs
105255945Sgibbs	if (threadmode) {
105355945Sgibbs		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
105455945Sgibbs		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
105539217Sgibbs
105640733Sgibbs		ORDERKEY_PRIO(l_)
105740733Sgibbs		ORDERKEY_PCTCPU(l_)
105839217Sgibbs		ORDERKEY_CPTICKS(l_)
105939217Sgibbs		ORDERKEY_STATE(l_)
106039217Sgibbs		return result;
106139217Sgibbs	} else {
106239217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
106339217Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
106455945Sgibbs
106555945Sgibbs		ORDERKEY_PRIO(p_)
106639217Sgibbs		ORDERKEY_PCTCPU(p_)
106739217Sgibbs		ORDERKEY_CPTICKS(p_)
106839217Sgibbs		ORDERKEY_STATE(p_)
106918781Sgibbs		ORDERKEY_RSSIZE
107039217Sgibbs		ORDERKEY_MEM
107139217Sgibbs		return result;
107239217Sgibbs	}
107339217Sgibbs
107439217Sgibbs	return (result);
107539217Sgibbs}
107639217Sgibbs
107739217Sgibbs/* compare_res - the comparison function for sorting by resident set size */
107839217Sgibbs
107939217Sgibbsstatic int
108039217Sgibbscompare_res(pp1, pp2)
108139217Sgibbs	struct proc **pp1, **pp2;
108239217Sgibbs{
108339217Sgibbs	int result;
108439217Sgibbs	pctcpu lresult;
108539217Sgibbs
108639217Sgibbs	if (threadmode) {
108739217Sgibbs		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
108839217Sgibbs		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
108939217Sgibbs
109039217Sgibbs		ORDERKEY_PCTCPU(l_)
109139217Sgibbs		ORDERKEY_CPTICKS(l_)
109239217Sgibbs		ORDERKEY_STATE(l_)
109339217Sgibbs		ORDERKEY_PRIO(l_)
109439217Sgibbs		return result;
109539217Sgibbs	} else {
109639217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
109739217Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
109839217Sgibbs
109939217Sgibbs		ORDERKEY_RSSIZE
110039217Sgibbs		ORDERKEY_MEM
110139217Sgibbs		ORDERKEY_PCTCPU(p_)
110239217Sgibbs		ORDERKEY_CPTICKS(p_)
110339217Sgibbs		ORDERKEY_STATE(p_)
110439217Sgibbs		ORDERKEY_PRIO(p_)
110539217Sgibbs		return result;
110639217Sgibbs	}
110739217Sgibbs
110839217Sgibbs	return (result);
110939217Sgibbs}
111039217Sgibbs
111139217Sgibbsstatic int
111239217Sgibbscompare_pid(pp1, pp2)
111339217Sgibbs	struct proc **pp1, **pp2;
111439217Sgibbs{
111539217Sgibbs	if (threadmode) {
111639217Sgibbs		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
111718781Sgibbs		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
111839217Sgibbs		struct kinfo_proc2 *p1 = proc_from_thread(l1);
111939217Sgibbs		struct kinfo_proc2 *p2 = proc_from_thread(l2);
112018781Sgibbs		return p2->p_pid - p1->p_pid;
112139217Sgibbs	} else {
112239217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
112318781Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
112439217Sgibbs		return p2->p_pid - p1->p_pid;
112539217Sgibbs	}
112639217Sgibbs}
112718781Sgibbs
112839217Sgibbsstatic int
112939217Sgibbscompare_command(pp1, pp2)
113039217Sgibbs	struct proc **pp1, **pp2;
113139217Sgibbs{
113239217Sgibbs	if (threadmode) {
113339217Sgibbs		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
113439217Sgibbs		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
113539217Sgibbs		struct kinfo_proc2 *p1 = proc_from_thread(l1);
113639217Sgibbs		struct kinfo_proc2 *p2 = proc_from_thread(l2);
113739217Sgibbs		return strcmp(p2->p_comm, p1->p_comm);
113839217Sgibbs	} else {
113939217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
114039217Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
114139217Sgibbs		return strcmp(p2->p_comm, p1->p_comm);
114239217Sgibbs	}
114339217Sgibbs}
114439217Sgibbs
114539217Sgibbsstatic int
114639217Sgibbscompare_username(pp1, pp2)
114739217Sgibbs	struct proc **pp1, **pp2;
114839217Sgibbs{
114939217Sgibbs	if (threadmode) {
115039217Sgibbs		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
115139217Sgibbs		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
115239217Sgibbs		struct kinfo_proc2 *p1 = proc_from_thread(l1);
115339217Sgibbs		struct kinfo_proc2 *p2 = proc_from_thread(l2);
115439217Sgibbs		return strcmp(p2->p_login, p1->p_login);
115539217Sgibbs	} else {
115639217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
115739217Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
115839217Sgibbs		return strcmp(p2->p_login, p1->p_login);
115939217Sgibbs	}
116039217Sgibbs}
116139217Sgibbs/* compare_size - the comparison function for sorting by total memory usage */
116239217Sgibbs
116339217Sgibbsstatic int
116439217Sgibbscompare_size(pp1, pp2)
116539217Sgibbs	struct proc **pp1, **pp2;
116639217Sgibbs{
116739217Sgibbs	int result;
116839217Sgibbs	pctcpu lresult;
116939217Sgibbs
117039217Sgibbs	if (threadmode) {
117139217Sgibbs		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
117239217Sgibbs		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
117339217Sgibbs
117439217Sgibbs		ORDERKEY_PCTCPU(l_)
117539217Sgibbs		ORDERKEY_CPTICKS(l_)
117639217Sgibbs		ORDERKEY_STATE(l_)
117739217Sgibbs		ORDERKEY_PRIO(l_)
117839217Sgibbs		return result;
117939217Sgibbs	} else {
118039217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
118139217Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
118239217Sgibbs
118339217Sgibbs		ORDERKEY_MEM
118439217Sgibbs		ORDERKEY_RSSIZE
118539217Sgibbs		ORDERKEY_PCTCPU(p_)
118639217Sgibbs		ORDERKEY_CPTICKS(p_)
118739217Sgibbs		ORDERKEY_STATE(p_)
118839217Sgibbs		ORDERKEY_PRIO(p_)
118939217Sgibbs		return result;
119039217Sgibbs	}
119139217Sgibbs
119239217Sgibbs	return (result);
119339217Sgibbs}
119439217Sgibbs
119518781Sgibbs/* compare_state - the comparison function for sorting by process state */
119618781Sgibbs
119718781Sgibbsstatic int
119839217Sgibbscompare_state(pp1, pp2)
119939217Sgibbs	struct proc **pp1, **pp2;
120039217Sgibbs{
120139217Sgibbs	int result;
120239217Sgibbs	pctcpu lresult;
120339217Sgibbs
120439217Sgibbs	if (threadmode) {
120518781Sgibbs		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
120618781Sgibbs		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
120718781Sgibbs
120818781Sgibbs		ORDERKEY_STATE(l_)
120918781Sgibbs		ORDERKEY_PCTCPU(l_)
121039217Sgibbs		ORDERKEY_CPTICKS(l_)
121139217Sgibbs		ORDERKEY_PRIO(l_)
121218781Sgibbs		return result;
121318781Sgibbs	} else {
121418781Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
121518781Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
121618781Sgibbs
121718781Sgibbs		ORDERKEY_STATE(p_)
121839217Sgibbs		ORDERKEY_PCTCPU(p_)
121939217Sgibbs		ORDERKEY_CPTICKS(p_)
122018781Sgibbs		ORDERKEY_PRIO(p_)
122118781Sgibbs		ORDERKEY_RSSIZE
122218781Sgibbs		ORDERKEY_MEM
122318781Sgibbs		return result;
122418781Sgibbs	}
122518781Sgibbs
122639217Sgibbs	return (result);
122739217Sgibbs}
122818781Sgibbs
122918781Sgibbs/* compare_time - the comparison function for sorting by total CPU time */
123039217Sgibbs
123139217Sgibbsstatic int
123218781Sgibbscompare_time(pp1, pp2)
123318781Sgibbs	struct proc **pp1, **pp2;
123418781Sgibbs{
123539217Sgibbs	int result;
123618781Sgibbs	pctcpu lresult;
123718781Sgibbs
123818781Sgibbs	if (threadmode) {
123918781Sgibbs		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
124018781Sgibbs		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
124139217Sgibbs
124239217Sgibbs		ORDERKEY_CPTICKS(l_)
124339217Sgibbs		ORDERKEY_PCTCPU(l_)
124418781Sgibbs		ORDERKEY_STATE(l_)
124518781Sgibbs		ORDERKEY_PRIO(l_)
124618781Sgibbs		return result;
124718781Sgibbs	} else {
124839217Sgibbs		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
124939217Sgibbs		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
125018781Sgibbs
125118781Sgibbs		ORDERKEY_CPTICKS(p_)
125218781Sgibbs		ORDERKEY_PCTCPU(p_)
125318781Sgibbs		ORDERKEY_STATE(p_)
125418781Sgibbs		ORDERKEY_PRIO(p_)
125518781Sgibbs		ORDERKEY_MEM
125639217Sgibbs		ORDERKEY_RSSIZE
125718781Sgibbs		return result;
125818781Sgibbs	}
125918781Sgibbs
126018781Sgibbs	return (result);
126118781Sgibbs}
126218781Sgibbs
126318781Sgibbs
126439217Sgibbs/*
126518781Sgibbs * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
126618781Sgibbs *		the process does not exist.
126718781Sgibbs *		It is EXTREMLY IMPORTANT that this function work correctly.
126818781Sgibbs *		If top runs setuid root (as in SVR4), then this function
126918781Sgibbs *		is the only thing that stands in the way of a serious
127018781Sgibbs *		security problem.  It validates requests for the "kill"
127118781Sgibbs *		and "renice" commands.
127218781Sgibbs */
127318781Sgibbs
127418781Sgibbsint
127518781Sgibbsproc_owner(pid)
127618781Sgibbs	int pid;
127718781Sgibbs{
127818781Sgibbs	int cnt;
127918781Sgibbs	struct kinfo_proc2 **prefp;
128018781Sgibbs	struct kinfo_proc2 *pp;
128118781Sgibbs
128239217Sgibbs	if (threadmode)
128318781Sgibbs		return(-1);
128418781Sgibbs
128518781Sgibbs	prefp = pref;
128618781Sgibbs	cnt = pref_len;
128718781Sgibbs	while (--cnt >= 0) {
128818781Sgibbs		pp = *prefp++;
128918781Sgibbs		if (pp->p_pid == (pid_t)pid)
129018781Sgibbs			return(pp->p_ruid);
129118781Sgibbs	}
129218781Sgibbs	return(-1);
129318781Sgibbs}
129418781Sgibbs
129518781Sgibbs/*
129639217Sgibbs *  percentages(cnt, out, new, old, diffs) - calculate percentage change
129739217Sgibbs *	between array "old" and "new", putting the percentages i "out".
129818781Sgibbs *	"cnt" is size of each array and "diffs" is used for scratch space.
129918781Sgibbs *	The array "old" is updated on each call.
130039217Sgibbs *	The routine assumes modulo arithmetic.  This function is especially
130118781Sgibbs *	useful on BSD mchines for calculating CPU state percentages.
130218781Sgibbs */
130318781Sgibbs
130439217Sgibbsstatic void
130518781Sgibbspercentages64(cnt, out, new, old, diffs)
130618781Sgibbs	int cnt;
130718781Sgibbs	int *out;
130818781Sgibbs	u_int64_t *new;
130918781Sgibbs	u_int64_t *old;
131018781Sgibbs	u_int64_t *diffs;
131118781Sgibbs{
131218781Sgibbs	int i;
131318781Sgibbs	u_int64_t change;
131418781Sgibbs	u_int64_t total_change;
131518781Sgibbs	u_int64_t *dp;
131618781Sgibbs	u_int64_t half_total;
131718781Sgibbs
131818781Sgibbs	/* initialization */
131918781Sgibbs	total_change = 0;
132039217Sgibbs	dp = diffs;
132118781Sgibbs
132218781Sgibbs	/* calculate changes for each state and the overall change */
132318781Sgibbs	for (i = 0; i < cnt; i++) {
132418781Sgibbs		/*
132518781Sgibbs		 * Don't worry about wrapping - even at hz=1GHz, a
132618781Sgibbs		 * u_int64_t will last at least 544 years.
132718781Sgibbs		 */
132818781Sgibbs		change = *new - *old;
132918781Sgibbs		total_change += (*dp++ = change);
133018781Sgibbs		*old++ = *new++;
133118781Sgibbs	}
133218781Sgibbs
133318781Sgibbs	/* avoid divide by zero potential */
133418781Sgibbs	if (total_change == 0)
133518781Sgibbs		total_change = 1;
133618781Sgibbs
133718781Sgibbs	/* calculate percentages based on overall change, rounding up */
133818781Sgibbs	half_total = total_change / 2;
133918781Sgibbs	for (i = 0; i < cnt; i++)
134018781Sgibbs		*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
134118781Sgibbs}
134218781Sgibbs