xref: /netbsd-src/external/bsd/top/dist/machine/m_netbsd.c (revision 2026b7285b519b6985686c4f29b6309b5e58de6d)
1*2026b728Smrg /*	$NetBSD: m_netbsd.c,v 1.30 2024/02/04 05:43:05 mrg Exp $	*/
210dd2532Schristos 
310dd2532Schristos /*
410dd2532Schristos  * top - a top users display for Unix
510dd2532Schristos  *
610dd2532Schristos  * SYNOPSIS:  For a NetBSD-1.5 (or later) system
710dd2532Schristos  *
810dd2532Schristos  * DESCRIPTION:
910dd2532Schristos  * Originally written for BSD4.4 system by Christos Zoulas.
1010dd2532Schristos  * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider.
1110dd2532Schristos  * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn.
1210dd2532Schristos  * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green.
1310dd2532Schristos  * NetBSD-1.4/UVM port by matthew green.
1410dd2532Schristos  * NetBSD-1.5 port by Simon Burge.
1510dd2532Schristos  * NetBSD-1.6/UBC port by Tomas Svensson.
1610dd2532Schristos  * -
1710dd2532Schristos  * This is the machine-dependent module for NetBSD-1.5 and later
1810dd2532Schristos  * works for:
192b60e3f2Schristos  *	NetBSD-1.6ZC
2010dd2532Schristos  * and should work for:
212b60e3f2Schristos  *	NetBSD-2.0	(when released)
2210dd2532Schristos  * -
23369cd1d7Smrg  * NetBSD-4.0 updates from Christos Zoulas.
24369cd1d7Smrg  * NetBSD-5.0 updates from Andrew Doran, Mindaugas Rasiukevicius and
25369cd1d7Smrg  * Christos Zoulas.
26369cd1d7Smrg  * NetBSD-6.0 updates from matthew green, Christos Zoulas, and
27369cd1d7Smrg  * Mindaugas Rasiukevicius.
28369cd1d7Smrg  * NetBSD-8 updates from Leonardo Taccari.
29369cd1d7Smrg  * NetBSD-10 updates from Christos Zoulas and matthew green.
30369cd1d7Smrg  *
3110dd2532Schristos  * top does not need to be installed setuid or setgid with this module.
3210dd2532Schristos  *
3310dd2532Schristos  * LIBS: -lkvm
3410dd2532Schristos  *
352b60e3f2Schristos  * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR
362b60e3f2Schristos  *
3710dd2532Schristos  * AUTHORS:	Christos Zoulas <christos@ee.cornell.edu>
3810dd2532Schristos  *		Steven Wallace <swallace@freebsd.org>
3910dd2532Schristos  *		Wolfram Schneider <wosch@cs.tu-berlin.de>
4010dd2532Schristos  *		Arne Helme <arne@acm.org>
412b60e3f2Schristos  *		Luke Mewburn <lukem@NetBSD.org>
42*2026b728Smrg  *		matthew green <mrg@eterna23.net>
432b60e3f2Schristos  *		Simon Burge <simonb@NetBSD.org>
4410dd2532Schristos  *		Tomas Svensson <ts@unix1.net>
452b60e3f2Schristos  *		Andrew Doran <ad@NetBSD.org>
4610dd2532Schristos  *
4710dd2532Schristos  *
48*2026b728Smrg  * $Id: m_netbsd.c,v 1.30 2024/02/04 05:43:05 mrg Exp $
4910dd2532Schristos  */
502b60e3f2Schristos #include <sys/cdefs.h>
512b60e3f2Schristos 
522b60e3f2Schristos #ifndef lint
53*2026b728Smrg __RCSID("$NetBSD: m_netbsd.c,v 1.30 2024/02/04 05:43:05 mrg Exp $");
542b60e3f2Schristos #endif
5510dd2532Schristos 
5610dd2532Schristos #include <sys/param.h>
572277afb1Spara #include <sys/resource.h>
5810dd2532Schristos #include <sys/sysctl.h>
5910dd2532Schristos #include <sys/sched.h>
6010dd2532Schristos #include <sys/swap.h>
61369cd1d7Smrg #include <sys/socket.h>
62369cd1d7Smrg 
63369cd1d7Smrg #include <net/route.h>
6410dd2532Schristos 
6510dd2532Schristos #include <uvm/uvm_extern.h>
6610dd2532Schristos 
6710dd2532Schristos #include <err.h>
6810dd2532Schristos #include <errno.h>
6910dd2532Schristos #include <kvm.h>
7010dd2532Schristos #include <math.h>
7157f83fe0Schristos #include <ctype.h>
7210dd2532Schristos #include <nlist.h>
7310dd2532Schristos #include <stdio.h>
7410dd2532Schristos #include <stdlib.h>
7510dd2532Schristos #include <string.h>
7610dd2532Schristos #include <unistd.h>
7710dd2532Schristos 
7810dd2532Schristos #include "os.h"
7910dd2532Schristos #include "top.h"
8010dd2532Schristos #include "machine.h"
8110dd2532Schristos #include "utils.h"
8210dd2532Schristos #include "display.h"
8310dd2532Schristos #include "loadavg.h"
842b60e3f2Schristos #include "username.h"
8510dd2532Schristos 
8658f90407Schristos static void percentages64(int, int *, u_int64_t *, u_int64_t *,
8758f90407Schristos     u_int64_t *);
8810dd2532Schristos 
8910dd2532Schristos /* get_process_info passes back a handle.  This is what it looks like: */
9010dd2532Schristos 
9110dd2532Schristos struct handle {
9258f90407Schristos 	struct process_select *sel;
9310dd2532Schristos 	struct kinfo_proc2 **next_proc;	/* points to next valid proc pointer */
9410dd2532Schristos 	int remaining;		/* number of pointers remaining */
9510dd2532Schristos };
9610dd2532Schristos 
972b60e3f2Schristos /* define what weighted CPU is. */
982b60e3f2Schristos #define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \
992b60e3f2Schristos 			 ((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu))))
10010dd2532Schristos 
10110dd2532Schristos /* what we consider to be process size: */
102fcc02354Smrg /* NetBSD introduced p_vm_msize with RLIMIT_AS */
103fcc02354Smrg #ifdef RLIMIT_AS
104fcc02354Smrg #define PROCSIZE(pp) \
105fcc02354Smrg     ((pp)->p_vm_msize)
106fcc02354Smrg #else
10710dd2532Schristos #define PROCSIZE(pp) \
10810dd2532Schristos     ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
109fcc02354Smrg #endif
11010dd2532Schristos 
11110dd2532Schristos 
11210dd2532Schristos /*
11310dd2532Schristos  * These definitions control the format of the per-process area
11410dd2532Schristos  */
11510dd2532Schristos 
1162b60e3f2Schristos static char Proc_header[] =
11710dd2532Schristos   "  PID X        PRI NICE   SIZE   RES STATE       TIME   WCPU    CPU COMMAND";
11810dd2532Schristos /* 0123456   -- field to fill in starts at header+6 */
1192b60e3f2Schristos #define PROC_UNAME_START 6
12010dd2532Schristos #define Proc_format \
12157f83fe0Schristos 	"%5d %-8.8s %3d %4d%7s %5s %-9.9s%7s %5.*f%% %5.*f%% %s"
12210dd2532Schristos 
1232b60e3f2Schristos static char Thread_header[] =
1241d62298cSchristos   "  PID   LID X        PRI STATE       TIME   WCPU    CPU NAME      COMMAND";
1252b60e3f2Schristos /* 0123456   -- field to fill in starts at header+6 */
1262b60e3f2Schristos #define THREAD_UNAME_START 12
1272b60e3f2Schristos #define Thread_format \
12857f83fe0Schristos         "%5d %5d %-8.8s %3d %-9.9s%7s %5.2f%% %5.2f%% %-9.9s %s"
12910dd2532Schristos 
13010dd2532Schristos /*
13110dd2532Schristos  * Process state names for the "STATE" column of the display.
13210dd2532Schristos  */
13310dd2532Schristos 
13410dd2532Schristos const char *state_abbrev[] = {
1352b60e3f2Schristos 	"", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
13610dd2532Schristos };
13710dd2532Schristos 
13810dd2532Schristos static kvm_t *kd;
13910dd2532Schristos 
1402b60e3f2Schristos static char *(*userprint)(int);
1412b60e3f2Schristos 
14210dd2532Schristos /* these are retrieved from the kernel in _init */
14310dd2532Schristos 
14410dd2532Schristos static double logcpu;
14510dd2532Schristos static int hz;
14610dd2532Schristos static int ccpu;
14710dd2532Schristos 
1482b60e3f2Schristos /* these are for calculating CPU state percentages */
14910dd2532Schristos 
1502b60e3f2Schristos static int ncpu = 0;
1512b60e3f2Schristos static u_int64_t *cp_time;
1522b60e3f2Schristos static u_int64_t *cp_old;
1532b60e3f2Schristos static u_int64_t *cp_diff;
15410dd2532Schristos 
15510dd2532Schristos /* these are for detailing the process states */
15610dd2532Schristos 
15710dd2532Schristos int process_states[8];
158213e7ef1Schristos const char *procstatenames[] = {
1592b60e3f2Schristos 	"", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
1602b60e3f2Schristos 	" zombie, ", " dead, ", " on CPU, ",
16110dd2532Schristos 	NULL
16210dd2532Schristos };
16310dd2532Schristos 
1642b60e3f2Schristos /* these are for detailing the CPU states */
16510dd2532Schristos 
1662b60e3f2Schristos int *cpu_states;
167213e7ef1Schristos const char *cpustatenames[] = {
16810dd2532Schristos 	"user", "nice", "system", "interrupt", "idle", NULL
16910dd2532Schristos };
17010dd2532Schristos 
17110dd2532Schristos /* these are for detailing the memory statistics */
17210dd2532Schristos 
17310dd2532Schristos long memory_stats[7];
174213e7ef1Schristos const char *memorynames[] = {
17510dd2532Schristos 	"K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
17610dd2532Schristos 	"K Free, ",
17710dd2532Schristos 	NULL
17810dd2532Schristos };
17910dd2532Schristos 
180369cd1d7Smrg long swap_stats[9];
181213e7ef1Schristos const char *swapnames[] = {
18234763808Ssimonb 	"K Total, ", "K Used, ", "K Free ", " Pools: ", "K Used ",
183369cd1d7Smrg 	" Network: ", "K In, ", "K Out, ",
18410dd2532Schristos 	NULL
18510dd2532Schristos };
18610dd2532Schristos 
18710dd2532Schristos 
18810dd2532Schristos /* these are names given to allowed sorting orders -- first is default */
189213e7ef1Schristos const char *ordernames[] = {
19010dd2532Schristos 	"cpu",
19110dd2532Schristos 	"pri",
19210dd2532Schristos 	"res",
19310dd2532Schristos 	"size",
19410dd2532Schristos 	"state",
19510dd2532Schristos 	"time",
19614f5b40fSchristos 	"pid",
19714f5b40fSchristos 	"command",
19814f5b40fSchristos 	"username",
19910dd2532Schristos 	NULL
20010dd2532Schristos };
20110dd2532Schristos 
20210dd2532Schristos /* forward definitions for comparison functions */
20358f90407Schristos static int compare_cpu(struct proc **, struct proc **);
20458f90407Schristos static int compare_prio(struct proc **, struct proc **);
20558f90407Schristos static int compare_res(struct proc **, struct proc **);
20658f90407Schristos static int compare_size(struct proc **, struct proc **);
20758f90407Schristos static int compare_state(struct proc **, struct proc **);
20858f90407Schristos static int compare_time(struct proc **, struct proc **);
20958f90407Schristos static int compare_pid(struct proc **, struct proc **);
21058f90407Schristos static int compare_command(struct proc **, struct proc **);
21158f90407Schristos static int compare_username(struct proc **, struct proc **);
21210dd2532Schristos 
21358f90407Schristos int (*proc_compares[])(struct proc **, struct proc **) = {
21410dd2532Schristos 	compare_cpu,
21510dd2532Schristos 	compare_prio,
21610dd2532Schristos 	compare_res,
21710dd2532Schristos 	compare_size,
21810dd2532Schristos 	compare_state,
21910dd2532Schristos 	compare_time,
22014f5b40fSchristos 	compare_pid,
22114f5b40fSchristos 	compare_command,
22214f5b40fSchristos 	compare_username,
22310dd2532Schristos 	NULL
22410dd2532Schristos };
22510dd2532Schristos 
2262b60e3f2Schristos static char *format_next_lwp(caddr_t, char *(*)(int));
2272b60e3f2Schristos static char *format_next_proc(caddr_t, char *(*)(int));
2282b60e3f2Schristos 
2292b60e3f2Schristos static caddr_t get_proc_info(struct system_info *, struct process_select *,
2302b60e3f2Schristos 			     int (*)(struct proc **, struct proc **));
2312b60e3f2Schristos static caddr_t get_lwp_info(struct system_info *, struct process_select *,
2322b60e3f2Schristos 			    int (*)(struct proc **, struct proc **));
23310dd2532Schristos 
23410dd2532Schristos /* these are for keeping track of the proc array */
23510dd2532Schristos 
23610dd2532Schristos static int nproc;
23710dd2532Schristos static int onproc = -1;
2382b60e3f2Schristos static int nlwp;
2392b60e3f2Schristos static int onlwp = -1;
24010dd2532Schristos static int pref_len;
2412b60e3f2Schristos static int lref_len;
24210dd2532Schristos static struct kinfo_proc2 *pbase;
2432b60e3f2Schristos static struct kinfo_lwp *lbase;
24410dd2532Schristos static struct kinfo_proc2 **pref;
2452b60e3f2Schristos static struct kinfo_lwp **lref;
2462b60e3f2Schristos static int maxswap;
2472b60e3f2Schristos static void *swapp;
2482b60e3f2Schristos static int procgen;
2492b60e3f2Schristos static int thread_nproc;
2502b60e3f2Schristos static int thread_onproc = -1;
2512b60e3f2Schristos static struct kinfo_proc2 *thread_pbase;
25210dd2532Schristos 
25310dd2532Schristos /* these are for getting the memory statistics */
25410dd2532Schristos 
25510dd2532Schristos static int pageshift;		/* log base 2 of the pagesize */
25610dd2532Schristos 
2572b60e3f2Schristos int threadmode;
2582b60e3f2Schristos 
25910dd2532Schristos /* define pagetok in terms of pageshift */
26010dd2532Schristos 
26110dd2532Schristos #define pagetok(size) ((size) << pageshift)
26210dd2532Schristos 
26358f90407Schristos /*
26458f90407Schristos  * Print swapped processes as <pname> and
26558f90407Schristos  * system processes as [pname]
26658f90407Schristos  */
26758f90407Schristos static const char *
get_pretty(const struct kinfo_proc2 * pp)26858f90407Schristos get_pretty(const struct kinfo_proc2 *pp)
26958f90407Schristos {
27058f90407Schristos 	if ((pp->p_flag & P_SYSTEM) != 0)
27158f90407Schristos 		return "[]";
27258f90407Schristos 	if ((pp->p_flag & P_INMEM) == 0)
27358f90407Schristos 		return "<>";
27458f90407Schristos 	return "";
27558f90407Schristos }
27658f90407Schristos 
27758f90407Schristos static const char *
get_command(const struct process_select * sel,struct kinfo_proc2 * pp)27858f90407Schristos get_command(const struct process_select *sel, struct kinfo_proc2 *pp)
27958f90407Schristos {
28058f90407Schristos 	static char cmdbuf[128];
28158f90407Schristos 	const char *pretty;
28258f90407Schristos 	char **argv;
28358f90407Schristos 	if (pp == NULL)
28458f90407Schristos 		return "<gone>";
28558f90407Schristos 	pretty = get_pretty(pp);
28658f90407Schristos 
28758f90407Schristos 	if (sel->fullcmd == 0 || kd == NULL || (argv = kvm_getargv2(kd, pp,
28858f90407Schristos 	    sizeof(cmdbuf))) == NULL) {
28958f90407Schristos 		if (pretty[0] != '\0' && pp->p_comm[0] != pretty[0])
29058f90407Schristos 			snprintf(cmdbuf, sizeof(cmdbuf), "%c%s%c", pretty[0],
29158f90407Schristos 			    printable(pp->p_comm), pretty[1]);
29258f90407Schristos 		else
29358f90407Schristos 			strlcpy(cmdbuf, printable(pp->p_comm), sizeof(cmdbuf));
29458f90407Schristos 	} else {
29558f90407Schristos 		char *d = cmdbuf;
29658f90407Schristos 		if (pretty[0] != '\0' && argv[0][0] != pretty[0])
29758f90407Schristos 			*d++ = pretty[0];
29858f90407Schristos 		while (*argv) {
29958f90407Schristos 			const char *s = printable(*argv++);
30058f90407Schristos 			while (d < cmdbuf + sizeof(cmdbuf) - 2 &&
30158f90407Schristos 			    (*d++ = *s++) != '\0')
30258f90407Schristos 				continue;
30358f90407Schristos 			if (d > cmdbuf && d < cmdbuf + sizeof(cmdbuf) - 2 &&
30458f90407Schristos 			    d[-1] == '\0')
30558f90407Schristos 				d[-1] = ' ';
30658f90407Schristos 		}
30758f90407Schristos 		if (pretty[0] != '\0' && pretty[0] == cmdbuf[0])
30858f90407Schristos 			*d++ = pretty[1];
30958f90407Schristos 		*d++ = '\0';
31058f90407Schristos 	}
31158f90407Schristos 	return cmdbuf;
31258f90407Schristos }
31358f90407Schristos 
31410dd2532Schristos int
machine_init(statics)31510dd2532Schristos machine_init(statics)
31610dd2532Schristos 	struct statics *statics;
31710dd2532Schristos {
31810dd2532Schristos 	int pagesize;
31910dd2532Schristos 	int mib[2];
32010dd2532Schristos 	size_t size;
32110dd2532Schristos 	struct clockinfo clockinfo;
322d4305dc7Skre 	struct timespec boottime;
32310dd2532Schristos 
32410dd2532Schristos 	if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
32510dd2532Schristos 		return -1;
32610dd2532Schristos 
3272b60e3f2Schristos 	mib[0] = CTL_HW;
3282b60e3f2Schristos 	mib[1] = HW_NCPU;
3292b60e3f2Schristos 	size = sizeof(ncpu);
3302b60e3f2Schristos 	if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) {
3312b60e3f2Schristos 		fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n",
3322b60e3f2Schristos 		    strerror(errno));
3332b60e3f2Schristos 		return(-1);
3342b60e3f2Schristos 	}
3352b60e3f2Schristos 	statics->ncpu = ncpu;
3362b60e3f2Schristos 	cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu);
3372b60e3f2Schristos 	mib[0] = CTL_KERN;
3382b60e3f2Schristos 	mib[1] = KERN_CP_TIME;
3392b60e3f2Schristos 	size = sizeof(cp_time[0]) * CPUSTATES * ncpu;
3402b60e3f2Schristos 	if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) {
3412b60e3f2Schristos 		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
3422b60e3f2Schristos 		    strerror(errno));
3432b60e3f2Schristos 		return(-1);
3442b60e3f2Schristos 	}
3452b60e3f2Schristos 
3462b60e3f2Schristos 	/* Handle old call that returned only aggregate */
3472b60e3f2Schristos 	if (size == sizeof(cp_time[0]) * CPUSTATES)
3482b60e3f2Schristos 		ncpu = 1;
3492b60e3f2Schristos 
3502b60e3f2Schristos 	cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu);
351ea3d16d0Skamil 	cp_old = calloc(CPUSTATES * ncpu, sizeof(cp_old[0]));
3522b60e3f2Schristos 	cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu);
3532b60e3f2Schristos 	if (cpu_states == NULL || cp_time == NULL || cp_old == NULL ||
3542b60e3f2Schristos 	    cp_diff == NULL) {
3552b60e3f2Schristos 		fprintf(stderr, "top: machine_init: %s\n",
3562b60e3f2Schristos 		    strerror(errno));
3572b60e3f2Schristos 		return(-1);
3582b60e3f2Schristos 	}
3592b60e3f2Schristos 
36010dd2532Schristos 	mib[0] = CTL_KERN;
36110dd2532Schristos 	mib[1] = KERN_CCPU;
36210dd2532Schristos 	size = sizeof(ccpu);
36310dd2532Schristos 	if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) {
36410dd2532Schristos 		fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n",
36510dd2532Schristos 		    strerror(errno));
36610dd2532Schristos 		return(-1);
36710dd2532Schristos 	}
36810dd2532Schristos 
36910dd2532Schristos 	mib[0] = CTL_KERN;
37010dd2532Schristos 	mib[1] = KERN_CLOCKRATE;
37110dd2532Schristos 	size = sizeof(clockinfo);
37210dd2532Schristos 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) {
37310dd2532Schristos 		fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n",
37410dd2532Schristos 		    strerror(errno));
37510dd2532Schristos 		return(-1);
37610dd2532Schristos 	}
37710dd2532Schristos 	hz = clockinfo.stathz;
37810dd2532Schristos 
37910dd2532Schristos 	/* this is used in calculating WCPU -- calculate it ahead of time */
38010dd2532Schristos 	logcpu = log(loaddouble(ccpu));
38110dd2532Schristos 
38210dd2532Schristos 	pbase = NULL;
3832b60e3f2Schristos 	lbase = NULL;
38410dd2532Schristos 	pref = NULL;
38510dd2532Schristos 	nproc = 0;
38610dd2532Schristos 	onproc = -1;
3872b60e3f2Schristos 	nlwp = 0;
3882b60e3f2Schristos 	onlwp = -1;
38910dd2532Schristos 	/* get the page size with "getpagesize" and calculate pageshift from it */
39010dd2532Schristos 	pagesize = getpagesize();
39110dd2532Schristos 	pageshift = 0;
39210dd2532Schristos 	while (pagesize > 1) {
39310dd2532Schristos 		pageshift++;
39410dd2532Schristos 		pagesize >>= 1;
39510dd2532Schristos 	}
39610dd2532Schristos 
39710dd2532Schristos 	/* we only need the amount of log(2)1024 for our conversion */
39810dd2532Schristos 	pageshift -= LOG1024;
39910dd2532Schristos 
40010dd2532Schristos 	/* fill in the statics information */
4012b60e3f2Schristos #ifdef notyet
4022b60e3f2Schristos 	statics->ncpu = ncpu;
4032b60e3f2Schristos #endif
40410dd2532Schristos 	statics->procstate_names = procstatenames;
40510dd2532Schristos 	statics->cpustate_names = cpustatenames;
40610dd2532Schristos 	statics->memory_names = memorynames;
40710dd2532Schristos 	statics->swap_names = swapnames;
40810dd2532Schristos 	statics->order_names = ordernames;
4092b60e3f2Schristos 	statics->flags.threads = 1;
41058f90407Schristos 	statics->flags.fullcmds = 1;
41110dd2532Schristos 
4122b60e3f2Schristos 	mib[0] = CTL_KERN;
4132b60e3f2Schristos 	mib[1] = KERN_BOOTTIME;
4142b60e3f2Schristos 	size = sizeof(boottime);
4152b60e3f2Schristos 	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
4162b60e3f2Schristos     	    boottime.tv_sec != 0)
4172b60e3f2Schristos 		statics->boottime = boottime.tv_sec;
4182b60e3f2Schristos 	else
4192b60e3f2Schristos 		statics->boottime = 0;
42010dd2532Schristos 	/* all done! */
42110dd2532Schristos 	return(0);
42210dd2532Schristos }
42310dd2532Schristos 
42410dd2532Schristos char *
format_process_header(struct process_select * sel,caddr_t handle,int count)4252b60e3f2Schristos format_process_header(struct process_select *sel, caddr_t handle, int count)
42610dd2532Schristos 
4272b60e3f2Schristos {
4282b60e3f2Schristos 	char *header;
4292b60e3f2Schristos 	char *ptr;
4302b60e3f2Schristos 	const char *uname_field = sel->usernames ? "USERNAME" : "    UID ";
4312b60e3f2Schristos 
4322b60e3f2Schristos 	if (sel->threads) {
4332b60e3f2Schristos 		header = Thread_header;
4342b60e3f2Schristos 		ptr = header + THREAD_UNAME_START;
4352b60e3f2Schristos 	} else {
4362b60e3f2Schristos 		header = Proc_header;
4372b60e3f2Schristos 		ptr = header + PROC_UNAME_START;
4382b60e3f2Schristos 	}
4392b60e3f2Schristos 
4402b60e3f2Schristos 	while (*uname_field != '\0') {
4412b60e3f2Schristos 		*ptr++ = *uname_field++;
4422b60e3f2Schristos 	}
4432b60e3f2Schristos 
4442b60e3f2Schristos 	return(header);
4452b60e3f2Schristos }
4462b60e3f2Schristos 
4472b60e3f2Schristos char *
format_header(char * uname_field)4482b60e3f2Schristos format_header(char *uname_field)
4492b60e3f2Schristos {
4502b60e3f2Schristos 	char *header = Proc_header;
4512b60e3f2Schristos 	char *ptr = header + PROC_UNAME_START;
4522b60e3f2Schristos 
45310dd2532Schristos 	while (*uname_field != '\0') {
45410dd2532Schristos 		*ptr++ = *uname_field++;
45510dd2532Schristos 	}
45610dd2532Schristos 
45710dd2532Schristos 	return(header);
45810dd2532Schristos }
45910dd2532Schristos 
460369cd1d7Smrg static void
get_network_kilobytes(long * kb_in,long * kb_out)461369cd1d7Smrg get_network_kilobytes(long *kb_in, long *kb_out)
462369cd1d7Smrg {
463369cd1d7Smrg 	struct if_msghdr *ifm;
464369cd1d7Smrg 	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
465369cd1d7Smrg 	struct rt_msghdr *rtm;
466369cd1d7Smrg 	struct if_data *ifd = NULL;
467369cd1d7Smrg 	static char *buf = NULL;
468369cd1d7Smrg 	static size_t olen;
469369cd1d7Smrg 	char *next, *lim;
470369cd1d7Smrg 	size_t len;
471369cd1d7Smrg 	static uint64_t last_bytes_in;
472369cd1d7Smrg 	static uint64_t last_bytes_out;
473369cd1d7Smrg 	uint64_t cur_bytes_in = 0;
474369cd1d7Smrg 	uint64_t cur_bytes_out = 0;
475369cd1d7Smrg 
476369cd1d7Smrg 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
477369cd1d7Smrg 		err(1, "sysctl");
478369cd1d7Smrg 	if (len > olen) {
479369cd1d7Smrg 		free(buf);
480369cd1d7Smrg 		if ((buf = malloc(len)) == NULL)
481369cd1d7Smrg 			err(1, NULL);
482369cd1d7Smrg 		olen = len;
483369cd1d7Smrg 	}
484369cd1d7Smrg 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
485369cd1d7Smrg 		err(1, "sysctl");
486369cd1d7Smrg 
487369cd1d7Smrg 	lim = buf + len;
488369cd1d7Smrg 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
489369cd1d7Smrg 		rtm = (struct rt_msghdr *)next;
490369cd1d7Smrg 		if (rtm->rtm_version != RTM_VERSION)
491369cd1d7Smrg 			continue;
492369cd1d7Smrg 		switch (rtm->rtm_type) {
493369cd1d7Smrg 		case RTM_IFINFO:
494369cd1d7Smrg 			ifm = (struct if_msghdr *)next;
495369cd1d7Smrg 			ifd = &ifm->ifm_data;
496369cd1d7Smrg 
497369cd1d7Smrg 			cur_bytes_in += ifd->ifi_ibytes;
498369cd1d7Smrg 			cur_bytes_out += ifd->ifi_obytes;
499369cd1d7Smrg 			break;
500369cd1d7Smrg 		}
501369cd1d7Smrg 	}
502369cd1d7Smrg 
503369cd1d7Smrg 	*kb_in = (cur_bytes_in - last_bytes_in) / 1024;
504369cd1d7Smrg 	*kb_out = (cur_bytes_out - last_bytes_out) / 1024;
505369cd1d7Smrg 	last_bytes_in = cur_bytes_in;
506369cd1d7Smrg 	last_bytes_out = cur_bytes_out;
507369cd1d7Smrg }
508369cd1d7Smrg 
50910dd2532Schristos void
get_system_info(struct system_info * si)510213e7ef1Schristos get_system_info(struct system_info *si)
51110dd2532Schristos {
51210dd2532Schristos 	size_t ssize;
513369cd1d7Smrg 	int mib[6];
51410dd2532Schristos 	struct uvmexp_sysctl uvmexp;
5152b60e3f2Schristos 	struct swapent *sep;
51610dd2532Schristos 	u_int64_t totalsize, totalinuse;
5172b60e3f2Schristos 	int size, inuse, ncounted, i;
51810dd2532Schristos 	int rnswap, nswap;
51910dd2532Schristos 
52010dd2532Schristos 	mib[0] = CTL_KERN;
52110dd2532Schristos 	mib[1] = KERN_CP_TIME;
5222b60e3f2Schristos 	ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu;
52310dd2532Schristos 	if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) {
52410dd2532Schristos 		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
52510dd2532Schristos 		    strerror(errno));
52610dd2532Schristos 		quit(23);
52710dd2532Schristos 	}
52810dd2532Schristos 
52910dd2532Schristos 	if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) {
530213e7ef1Schristos 		int j;
53110dd2532Schristos 
53210dd2532Schristos 		warn("can't getloadavg");
533213e7ef1Schristos 		for (j = 0; j < NUM_AVERAGES; j++)
534213e7ef1Schristos 			si->load_avg[j] = 0.0;
53510dd2532Schristos 	}
53610dd2532Schristos 
53710dd2532Schristos 	/* convert cp_time counts to percentages */
5382b60e3f2Schristos 	for (i = 0; i < ncpu; i++) {
5392b60e3f2Schristos 	    int j = i * CPUSTATES;
5402b60e3f2Schristos 	    percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j,
5412b60e3f2Schristos 		cp_diff + j);
5422b60e3f2Schristos 	}
54310dd2532Schristos 
54410dd2532Schristos 	mib[0] = CTL_VM;
54510dd2532Schristos 	mib[1] = VM_UVMEXP2;
54610dd2532Schristos 	ssize = sizeof(uvmexp);
54710dd2532Schristos 	if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) {
54810dd2532Schristos 		fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n",
54910dd2532Schristos 		    strerror(errno));
55010dd2532Schristos 		quit(23);
55110dd2532Schristos 	}
55210dd2532Schristos 
55310dd2532Schristos 	/* convert memory stats to Kbytes */
55410dd2532Schristos 	memory_stats[0] = pagetok(uvmexp.active);
55510dd2532Schristos 	memory_stats[1] = pagetok(uvmexp.inactive);
55610dd2532Schristos 	memory_stats[2] = pagetok(uvmexp.wired);
55710dd2532Schristos 	memory_stats[3] = pagetok(uvmexp.execpages);
55810dd2532Schristos 	memory_stats[4] = pagetok(uvmexp.filepages);
55910dd2532Schristos 	memory_stats[5] = pagetok(uvmexp.free);
56010dd2532Schristos 
56110dd2532Schristos 	swap_stats[0] = swap_stats[1] = swap_stats[2] = 0;
56210dd2532Schristos 
56310dd2532Schristos 	do {
56410dd2532Schristos 		nswap = swapctl(SWAP_NSWAP, 0, 0);
56510dd2532Schristos 		if (nswap < 1)
56610dd2532Schristos 			break;
5672b60e3f2Schristos 		if (nswap > maxswap) {
5682b60e3f2Schristos 			if (swapp)
5692b60e3f2Schristos 				free(swapp);
5702b60e3f2Schristos 			swapp = sep = malloc(nswap * sizeof(*sep));
57110dd2532Schristos 			if (sep == NULL)
57210dd2532Schristos 				break;
5732b60e3f2Schristos 			maxswap = nswap;
5742b60e3f2Schristos 		} else
5752b60e3f2Schristos 			sep = swapp;
57610dd2532Schristos 		rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
57710dd2532Schristos 		if (nswap != rnswap)
57810dd2532Schristos 			break;
57910dd2532Schristos 
58010dd2532Schristos 		totalsize = totalinuse = ncounted = 0;
58110dd2532Schristos 		for (; rnswap-- > 0; sep++) {
58210dd2532Schristos 			ncounted++;
58310dd2532Schristos 			size = sep->se_nblks;
58410dd2532Schristos 			inuse = sep->se_inuse;
58510dd2532Schristos 			totalsize += size;
58610dd2532Schristos 			totalinuse += inuse;
58710dd2532Schristos 		}
58810dd2532Schristos 		swap_stats[0] = dbtob(totalsize) / 1024;
58910dd2532Schristos 		swap_stats[1] = dbtob(totalinuse) / 1024;
59010dd2532Schristos 		swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1];
59110dd2532Schristos 	} while (0);
59210dd2532Schristos 
593fc98c499Smrg 	swap_stats[4] = pagetok(uvmexp.poolpages);
594fc98c499Smrg 
595369cd1d7Smrg 	get_network_kilobytes(&swap_stats[6], &swap_stats[7]);
596369cd1d7Smrg 
59710dd2532Schristos 	memory_stats[6] = -1;
598369cd1d7Smrg 	swap_stats[3] = swap_stats[5] = swap_stats[8] = -1;
59910dd2532Schristos 
60010dd2532Schristos 	/* set arrays and strings */
60110dd2532Schristos 	si->cpustates = cpu_states;
60210dd2532Schristos 	si->memory = memory_stats;
60310dd2532Schristos 	si->swap = swap_stats;
60410dd2532Schristos 	si->last_pid = -1;
6052b60e3f2Schristos 
60610dd2532Schristos }
60710dd2532Schristos 
6082b60e3f2Schristos static struct kinfo_proc2 *
proc_from_thread(struct kinfo_lwp * pl)6092b60e3f2Schristos proc_from_thread(struct kinfo_lwp *pl)
6102b60e3f2Schristos {
6112b60e3f2Schristos 	struct kinfo_proc2 *pp = thread_pbase;
6122b60e3f2Schristos 	int i;
6132b60e3f2Schristos 
6142b60e3f2Schristos 	for (i = 0; i < thread_nproc; i++, pp++)
615213e7ef1Schristos 		if ((pid_t)pp->p_pid == (pid_t)pl->l_pid)
6162b60e3f2Schristos 			return pp;
6172b60e3f2Schristos 	return NULL;
6182b60e3f2Schristos }
6192b60e3f2Schristos 
6202b60e3f2Schristos static int
uid_from_thread(struct kinfo_lwp * pl)6212b60e3f2Schristos uid_from_thread(struct kinfo_lwp *pl)
6222b60e3f2Schristos {
6232b60e3f2Schristos 	struct kinfo_proc2 *pp;
6242b60e3f2Schristos 
6252b60e3f2Schristos 	if ((pp = proc_from_thread(pl)) == NULL)
6262b60e3f2Schristos 		return -1;
6272b60e3f2Schristos 	return pp->p_ruid;
6282b60e3f2Schristos }
62910dd2532Schristos 
63010dd2532Schristos caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int c)6312b60e3f2Schristos get_process_info(struct system_info *si, struct process_select *sel, int c)
6322b60e3f2Schristos {
6332b60e3f2Schristos 	userprint = sel->usernames ? username : itoa7;
6342b60e3f2Schristos 
6352b60e3f2Schristos 	if ((threadmode = sel->threads) != 0)
6362b60e3f2Schristos 		return get_lwp_info(si, sel, proc_compares[c]);
6372b60e3f2Schristos 	else
6382b60e3f2Schristos 		return get_proc_info(si, sel, proc_compares[c]);
6392b60e3f2Schristos }
6402b60e3f2Schristos 
6412b60e3f2Schristos static caddr_t
get_proc_info(struct system_info * si,struct process_select * sel,int (* compare)(struct proc **,struct proc **))6422b60e3f2Schristos get_proc_info(struct system_info *si, struct process_select *sel,
6432b60e3f2Schristos 	      int (*compare)(struct proc **, struct proc **))
64410dd2532Schristos {
64510dd2532Schristos 	int i;
64610dd2532Schristos 	int total_procs;
64710dd2532Schristos 	int active_procs;
6482b60e3f2Schristos 	struct kinfo_proc2 **prefp, **n;
64910dd2532Schristos 	struct kinfo_proc2 *pp;
6502b60e3f2Schristos 	int op, arg;
65110dd2532Schristos 
65210dd2532Schristos 	/* these are copied out of sel for speed */
65310dd2532Schristos 	int show_idle;
65410dd2532Schristos 	int show_system;
65510dd2532Schristos 	int show_uid;
6562b0c6991Sleot 	char *show_command;
65710dd2532Schristos 
65810dd2532Schristos 	static struct handle handle;
65910dd2532Schristos 
6602b60e3f2Schristos 	procgen++;
66110dd2532Schristos 
662213e7ef1Schristos 	if (sel->pid == (pid_t)-1) {
6632b60e3f2Schristos 		op = KERN_PROC_ALL;
6642b60e3f2Schristos 		arg = 0;
6652b60e3f2Schristos 	} else {
6662b60e3f2Schristos 		op = KERN_PROC_PID;
6672b60e3f2Schristos 		arg = sel->pid;
6682b60e3f2Schristos 	}
6692b60e3f2Schristos 
6702b60e3f2Schristos 	pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc);
6712b60e3f2Schristos 	if (pbase == NULL) {
672213e7ef1Schristos 		if (sel->pid != (pid_t)-1) {
6732b60e3f2Schristos 			nproc = 0;
67414f5b40fSchristos 		} else {
67510dd2532Schristos 			(void) fprintf(stderr, "top: Out of memory.\n");
67610dd2532Schristos 			quit(23);
67710dd2532Schristos 		}
6782b60e3f2Schristos 	}
6792b60e3f2Schristos 	if (nproc > onproc) {
6802b60e3f2Schristos 		n = (struct kinfo_proc2 **) realloc(pref,
6812b60e3f2Schristos 		    sizeof(struct kinfo_proc2 *) * nproc);
6822b60e3f2Schristos 		if (n == NULL) {
6832b60e3f2Schristos 			(void) fprintf(stderr, "top: Out of memory.\n");
6842b60e3f2Schristos 			quit(23);
6852b60e3f2Schristos 		}
6862b60e3f2Schristos 		pref = n;
6872b60e3f2Schristos 		onproc = nproc;
6882b60e3f2Schristos 	}
68910dd2532Schristos 	/* get a pointer to the states summary array */
69010dd2532Schristos 	si->procstates = process_states;
69110dd2532Schristos 
69210dd2532Schristos 	/* set up flags which define what we are going to select */
69310dd2532Schristos 	show_idle = sel->idle;
69410dd2532Schristos 	show_system = sel->system;
69510dd2532Schristos 	show_uid = sel->uid != -1;
6962b0c6991Sleot 	show_command = sel->command;
69710dd2532Schristos 
69810dd2532Schristos 	/* count up process states and get pointers to interesting procs */
69910dd2532Schristos 	total_procs = 0;
70010dd2532Schristos 	active_procs = 0;
70110dd2532Schristos 	memset((char *)process_states, 0, sizeof(process_states));
70210dd2532Schristos 	prefp = pref;
70310dd2532Schristos 	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
70410dd2532Schristos 
70510dd2532Schristos 		/*
70610dd2532Schristos 		 * Place pointers to each valid proc structure in pref[].
70710dd2532Schristos 		 * Process slots that are actually in use have a non-zero
70810dd2532Schristos 		 * status field.  Processes with P_SYSTEM set are system
70910dd2532Schristos 		 * processes---these get ignored unless show_sysprocs is set.
71010dd2532Schristos 		 */
71110dd2532Schristos 		if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) {
71210dd2532Schristos 			total_procs++;
71310dd2532Schristos 			process_states[(unsigned char) pp->p_stat]++;
7142b60e3f2Schristos 			if (pp->p_stat != LSZOMB &&
71510dd2532Schristos 			    (show_idle || (pp->p_pctcpu != 0) ||
7162b60e3f2Schristos 			    (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) &&
7172b0c6991Sleot 			    (!show_uid || pp->p_ruid == (uid_t)sel->uid) &&
7182b0c6991Sleot 			    (!show_command ||
7192b0c6991Sleot 			     strstr(get_command(sel, pp),
7202b0c6991Sleot 				 show_command) != NULL)) {
72110dd2532Schristos 					*prefp++ = pp;
72210dd2532Schristos 					active_procs++;
72310dd2532Schristos 			}
72410dd2532Schristos 		}
72510dd2532Schristos 	}
72610dd2532Schristos 
72710dd2532Schristos 	/* if requested, sort the "interesting" processes */
7282b60e3f2Schristos 	if (compare != NULL) {
72910dd2532Schristos 		qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *),
7302b60e3f2Schristos 		    (int (*)(const void *, const void *))compare);
7312b60e3f2Schristos 	}
73210dd2532Schristos 
73310dd2532Schristos 	/* remember active and total counts */
73410dd2532Schristos 	si->p_total = total_procs;
73510dd2532Schristos 	si->p_active = pref_len = active_procs;
73610dd2532Schristos 
73710dd2532Schristos 	/* pass back a handle */
73810dd2532Schristos 	handle.next_proc = pref;
73910dd2532Schristos 	handle.remaining = active_procs;
74058f90407Schristos 	handle.sel = sel;
74110dd2532Schristos 	return((caddr_t)&handle);
74210dd2532Schristos }
74310dd2532Schristos 
7442b60e3f2Schristos static caddr_t
get_lwp_info(struct system_info * si,struct process_select * sel,int (* compare)(struct proc **,struct proc **))7452b60e3f2Schristos get_lwp_info(struct system_info *si, struct process_select *sel,
7462b60e3f2Schristos 	     int (*compare)(struct proc **, struct proc **))
7472b60e3f2Schristos {
7482b60e3f2Schristos 	int i;
7492b60e3f2Schristos 	int total_lwps;
7502b60e3f2Schristos 	int active_lwps;
7512b60e3f2Schristos 	struct kinfo_lwp **lrefp, **n;
7522b60e3f2Schristos 	struct kinfo_lwp *lp;
7532b60e3f2Schristos 	struct kinfo_proc2 *pp;
7542b60e3f2Schristos 
7552b60e3f2Schristos 	/* these are copied out of sel for speed */
7562b60e3f2Schristos 	int show_idle;
7572b60e3f2Schristos 	int show_system;
7582b60e3f2Schristos 	int show_uid;
7592b0c6991Sleot 	char *show_command;
7602b60e3f2Schristos 
7612b60e3f2Schristos 	static struct handle handle;
7622b60e3f2Schristos 
7632b60e3f2Schristos 	pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
7642b60e3f2Schristos 	    &thread_nproc);
7652b60e3f2Schristos 	if (pp == NULL) {
7662b60e3f2Schristos 		(void) fprintf(stderr, "top: Out of memory.\n");
7672b60e3f2Schristos 		quit(23);
7682b60e3f2Schristos 	}
7692b60e3f2Schristos 	if (thread_pbase == NULL || thread_nproc != thread_onproc) {
7702b60e3f2Schristos 		free(thread_pbase);
7712b60e3f2Schristos 		thread_onproc = thread_nproc;
7722b60e3f2Schristos 		thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc);
7732b60e3f2Schristos 		if (thread_pbase == NULL) {
7742b60e3f2Schristos 			(void) fprintf(stderr, "top: Out of memory.\n");
7752b60e3f2Schristos 			quit(23);
7762b60e3f2Schristos 		}
7772b60e3f2Schristos 	}
7782b60e3f2Schristos 	memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc);
7792b60e3f2Schristos 
7802b60e3f2Schristos 	lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp);
7812b60e3f2Schristos 	if (lbase == NULL) {
7822b60e3f2Schristos #ifdef notyet
783213e7ef1Schristos 		if (sel->pid != (pid_t)-1) {
7842b60e3f2Schristos 			nproc = 0;
7852b60e3f2Schristos 			nlwp = 0;
7862b60e3f2Schristos 		}
7872b60e3f2Schristos 		else
7882b60e3f2Schristos #endif
7892b60e3f2Schristos 		{
7902b60e3f2Schristos 			(void) fprintf(stderr, "top: Out of memory.\n");
7912b60e3f2Schristos 			quit(23);
7922b60e3f2Schristos 		}
7932b60e3f2Schristos 	}
7942b60e3f2Schristos 	if (nlwp > onlwp) {
7952b60e3f2Schristos 		n = (struct kinfo_lwp **) realloc(lref,
7962b60e3f2Schristos 		    sizeof(struct kinfo_lwp *) * nlwp);
7972b60e3f2Schristos 		if (n == NULL) {
7982b60e3f2Schristos 			(void) fprintf(stderr, "top: Out of memory.\n");
7992b60e3f2Schristos 			quit(23);
8002b60e3f2Schristos 		}
8012b60e3f2Schristos 		lref = n;
8022b60e3f2Schristos 		onlwp = nlwp;
8032b60e3f2Schristos 	}
8042b60e3f2Schristos 	/* get a pointer to the states summary array */
8052b60e3f2Schristos 	si->procstates = process_states;
8062b60e3f2Schristos 
8072b60e3f2Schristos 	/* set up flags which define what we are going to select */
8082b60e3f2Schristos 	show_idle = sel->idle;
8092b60e3f2Schristos 	show_system = sel->system;
8102b60e3f2Schristos 	show_uid = sel->uid != -1;
8112b0c6991Sleot 	show_command = sel->command;
8122b60e3f2Schristos 
8132b60e3f2Schristos 	/* count up thread states and get pointers to interesting threads */
8142b60e3f2Schristos 	total_lwps = 0;
8152b60e3f2Schristos 	active_lwps = 0;
8162b60e3f2Schristos 	memset((char *)process_states, 0, sizeof(process_states));
8172b60e3f2Schristos 	lrefp = lref;
8182b60e3f2Schristos 	for (lp = lbase, i = 0; i < nlwp; lp++, i++) {
819213e7ef1Schristos 		if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid)
8201fb97e15Schristos 			continue;
8212b60e3f2Schristos 
8222b60e3f2Schristos 		/*
8232b60e3f2Schristos 		 * Place pointers to each valid lwp structure in lref[].
8242b60e3f2Schristos 		 * thread slots that are actually in use have a non-zero
8252b60e3f2Schristos 		 * status field.  threads with L_SYSTEM set are system
8262b60e3f2Schristos 		 * threads---these get ignored unless show_sysprocs is set.
8272b60e3f2Schristos 		 */
82850f07ffdSmrg 		if (lp->l_stat != 0 &&
82950f07ffdSmrg 		    (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) {
8302b60e3f2Schristos 			total_lwps++;
8312b60e3f2Schristos 			process_states[(unsigned char) lp->l_stat]++;
8322b60e3f2Schristos 			if (lp->l_stat != LSZOMB &&
8332b60e3f2Schristos 			    (show_idle || (lp->l_pctcpu != 0) ||
8342b60e3f2Schristos 			     (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) &&
8352b0c6991Sleot 			    (!show_uid || uid_from_thread(lp) == sel->uid) &&
8362b0c6991Sleot 			    (!show_command ||
83750f07ffdSmrg 			     ((pp = proc_from_thread(lp)) != NULL &&
83850f07ffdSmrg 			      strstr(get_command(sel, pp),
83950f07ffdSmrg 				     show_command) != NULL))) {
8402b60e3f2Schristos 				*lrefp++ = lp;
8412b60e3f2Schristos 				active_lwps++;
8422b60e3f2Schristos 			}
8432b60e3f2Schristos 		}
8442b60e3f2Schristos 	}
8452b60e3f2Schristos 
8462b60e3f2Schristos 	/* if requested, sort the "interesting" threads */
8472b60e3f2Schristos 	if (compare != NULL) {
8482b60e3f2Schristos 		qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *),
8492b60e3f2Schristos 		    (int (*)(const void *, const void *))compare);
8502b60e3f2Schristos 	}
8512b60e3f2Schristos 
8522b60e3f2Schristos 	/* remember active and total counts */
8532b60e3f2Schristos 	si->p_total = total_lwps;
8542b60e3f2Schristos 	si->p_active = lref_len = active_lwps;
8552b60e3f2Schristos 
8562b60e3f2Schristos 	/* pass back a handle */
8572b60e3f2Schristos 	handle.next_proc = (struct kinfo_proc2 **)lref;
8582b60e3f2Schristos 	handle.remaining = active_lwps;
85958f90407Schristos 	handle.sel = sel;
8602b60e3f2Schristos 
8612b60e3f2Schristos 	return((caddr_t)&handle);
8622b60e3f2Schristos }
86310dd2532Schristos 
86410dd2532Schristos char *
format_next_process(caddr_t handle,char * (* get_userid)(int))8652b60e3f2Schristos format_next_process(caddr_t handle, char *(*get_userid)(int))
8662b60e3f2Schristos {
8672b60e3f2Schristos 
8682b60e3f2Schristos 	if (threadmode)
8692b60e3f2Schristos 		return format_next_lwp(handle, get_userid);
8702b60e3f2Schristos 	else
8712b60e3f2Schristos 		return format_next_proc(handle, get_userid);
8722b60e3f2Schristos }
8732b60e3f2Schristos 
8742b60e3f2Schristos 
8752b60e3f2Schristos char *
format_next_proc(caddr_t handle,char * (* get_userid)(int))8762b60e3f2Schristos format_next_proc(caddr_t handle, char *(*get_userid)(int))
87710dd2532Schristos {
87810dd2532Schristos 	struct kinfo_proc2 *pp;
87910dd2532Schristos 	long cputime;
880f4e46459Snjoly 	double pct, wcpu, cpu;
88110dd2532Schristos 	struct handle *hp;
88210dd2532Schristos 	const char *statep;
88310dd2532Schristos #ifdef KI_NOCPU
88410dd2532Schristos 	char state[10];
88510dd2532Schristos #endif
88610dd2532Schristos 	char wmesg[KI_WMESGLEN + 1];
887c32922f1Scube 	static char fmt[MAX_COLS];		/* static area where result is built */
88810dd2532Schristos 
88910dd2532Schristos 	/* find and remember the next proc structure */
89010dd2532Schristos 	hp = (struct handle *)handle;
89110dd2532Schristos 	pp = *(hp->next_proc++);
89210dd2532Schristos 	hp->remaining--;
89310dd2532Schristos 
89410dd2532Schristos 	/* get the process's user struct and set cputime */
89510dd2532Schristos 
89610dd2532Schristos #if 0
89710dd2532Schristos 	/* This does not produce the correct results */
89810dd2532Schristos 	cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
89910dd2532Schristos #else
90010dd2532Schristos 	cputime = pp->p_rtime_sec;	/* This does not count interrupts */
90110dd2532Schristos #endif
90210dd2532Schristos 
9032b60e3f2Schristos 	/* calculate the base for CPU percentages */
90410dd2532Schristos 	pct = pctdouble(pp->p_pctcpu);
90510dd2532Schristos 
9062b60e3f2Schristos 	if (pp->p_stat == LSSLEEP) {
90710dd2532Schristos 		strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg));
90810dd2532Schristos 		statep = wmesg;
90910dd2532Schristos 	} else
91010dd2532Schristos 		statep = state_abbrev[(unsigned)pp->p_stat];
91110dd2532Schristos 
91210dd2532Schristos #ifdef KI_NOCPU
9132b60e3f2Schristos 	/* Post-1.5 change: add CPU number if appropriate */
9142b60e3f2Schristos 	if (pp->p_cpuid != KI_NOCPU && ncpu > 1) {
91510dd2532Schristos 		switch (pp->p_stat) {
9162b60e3f2Schristos 		case LSONPROC:
9172b60e3f2Schristos 		case LSRUN:
9182b60e3f2Schristos 		case LSSLEEP:
9192b60e3f2Schristos 		case LSIDL:
920c0c9bed8Srmind 			(void)snprintf(state, sizeof(state), "%.6s/%u",
921c0c9bed8Srmind 			     statep, (unsigned int)pp->p_cpuid);
92210dd2532Schristos 			statep = state;
92310dd2532Schristos 			break;
92410dd2532Schristos 		}
92510dd2532Schristos 	}
92610dd2532Schristos #endif
927aaad3eb0Snjoly 	wcpu = 100.0 * weighted_cpu(p_, pct, pp);
928f4e46459Snjoly 	cpu = 100.0 * pct;
929aaad3eb0Snjoly 
93010dd2532Schristos 	/* format this entry */
93110dd2532Schristos 	sprintf(fmt,
93210dd2532Schristos 	    Proc_format,
93310dd2532Schristos 	    pp->p_pid,
9342b60e3f2Schristos 	    (*userprint)(pp->p_ruid),
9352b60e3f2Schristos 	    pp->p_priority,
93610dd2532Schristos 	    pp->p_nice - NZERO,
93710dd2532Schristos 	    format_k(pagetok(PROCSIZE(pp))),
93810dd2532Schristos 	    format_k(pagetok(pp->p_vm_rssize)),
93910dd2532Schristos 	    statep,
94010dd2532Schristos 	    format_time(cputime),
941aaad3eb0Snjoly 	    (wcpu >= 100.0) ? 0 : 2, wcpu,
942f4e46459Snjoly 	    (cpu >= 100.0) ? 0 : 2, cpu,
94358f90407Schristos 	    get_command(hp->sel, pp));
94410dd2532Schristos 
94510dd2532Schristos 	/* return the result */
94610dd2532Schristos 	return(fmt);
94710dd2532Schristos }
94810dd2532Schristos 
9492b60e3f2Schristos static char *
countable(char * p,size_t width)95057f83fe0Schristos countable(char *p, size_t width)
951260d5f32Schristos {
95257f83fe0Schristos 	size_t len = strlen(p);
95357f83fe0Schristos 	if (len < width) {		// shorter than width, ok
954260d5f32Schristos 		return p;
95557f83fe0Schristos 	}
95657f83fe0Schristos 	size_t first, last = len - 1;
95757f83fe0Schristos 	for (first = len - 1; isdigit((unsigned char)p[first]); first--) {
95857f83fe0Schristos 		continue;
95957f83fe0Schristos 	}
96057f83fe0Schristos 	if (first == len - 1) {		// no digits, ok
961260d5f32Schristos 		return p;
96257f83fe0Schristos 	}
96357f83fe0Schristos 	first++;
96457f83fe0Schristos 	last = len - first;
96557f83fe0Schristos 	if (width < last + 1) {		// if not enough for digits, done
966260d5f32Schristos 		return p;
96757f83fe0Schristos 	}
96857f83fe0Schristos 	size_t start = width - last - 1;	// compute starting point
969a45df3f4Schristos 	p[start] = '*';			// put a star
970a45df3f4Schristos 	memmove(p + start + 1, p + first, last + 1);	// move digits and NUL
971260d5f32Schristos 	return p;
972260d5f32Schristos }
973260d5f32Schristos 
974260d5f32Schristos static char *
format_next_lwp(caddr_t handle,char * (* get_userid)(int))9752b60e3f2Schristos format_next_lwp(caddr_t handle, char *(*get_userid)(int))
9762b60e3f2Schristos {
9772b60e3f2Schristos 	struct kinfo_proc2 *pp;
9782b60e3f2Schristos 	struct kinfo_lwp *pl;
9792b60e3f2Schristos 	long cputime;
9802b60e3f2Schristos 	double pct;
9812b60e3f2Schristos 	struct handle *hp;
9822b60e3f2Schristos 	const char *statep;
9832b60e3f2Schristos #ifdef KI_NOCPU
9842b60e3f2Schristos 	char state[10];
9852b60e3f2Schristos #endif
9862b60e3f2Schristos 	char wmesg[KI_WMESGLEN + 1];
987c32922f1Scube 	static char fmt[MAX_COLS];		/* static area where result is built */
9882b60e3f2Schristos 	int uid;
9892b60e3f2Schristos 
9902b60e3f2Schristos 	/* find and remember the next proc structure */
9912b60e3f2Schristos 	hp = (struct handle *)handle;
9922b60e3f2Schristos 	pl = (struct kinfo_lwp *)*(hp->next_proc++);
9932b60e3f2Schristos 	hp->remaining--;
9942b60e3f2Schristos 	pp = proc_from_thread(pl);
9952b60e3f2Schristos 
9962b60e3f2Schristos 	/* get the process's user struct and set cputime */
99758f90407Schristos 	uid = pp ? pp->p_ruid : 0;
9982b60e3f2Schristos 
9992b60e3f2Schristos 	cputime = pl->l_rtime_sec;
10002b60e3f2Schristos 
10012b60e3f2Schristos 	/* calculate the base for CPU percentages */
10022b60e3f2Schristos 	pct = pctdouble(pl->l_pctcpu);
10032b60e3f2Schristos 
10042b60e3f2Schristos 	if (pl->l_stat == LSSLEEP) {
10052b60e3f2Schristos 		strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg));
10062b60e3f2Schristos 		statep = wmesg;
10072b60e3f2Schristos 	} else
10082b60e3f2Schristos 		statep = state_abbrev[(unsigned)pl->l_stat];
10092b60e3f2Schristos 
10102b60e3f2Schristos #ifdef KI_NOCPU
10112b60e3f2Schristos 	/* Post-1.5 change: add CPU number if appropriate */
10122b60e3f2Schristos 	if (pl->l_cpuid != KI_NOCPU && ncpu > 1) {
10132b60e3f2Schristos 		switch (pl->l_stat) {
10142b60e3f2Schristos 		case LSONPROC:
10152b60e3f2Schristos 		case LSRUN:
10162b60e3f2Schristos 		case LSSLEEP:
10172b60e3f2Schristos 		case LSIDL:
1018c0c9bed8Srmind 			(void)snprintf(state, sizeof(state), "%.6s/%u",
1019c0c9bed8Srmind 			     statep, (unsigned int)pl->l_cpuid);
10202b60e3f2Schristos 			statep = state;
10212b60e3f2Schristos 			break;
10222b60e3f2Schristos 		}
10232b60e3f2Schristos 	}
10242b60e3f2Schristos #endif
10252b60e3f2Schristos 
10262b60e3f2Schristos 	if (pl->l_name[0] == '\0') {
10272b60e3f2Schristos 		pl->l_name[0] = '-';
10282b60e3f2Schristos 		pl->l_name[1] = '\0';
10292b60e3f2Schristos 	}
10302b60e3f2Schristos 
10312b60e3f2Schristos 	/* format this entry */
10322b60e3f2Schristos 	sprintf(fmt,
10332b60e3f2Schristos 	    Thread_format,
10342b60e3f2Schristos 	    pl->l_pid,
10352b60e3f2Schristos 	    pl->l_lid,
10362b60e3f2Schristos 	    (*userprint)(uid),
10372b60e3f2Schristos 	    pl->l_priority,
10382b60e3f2Schristos 	    statep,
10392b60e3f2Schristos 	    format_time(cputime),
10402b60e3f2Schristos 	    100.0 * weighted_cpu(l_, pct, pl),
10412b60e3f2Schristos 	    100.0 * pct,
1042260d5f32Schristos 	    countable(printable(pl->l_name), 9),
10431d62298cSchristos 	    get_command(hp->sel, pp));
10442b60e3f2Schristos 
10452b60e3f2Schristos 	/* return the result */
10462b60e3f2Schristos 	return(fmt);
10472b60e3f2Schristos }
10482b60e3f2Schristos 
104910dd2532Schristos /* comparison routines for qsort */
105010dd2532Schristos 
105110dd2532Schristos /*
105210dd2532Schristos  * There are currently four possible comparison routines.  main selects
105310dd2532Schristos  * one of these by indexing in to the array proc_compares.
105410dd2532Schristos  *
105510dd2532Schristos  * Possible keys are defined as macros below.  Currently these keys are
10562b60e3f2Schristos  * defined:  percent CPU, CPU ticks, process state, resident set size,
105710dd2532Schristos  * total virtual memory usage.  The process states are ordered as follows
105810dd2532Schristos  * (from least to most important):  WAIT, zombie, sleep, stop, start, run.
105910dd2532Schristos  * The array declaration below maps a process state index into a number
106010dd2532Schristos  * that reflects this ordering.
106110dd2532Schristos  */
106210dd2532Schristos 
106310dd2532Schristos /*
106410dd2532Schristos  * First, the possible comparison keys.  These are defined in such a way
106510dd2532Schristos  * that they can be merely listed in the source code to define the actual
106610dd2532Schristos  * desired ordering.
106710dd2532Schristos  */
106810dd2532Schristos 
10692b60e3f2Schristos #define ORDERKEY_PCTCPU(pfx) \
10702b60e3f2Schristos 	if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
107110dd2532Schristos 	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
107210dd2532Schristos 
10732b60e3f2Schristos #define ORDERKEY_CPTICKS(pfx) \
10742b60e3f2Schristos 	if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
10752b60e3f2Schristos 		    - (pctcpu)(p1)->pfx ## rtime_sec,\
107610dd2532Schristos 	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
107710dd2532Schristos 
10782b60e3f2Schristos #define ORDERKEY_STATE(pfx) \
10792b60e3f2Schristos 	if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
10802b60e3f2Schristos 		      sorted_state[(int)(p1)->pfx ## stat] ) == 0)
108110dd2532Schristos 
10822b60e3f2Schristos #define ORDERKEY_PRIO(pfx) \
10832b60e3f2Schristos 	if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
108410dd2532Schristos 
108510dd2532Schristos #define ORDERKEY_RSSIZE \
108610dd2532Schristos 	if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
108710dd2532Schristos 
108810dd2532Schristos #define ORDERKEY_MEM	\
108910dd2532Schristos 	if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
10902b60e3f2Schristos #define ORDERKEY_SIZE(v1, v2)	\
10912b60e3f2Schristos 	if ((result = (v2 - v1)) == 0)
109210dd2532Schristos 
109310dd2532Schristos /*
109410dd2532Schristos  * Now the array that maps process state to a weight.
109510dd2532Schristos  * The order of the elements should match those in state_abbrev[]
109610dd2532Schristos  */
109710dd2532Schristos 
109810dd2532Schristos static int sorted_state[] = {
109910dd2532Schristos 	0,	/*  (not used)	  ?	*/
11005e99d26fSad 	1,	/* "start"	SIDL	*/
110110dd2532Schristos 	4,	/* "run"	SRUN	*/
110210dd2532Schristos 	3,	/* "sleep"	SSLEEP	*/
110310dd2532Schristos 	3,	/* "stop"	SSTOP	*/
110410dd2532Schristos 	2,	/* "dead"	SDEAD	*/
110510dd2532Schristos 	1,	/* "zomb"	SZOMB	*/
110610dd2532Schristos 	5,	/* "onproc"	SONPROC	*/
110710dd2532Schristos };
110810dd2532Schristos 
11092b60e3f2Schristos /* compare_cpu - the comparison function for sorting by CPU percentage */
111010dd2532Schristos 
111110dd2532Schristos static int
compare_cpu(pp1,pp2)111210dd2532Schristos compare_cpu(pp1, pp2)
111310dd2532Schristos 	struct proc **pp1, **pp2;
111410dd2532Schristos {
111510dd2532Schristos 	int result;
111610dd2532Schristos 	pctcpu lresult;
111710dd2532Schristos 
11182b60e3f2Schristos 	if (threadmode) {
11192b60e3f2Schristos 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
11202b60e3f2Schristos 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
112110dd2532Schristos 
11222b60e3f2Schristos 		ORDERKEY_PCTCPU(l_)
11232b60e3f2Schristos 		ORDERKEY_CPTICKS(l_)
11242b60e3f2Schristos 		ORDERKEY_STATE(l_)
11252b60e3f2Schristos 		ORDERKEY_PRIO(l_)
1126213e7ef1Schristos 		return result;
11272b60e3f2Schristos 	} else {
11282b60e3f2Schristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
11292b60e3f2Schristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
11302b60e3f2Schristos 
11312b60e3f2Schristos 		ORDERKEY_PCTCPU(p_)
11322b60e3f2Schristos 		ORDERKEY_CPTICKS(p_)
11332b60e3f2Schristos 		ORDERKEY_STATE(p_)
11342b60e3f2Schristos 		ORDERKEY_PRIO(p_)
113510dd2532Schristos 		ORDERKEY_RSSIZE
113610dd2532Schristos 		ORDERKEY_MEM
1137213e7ef1Schristos 		return result;
11382b60e3f2Schristos 	}
113910dd2532Schristos 
114010dd2532Schristos 	return (result);
114110dd2532Schristos }
114210dd2532Schristos 
114310dd2532Schristos /* compare_prio - the comparison function for sorting by process priority */
114410dd2532Schristos 
114510dd2532Schristos static int
compare_prio(pp1,pp2)114610dd2532Schristos compare_prio(pp1, pp2)
114710dd2532Schristos 	struct proc **pp1, **pp2;
114810dd2532Schristos {
114910dd2532Schristos 	int result;
115010dd2532Schristos 	pctcpu lresult;
115110dd2532Schristos 
11522b60e3f2Schristos 	if (threadmode) {
11532b60e3f2Schristos 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
11542b60e3f2Schristos 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
115510dd2532Schristos 
11562b60e3f2Schristos 		ORDERKEY_PRIO(l_)
11572b60e3f2Schristos 		ORDERKEY_PCTCPU(l_)
11582b60e3f2Schristos 		ORDERKEY_CPTICKS(l_)
11592b60e3f2Schristos 		ORDERKEY_STATE(l_)
1160213e7ef1Schristos 		return result;
11612b60e3f2Schristos 	} else {
11622b60e3f2Schristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
11632b60e3f2Schristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
11642b60e3f2Schristos 
11652b60e3f2Schristos 		ORDERKEY_PRIO(p_)
11662b60e3f2Schristos 		ORDERKEY_PCTCPU(p_)
11672b60e3f2Schristos 		ORDERKEY_CPTICKS(p_)
11682b60e3f2Schristos 		ORDERKEY_STATE(p_)
116910dd2532Schristos 		ORDERKEY_RSSIZE
117010dd2532Schristos 		ORDERKEY_MEM
1171213e7ef1Schristos 		return result;
11722b60e3f2Schristos 	}
117310dd2532Schristos 
117410dd2532Schristos 	return (result);
117510dd2532Schristos }
117610dd2532Schristos 
117710dd2532Schristos /* compare_res - the comparison function for sorting by resident set size */
117810dd2532Schristos 
117910dd2532Schristos static int
compare_res(pp1,pp2)118010dd2532Schristos compare_res(pp1, pp2)
118110dd2532Schristos 	struct proc **pp1, **pp2;
118210dd2532Schristos {
118310dd2532Schristos 	int result;
118410dd2532Schristos 	pctcpu lresult;
118510dd2532Schristos 
11862b60e3f2Schristos 	if (threadmode) {
11872b60e3f2Schristos 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
11882b60e3f2Schristos 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
11892b60e3f2Schristos 
11902b60e3f2Schristos 		ORDERKEY_PCTCPU(l_)
11912b60e3f2Schristos 		ORDERKEY_CPTICKS(l_)
11922b60e3f2Schristos 		ORDERKEY_STATE(l_)
11932b60e3f2Schristos 		ORDERKEY_PRIO(l_)
1194213e7ef1Schristos 		return result;
11952b60e3f2Schristos 	} else {
11962b60e3f2Schristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
11972b60e3f2Schristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
119810dd2532Schristos 
119910dd2532Schristos 		ORDERKEY_RSSIZE
120010dd2532Schristos 		ORDERKEY_MEM
12012b60e3f2Schristos 		ORDERKEY_PCTCPU(p_)
12022b60e3f2Schristos 		ORDERKEY_CPTICKS(p_)
12032b60e3f2Schristos 		ORDERKEY_STATE(p_)
12042b60e3f2Schristos 		ORDERKEY_PRIO(p_)
1205213e7ef1Schristos 		return result;
12062b60e3f2Schristos 	}
120710dd2532Schristos 
120810dd2532Schristos 	return (result);
120910dd2532Schristos }
121010dd2532Schristos 
121114f5b40fSchristos static int
compare_pid(pp1,pp2)121214f5b40fSchristos compare_pid(pp1, pp2)
121314f5b40fSchristos 	struct proc **pp1, **pp2;
121414f5b40fSchristos {
121514f5b40fSchristos 	if (threadmode) {
12161fb97e15Schristos 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
12171fb97e15Schristos 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
12181fb97e15Schristos 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
12191fb97e15Schristos 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
122050f07ffdSmrg 		if (p1 == NULL || p2 == NULL)
122150f07ffdSmrg 			return -1;
12221fb97e15Schristos 		return p2->p_pid - p1->p_pid;
122314f5b40fSchristos 	} else {
122414f5b40fSchristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
122514f5b40fSchristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
122614f5b40fSchristos 		return p2->p_pid - p1->p_pid;
122714f5b40fSchristos 	}
122814f5b40fSchristos }
122914f5b40fSchristos 
123014f5b40fSchristos static int
compare_command(pp1,pp2)123114f5b40fSchristos compare_command(pp1, pp2)
123214f5b40fSchristos 	struct proc **pp1, **pp2;
123314f5b40fSchristos {
123414f5b40fSchristos 	if (threadmode) {
12351fb97e15Schristos 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
12361fb97e15Schristos 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
12371fb97e15Schristos 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
12381fb97e15Schristos 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
123950f07ffdSmrg 		if (p1 == NULL || p2 == NULL)
124050f07ffdSmrg 			return -1;
12411fb97e15Schristos 		return strcmp(p2->p_comm, p1->p_comm);
124214f5b40fSchristos 	} else {
124314f5b40fSchristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
124414f5b40fSchristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
124514f5b40fSchristos 		return strcmp(p2->p_comm, p1->p_comm);
124614f5b40fSchristos 	}
124714f5b40fSchristos }
124814f5b40fSchristos 
124914f5b40fSchristos static int
compare_username(pp1,pp2)125014f5b40fSchristos compare_username(pp1, pp2)
125114f5b40fSchristos 	struct proc **pp1, **pp2;
125214f5b40fSchristos {
125314f5b40fSchristos 	if (threadmode) {
12541fb97e15Schristos 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
12551fb97e15Schristos 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
12561fb97e15Schristos 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
12571fb97e15Schristos 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
125850f07ffdSmrg 		if (p1 == NULL || p2 == NULL)
125950f07ffdSmrg 			return -1;
12601fb97e15Schristos 		return strcmp(p2->p_login, p1->p_login);
126114f5b40fSchristos 	} else {
126214f5b40fSchristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
126314f5b40fSchristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
126414f5b40fSchristos 		return strcmp(p2->p_login, p1->p_login);
126514f5b40fSchristos 	}
126614f5b40fSchristos }
126710dd2532Schristos /* compare_size - the comparison function for sorting by total memory usage */
126810dd2532Schristos 
126910dd2532Schristos static int
compare_size(pp1,pp2)127010dd2532Schristos compare_size(pp1, pp2)
127110dd2532Schristos 	struct proc **pp1, **pp2;
127210dd2532Schristos {
127310dd2532Schristos 	int result;
127410dd2532Schristos 	pctcpu lresult;
127510dd2532Schristos 
12762b60e3f2Schristos 	if (threadmode) {
12772b60e3f2Schristos 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
12782b60e3f2Schristos 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
12792b60e3f2Schristos 
12802b60e3f2Schristos 		ORDERKEY_PCTCPU(l_)
12812b60e3f2Schristos 		ORDERKEY_CPTICKS(l_)
12822b60e3f2Schristos 		ORDERKEY_STATE(l_)
12832b60e3f2Schristos 		ORDERKEY_PRIO(l_)
1284213e7ef1Schristos 		return result;
12852b60e3f2Schristos 	} else {
12862b60e3f2Schristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
12872b60e3f2Schristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
128810dd2532Schristos 
128910dd2532Schristos 		ORDERKEY_MEM
129010dd2532Schristos 		ORDERKEY_RSSIZE
12912b60e3f2Schristos 		ORDERKEY_PCTCPU(p_)
12922b60e3f2Schristos 		ORDERKEY_CPTICKS(p_)
12932b60e3f2Schristos 		ORDERKEY_STATE(p_)
12942b60e3f2Schristos 		ORDERKEY_PRIO(p_)
1295213e7ef1Schristos 		return result;
12962b60e3f2Schristos 	}
129710dd2532Schristos 
129810dd2532Schristos 	return (result);
129910dd2532Schristos }
130010dd2532Schristos 
130110dd2532Schristos /* compare_state - the comparison function for sorting by process state */
130210dd2532Schristos 
130310dd2532Schristos static int
compare_state(pp1,pp2)130410dd2532Schristos compare_state(pp1, pp2)
130510dd2532Schristos 	struct proc **pp1, **pp2;
130610dd2532Schristos {
130710dd2532Schristos 	int result;
130810dd2532Schristos 	pctcpu lresult;
130910dd2532Schristos 
13102b60e3f2Schristos 	if (threadmode) {
13112b60e3f2Schristos 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
13122b60e3f2Schristos 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
131310dd2532Schristos 
13142b60e3f2Schristos 		ORDERKEY_STATE(l_)
13152b60e3f2Schristos 		ORDERKEY_PCTCPU(l_)
13162b60e3f2Schristos 		ORDERKEY_CPTICKS(l_)
13172b60e3f2Schristos 		ORDERKEY_PRIO(l_)
1318213e7ef1Schristos 		return result;
13192b60e3f2Schristos 	} else {
13202b60e3f2Schristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
13212b60e3f2Schristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
13222b60e3f2Schristos 
13232b60e3f2Schristos 		ORDERKEY_STATE(p_)
13242b60e3f2Schristos 		ORDERKEY_PCTCPU(p_)
13252b60e3f2Schristos 		ORDERKEY_CPTICKS(p_)
13262b60e3f2Schristos 		ORDERKEY_PRIO(p_)
132710dd2532Schristos 		ORDERKEY_RSSIZE
132810dd2532Schristos 		ORDERKEY_MEM
1329213e7ef1Schristos 		return result;
13302b60e3f2Schristos 	}
133110dd2532Schristos 
133210dd2532Schristos 	return (result);
133310dd2532Schristos }
133410dd2532Schristos 
13352b60e3f2Schristos /* compare_time - the comparison function for sorting by total CPU time */
133610dd2532Schristos 
133710dd2532Schristos static int
compare_time(pp1,pp2)133810dd2532Schristos compare_time(pp1, pp2)
133910dd2532Schristos 	struct proc **pp1, **pp2;
134010dd2532Schristos {
134110dd2532Schristos 	int result;
134210dd2532Schristos 	pctcpu lresult;
134310dd2532Schristos 
13442b60e3f2Schristos 	if (threadmode) {
13452b60e3f2Schristos 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
13462b60e3f2Schristos 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
134710dd2532Schristos 
13482b60e3f2Schristos 		ORDERKEY_CPTICKS(l_)
13492b60e3f2Schristos 		ORDERKEY_PCTCPU(l_)
13502b60e3f2Schristos 		ORDERKEY_STATE(l_)
13512b60e3f2Schristos 		ORDERKEY_PRIO(l_)
1352213e7ef1Schristos 		return result;
13532b60e3f2Schristos 	} else {
13542b60e3f2Schristos 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
13552b60e3f2Schristos 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
13562b60e3f2Schristos 
13572b60e3f2Schristos 		ORDERKEY_CPTICKS(p_)
13582b60e3f2Schristos 		ORDERKEY_PCTCPU(p_)
13592b60e3f2Schristos 		ORDERKEY_STATE(p_)
13602b60e3f2Schristos 		ORDERKEY_PRIO(p_)
136110dd2532Schristos 		ORDERKEY_MEM
136210dd2532Schristos 		ORDERKEY_RSSIZE
1363213e7ef1Schristos 		return result;
13642b60e3f2Schristos 	}
136510dd2532Schristos 
136610dd2532Schristos 	return (result);
136710dd2532Schristos }
136810dd2532Schristos 
136910dd2532Schristos 
137010dd2532Schristos /*
137110dd2532Schristos  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
137210dd2532Schristos  *		the process does not exist.
137310dd2532Schristos  *		It is EXTREMLY IMPORTANT that this function work correctly.
137410dd2532Schristos  *		If top runs setuid root (as in SVR4), then this function
137510dd2532Schristos  *		is the only thing that stands in the way of a serious
137610dd2532Schristos  *		security problem.  It validates requests for the "kill"
137710dd2532Schristos  *		and "renice" commands.
137810dd2532Schristos  */
137910dd2532Schristos 
138010dd2532Schristos int
proc_owner(pid)138110dd2532Schristos proc_owner(pid)
138210dd2532Schristos 	int pid;
138310dd2532Schristos {
138410dd2532Schristos 	int cnt;
138510dd2532Schristos 	struct kinfo_proc2 **prefp;
138610dd2532Schristos 	struct kinfo_proc2 *pp;
138710dd2532Schristos 
13882b60e3f2Schristos 	if (threadmode)
13892b60e3f2Schristos 		return(-1);
13902b60e3f2Schristos 
139110dd2532Schristos 	prefp = pref;
139210dd2532Schristos 	cnt = pref_len;
139310dd2532Schristos 	while (--cnt >= 0) {
139410dd2532Schristos 		pp = *prefp++;
139510dd2532Schristos 		if (pp->p_pid == (pid_t)pid)
139610dd2532Schristos 			return(pp->p_ruid);
139710dd2532Schristos 	}
139810dd2532Schristos 	return(-1);
139910dd2532Schristos }
140010dd2532Schristos 
140110dd2532Schristos /*
140210dd2532Schristos  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
140310dd2532Schristos  *	between array "old" and "new", putting the percentages i "out".
140410dd2532Schristos  *	"cnt" is size of each array and "diffs" is used for scratch space.
140510dd2532Schristos  *	The array "old" is updated on each call.
140610dd2532Schristos  *	The routine assumes modulo arithmetic.  This function is especially
14072b60e3f2Schristos  *	useful on BSD mchines for calculating CPU state percentages.
140810dd2532Schristos  */
140910dd2532Schristos 
14102b60e3f2Schristos static void
percentages64(cnt,out,new,old,diffs)141110dd2532Schristos percentages64(cnt, out, new, old, diffs)
141210dd2532Schristos 	int cnt;
141310dd2532Schristos 	int *out;
141410dd2532Schristos 	u_int64_t *new;
141510dd2532Schristos 	u_int64_t *old;
141610dd2532Schristos 	u_int64_t *diffs;
141710dd2532Schristos {
141810dd2532Schristos 	int i;
141910dd2532Schristos 	u_int64_t change;
142010dd2532Schristos 	u_int64_t total_change;
142110dd2532Schristos 	u_int64_t *dp;
142210dd2532Schristos 	u_int64_t half_total;
142310dd2532Schristos 
142410dd2532Schristos 	/* initialization */
142510dd2532Schristos 	total_change = 0;
142610dd2532Schristos 	dp = diffs;
142710dd2532Schristos 
142810dd2532Schristos 	/* calculate changes for each state and the overall change */
142910dd2532Schristos 	for (i = 0; i < cnt; i++) {
143010dd2532Schristos 		/*
143110dd2532Schristos 		 * Don't worry about wrapping - even at hz=1GHz, a
143210dd2532Schristos 		 * u_int64_t will last at least 544 years.
143310dd2532Schristos 		 */
143410dd2532Schristos 		change = *new - *old;
143510dd2532Schristos 		total_change += (*dp++ = change);
143610dd2532Schristos 		*old++ = *new++;
143710dd2532Schristos 	}
143810dd2532Schristos 
143910dd2532Schristos 	/* avoid divide by zero potential */
144010dd2532Schristos 	if (total_change == 0)
144110dd2532Schristos 		total_change = 1;
144210dd2532Schristos 
144310dd2532Schristos 	/* calculate percentages based on overall change, rounding up */
144410dd2532Schristos 	half_total = total_change / 2;
144510dd2532Schristos 	for (i = 0; i < cnt; i++)
144610dd2532Schristos 		*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
144710dd2532Schristos }
1448