Home | History | Annotate | Line # | Download | only in machine
      1 /*	$NetBSD: m_netbsd.c,v 1.31 2026/04/18 21:37:04 christos Exp $	*/
      2 
      3 /*
      4  * top - a top users display for Unix
      5  *
      6  * SYNOPSIS:  For a NetBSD-1.5 (or later) system
      7  *
      8  * DESCRIPTION:
      9  * Originally written for BSD4.4 system by Christos Zoulas.
     10  * Based on the FreeBSD 2.0 version by Steven Wallace and Wolfram Schneider.
     11  * NetBSD-1.0 port by Arne Helme. Process ordering by Luke Mewburn.
     12  * NetBSD-1.3 port by Luke Mewburn, based on code by Matthew Green.
     13  * NetBSD-1.4/UVM port by matthew green.
     14  * NetBSD-1.5 port by Simon Burge.
     15  * NetBSD-1.6/UBC port by Tomas Svensson.
     16  * -
     17  * This is the machine-dependent module for NetBSD-1.5 and later
     18  * works for:
     19  *	NetBSD-1.6ZC
     20  * and should work for:
     21  *	NetBSD-2.0	(when released)
     22  * -
     23  * NetBSD-4.0 updates from Christos Zoulas.
     24  * NetBSD-5.0 updates from Andrew Doran, Mindaugas Rasiukevicius and
     25  * Christos Zoulas.
     26  * NetBSD-6.0 updates from matthew green, Christos Zoulas, and
     27  * Mindaugas Rasiukevicius.
     28  * NetBSD-8 updates from Leonardo Taccari.
     29  * NetBSD-10 updates from Christos Zoulas and matthew green.
     30  *
     31  * top does not need to be installed setuid or setgid with this module.
     32  *
     33  * LIBS: -lkvm
     34  *
     35  * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR
     36  *
     37  * AUTHORS:	Christos Zoulas <christos (at) ee.cornell.edu>
     38  *		Steven Wallace <swallace (at) freebsd.org>
     39  *		Wolfram Schneider <wosch (at) cs.tu-berlin.de>
     40  *		Arne Helme <arne (at) acm.org>
     41  *		Luke Mewburn <lukem (at) NetBSD.org>
     42  *		matthew green <mrg (at) eterna23.net>
     43  *		Simon Burge <simonb (at) NetBSD.org>
     44  *		Tomas Svensson <ts (at) unix1.net>
     45  *		Andrew Doran <ad (at) NetBSD.org>
     46  *
     47  *
     48  * $Id: m_netbsd.c,v 1.31 2026/04/18 21:37:04 christos Exp $
     49  */
     50 #include <sys/cdefs.h>
     51 
     52 #ifndef lint
     53 __RCSID("$NetBSD: m_netbsd.c,v 1.31 2026/04/18 21:37:04 christos Exp $");
     54 #endif
     55 
     56 #include <sys/param.h>
     57 #include <sys/resource.h>
     58 #include <sys/sysctl.h>
     59 #include <sys/sched.h>
     60 #include <sys/swap.h>
     61 #include <sys/socket.h>
     62 
     63 #include <net/route.h>
     64 
     65 #include <uvm/uvm_extern.h>
     66 
     67 #include <err.h>
     68 #include <errno.h>
     69 #include <kvm.h>
     70 #include <math.h>
     71 #include <ctype.h>
     72 #include <nlist.h>
     73 #include <stdio.h>
     74 #include <stdlib.h>
     75 #include <string.h>
     76 #include <unistd.h>
     77 
     78 #include "os.h"
     79 #include "top.h"
     80 #include "machine.h"
     81 #include "utils.h"
     82 #include "display.h"
     83 #include "loadavg.h"
     84 #include "username.h"
     85 
     86 static void percentages64(int, int *, u_int64_t *, u_int64_t *,
     87     u_int64_t *);
     88 
     89 /* get_process_info passes back a handle.  This is what it looks like: */
     90 
     91 struct handle {
     92 	struct process_select *sel;
     93 	struct kinfo_proc2 **next_proc;	/* points to next valid proc pointer */
     94 	int remaining;		/* number of pointers remaining */
     95 };
     96 
     97 /* define what weighted CPU is. */
     98 #define weighted_cpu(pfx, pct, pp) ((pp)->pfx ## swtime == 0 ? 0.0 : \
     99 			 ((pct) / (1.0 - exp((pp)->pfx ## swtime * logcpu))))
    100 
    101 /* what we consider to be process size: */
    102 /* NetBSD introduced p_vm_msize with RLIMIT_AS */
    103 #ifdef RLIMIT_AS
    104 #define PROCSIZE(pp) \
    105     ((pp)->p_vm_msize)
    106 #else
    107 #define PROCSIZE(pp) \
    108     ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize)
    109 #endif
    110 
    111 
    112 /*
    113  * These definitions control the format of the per-process area
    114  */
    115 
    116 static char Proc_header[] =
    117   "  PID X        PRI NICE   SIZE   RES STATE       TIME   WCPU    CPU COMMAND";
    118 /* 0123456   -- field to fill in starts at header+6 */
    119 #define PROC_UNAME_START 6
    120 #define Proc_format \
    121 	"%5d %-8.8s %3d %4d%7s %5s %-9.9s%7s %5.*f%% %5.*f%% %s"
    122 
    123 static char Thread_header[] =
    124   "  PID   LID X        PRI STATE       TIME   WCPU    CPU NAME      COMMAND";
    125 /* 0123456   -- field to fill in starts at header+6 */
    126 #define THREAD_UNAME_START 12
    127 #define Thread_format \
    128         "%5d %5d %-8.8s %3d %-9.9s%7s %5.2f%% %5.2f%% %-9.9s %s"
    129 
    130 /*
    131  * Process state names for the "STATE" column of the display.
    132  */
    133 
    134 const char *state_abbrev[] = {
    135 	"", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
    136 };
    137 
    138 static kvm_t *kd;
    139 
    140 static char *(*userprint)(int);
    141 
    142 /* these are retrieved from the kernel in _init */
    143 
    144 static double logcpu;
    145 static int hz;
    146 static int ccpu;
    147 
    148 /* these are for calculating CPU state percentages */
    149 
    150 static int ncpu = 0;
    151 static u_int64_t *cp_time;
    152 static u_int64_t *cp_old;
    153 static u_int64_t *cp_diff;
    154 
    155 /* these are for detailing the process states */
    156 
    157 int process_states[8];
    158 const char *procstatenames[] = {
    159 	"", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
    160 	" zombie, ", " dead, ", " on CPU, ",
    161 	NULL
    162 };
    163 
    164 /* these are for detailing the CPU states */
    165 
    166 int *cpu_states;
    167 const char *cpustatenames[] = {
    168 	"user", "nice", "system", "interrupt", "idle", NULL
    169 };
    170 
    171 /* these are for detailing the memory statistics */
    172 
    173 long memory_stats[7];
    174 const char *memorynames[] = {
    175 	"K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
    176 	"K Free, ",
    177 	NULL
    178 };
    179 
    180 long swap_stats[9];
    181 const char *swapnames[] = {
    182 	"K Total, ", "K Used, ", "K Free ", " Pools: ", "K Used ",
    183 	" Network: ", "K In, ", "K Out, ",
    184 	NULL
    185 };
    186 
    187 
    188 /* these are names given to allowed sorting orders -- first is default */
    189 const char *ordernames[] = {
    190 	"cpu",
    191 	"pri",
    192 	"res",
    193 	"size",
    194 	"state",
    195 	"time",
    196 	"pid",
    197 	"command",
    198 	"username",
    199 	NULL
    200 };
    201 
    202 /* forward definitions for comparison functions */
    203 static int compare_cpu(struct proc **, struct proc **);
    204 static int compare_prio(struct proc **, struct proc **);
    205 static int compare_res(struct proc **, struct proc **);
    206 static int compare_size(struct proc **, struct proc **);
    207 static int compare_state(struct proc **, struct proc **);
    208 static int compare_time(struct proc **, struct proc **);
    209 static int compare_pid(struct proc **, struct proc **);
    210 static int compare_command(struct proc **, struct proc **);
    211 static int compare_username(struct proc **, struct proc **);
    212 
    213 int (*proc_compares[])(struct proc **, struct proc **) = {
    214 	compare_cpu,
    215 	compare_prio,
    216 	compare_res,
    217 	compare_size,
    218 	compare_state,
    219 	compare_time,
    220 	compare_pid,
    221 	compare_command,
    222 	compare_username,
    223 	NULL
    224 };
    225 
    226 static char *format_next_lwp(caddr_t, char *(*)(int));
    227 static char *format_next_proc(caddr_t, char *(*)(int));
    228 
    229 static caddr_t get_proc_info(struct system_info *, struct process_select *,
    230 			     int (*)(struct proc **, struct proc **));
    231 static caddr_t get_lwp_info(struct system_info *, struct process_select *,
    232 			    int (*)(struct proc **, struct proc **));
    233 
    234 /* these are for keeping track of the proc array */
    235 
    236 static int nproc;
    237 static int onproc = -1;
    238 static int nlwp;
    239 static int onlwp = -1;
    240 static int pref_len;
    241 static int lref_len;
    242 static struct kinfo_proc2 *pbase;
    243 static struct kinfo_lwp *lbase;
    244 static struct kinfo_proc2 **pref;
    245 static struct kinfo_lwp **lref;
    246 static int maxswap;
    247 static void *swapp;
    248 static int procgen;
    249 static int thread_nproc;
    250 static int thread_onproc = -1;
    251 static struct kinfo_proc2 *thread_pbase;
    252 
    253 /* these are for getting the memory statistics */
    254 
    255 static int pageshift;		/* log base 2 of the pagesize */
    256 
    257 int threadmode;
    258 
    259 /* define pagetok in terms of pageshift */
    260 
    261 #define pagetok(size) ((size) << pageshift)
    262 
    263 /*
    264  * Print swapped processes as <pname> and
    265  * system processes as [pname]
    266  */
    267 static const char *
    268 get_pretty(const struct kinfo_proc2 *pp)
    269 {
    270 	if ((pp->p_flag & P_SYSTEM) != 0)
    271 		return "[]";
    272 	if ((pp->p_flag & P_INMEM) == 0)
    273 		return "<>";
    274 	return "";
    275 }
    276 
    277 static const char *
    278 get_command(const struct process_select *sel, struct kinfo_proc2 *pp)
    279 {
    280 	static char cmdbuf[128];
    281 	const char *pretty;
    282 	char **argv;
    283 	if (pp == NULL)
    284 		return "<gone>";
    285 	pretty = get_pretty(pp);
    286 
    287 	if (sel->fullcmd == 0 || kd == NULL || (argv = kvm_getargv2(kd, pp,
    288 	    sizeof(cmdbuf))) == NULL) {
    289 		if (pretty[0] != '\0' && pp->p_comm[0] != pretty[0])
    290 			snprintf(cmdbuf, sizeof(cmdbuf), "%c%s%c", pretty[0],
    291 			    printable(pp->p_comm), pretty[1]);
    292 		else
    293 			strlcpy(cmdbuf, printable(pp->p_comm), sizeof(cmdbuf));
    294 	} else {
    295 		char *d = cmdbuf;
    296 		if (pretty[0] != '\0' && argv[0][0] != pretty[0])
    297 			*d++ = pretty[0];
    298 		while (*argv) {
    299 			const char *s = printable(*argv++);
    300 			while (d < cmdbuf + sizeof(cmdbuf) - 2 &&
    301 			    (*d++ = *s++) != '\0')
    302 				continue;
    303 			if (d > cmdbuf && d < cmdbuf + sizeof(cmdbuf) - 2 &&
    304 			    d[-1] == '\0')
    305 				d[-1] = ' ';
    306 		}
    307 		if (pretty[0] != '\0' && pretty[0] == cmdbuf[0])
    308 			*d++ = pretty[1];
    309 		*d++ = '\0';
    310 	}
    311 	return cmdbuf;
    312 }
    313 
    314 int
    315 machine_init(statics)
    316 	struct statics *statics;
    317 {
    318 	int pagesize;
    319 	int mib[2];
    320 	size_t size;
    321 	struct clockinfo clockinfo;
    322 	struct timespec boottime;
    323 
    324 	if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
    325 		return -1;
    326 
    327 	mib[0] = CTL_HW;
    328 	mib[1] = HW_NCPU;
    329 	size = sizeof(ncpu);
    330 	if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) {
    331 		fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n",
    332 		    strerror(errno));
    333 		return(-1);
    334 	}
    335 	statics->ncpu = ncpu;
    336 	cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu);
    337 	mib[0] = CTL_KERN;
    338 	mib[1] = KERN_CP_TIME;
    339 	size = sizeof(cp_time[0]) * CPUSTATES * ncpu;
    340 	if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) {
    341 		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
    342 		    strerror(errno));
    343 		return(-1);
    344 	}
    345 
    346 	/* Handle old call that returned only aggregate */
    347 	if (size == sizeof(cp_time[0]) * CPUSTATES)
    348 		ncpu = 1;
    349 
    350 	cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu);
    351 	cp_old = calloc(CPUSTATES * ncpu, sizeof(cp_old[0]));
    352 	cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu);
    353 	if (cpu_states == NULL || cp_time == NULL || cp_old == NULL ||
    354 	    cp_diff == NULL) {
    355 		fprintf(stderr, "top: machine_init: %s\n",
    356 		    strerror(errno));
    357 		return(-1);
    358 	}
    359 
    360 	mib[0] = CTL_KERN;
    361 	mib[1] = KERN_CCPU;
    362 	size = sizeof(ccpu);
    363 	if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) {
    364 		fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n",
    365 		    strerror(errno));
    366 		return(-1);
    367 	}
    368 
    369 	mib[0] = CTL_KERN;
    370 	mib[1] = KERN_CLOCKRATE;
    371 	size = sizeof(clockinfo);
    372 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) {
    373 		fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n",
    374 		    strerror(errno));
    375 		return(-1);
    376 	}
    377 	hz = clockinfo.stathz;
    378 
    379 	/* this is used in calculating WCPU -- calculate it ahead of time */
    380 	logcpu = log(loaddouble(ccpu));
    381 
    382 	pbase = NULL;
    383 	lbase = NULL;
    384 	pref = NULL;
    385 	nproc = 0;
    386 	onproc = -1;
    387 	nlwp = 0;
    388 	onlwp = -1;
    389 	/* get the page size with "getpagesize" and calculate pageshift from it */
    390 	pagesize = getpagesize();
    391 	pageshift = 0;
    392 	while (pagesize > 1) {
    393 		pageshift++;
    394 		pagesize >>= 1;
    395 	}
    396 
    397 	/* we only need the amount of log(2)1024 for our conversion */
    398 	pageshift -= LOG1024;
    399 
    400 	/* fill in the statics information */
    401 #ifdef notyet
    402 	statics->ncpu = ncpu;
    403 #endif
    404 	statics->procstate_names = procstatenames;
    405 	statics->cpustate_names = cpustatenames;
    406 	statics->memory_names = memorynames;
    407 	statics->swap_names = swapnames;
    408 	statics->order_names = ordernames;
    409 	statics->flags.threads = 1;
    410 	statics->flags.fullcmds = 1;
    411 
    412 	mib[0] = CTL_KERN;
    413 	mib[1] = KERN_BOOTTIME;
    414 	size = sizeof(boottime);
    415 	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
    416     	    boottime.tv_sec != 0)
    417 		statics->boottime = boottime.tv_sec;
    418 	else
    419 		statics->boottime = 0;
    420 	/* all done! */
    421 	return(0);
    422 }
    423 
    424 char *
    425 format_process_header(struct process_select *sel, caddr_t handle, int count)
    426 
    427 {
    428 	char *header;
    429 	char *ptr;
    430 	const char *uname_field = sel->usernames ? "USERNAME" : "    UID ";
    431 
    432 	if (sel->threads) {
    433 		header = Thread_header;
    434 		ptr = header + THREAD_UNAME_START;
    435 	} else {
    436 		header = Proc_header;
    437 		ptr = header + PROC_UNAME_START;
    438 	}
    439 
    440 	while (*uname_field != '\0') {
    441 		*ptr++ = *uname_field++;
    442 	}
    443 
    444 	return(header);
    445 }
    446 
    447 char *
    448 format_header(char *uname_field)
    449 {
    450 	char *header = Proc_header;
    451 	char *ptr = header + PROC_UNAME_START;
    452 
    453 	while (*uname_field != '\0') {
    454 		*ptr++ = *uname_field++;
    455 	}
    456 
    457 	return(header);
    458 }
    459 
    460 static void
    461 get_network_kilobytes(long *kb_in, long *kb_out)
    462 {
    463 	struct if_msghdr *ifm;
    464 	int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 };
    465 	struct rt_msghdr *rtm;
    466 	struct if_data *ifd = NULL;
    467 	static char *buf = NULL;
    468 	static size_t olen;
    469 	char *next, *lim;
    470 	size_t len;
    471 	static uint64_t last_bytes_in;
    472 	static uint64_t last_bytes_out;
    473 	uint64_t cur_bytes_in = 0;
    474 	uint64_t cur_bytes_out = 0;
    475 
    476 	if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
    477 		err(1, "sysctl");
    478 	if (len > olen) {
    479 		free(buf);
    480 		if ((buf = malloc(len)) == NULL)
    481 			err(1, NULL);
    482 		olen = len;
    483 	}
    484 	if (sysctl(mib, 6, buf, &len, NULL, 0) == -1)
    485 		err(1, "sysctl");
    486 
    487 	lim = buf + len;
    488 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
    489 		rtm = (struct rt_msghdr *)next;
    490 		if (rtm->rtm_version != RTM_VERSION)
    491 			continue;
    492 		switch (rtm->rtm_type) {
    493 		case RTM_IFINFO:
    494 			ifm = (struct if_msghdr *)next;
    495 			ifd = &ifm->ifm_data;
    496 
    497 			cur_bytes_in += ifd->ifi_ibytes;
    498 			cur_bytes_out += ifd->ifi_obytes;
    499 			break;
    500 		}
    501 	}
    502 
    503 	*kb_in = (cur_bytes_in - last_bytes_in) / 1024;
    504 	*kb_out = (cur_bytes_out - last_bytes_out) / 1024;
    505 	last_bytes_in = cur_bytes_in;
    506 	last_bytes_out = cur_bytes_out;
    507 }
    508 
    509 void
    510 get_system_info(struct system_info *si)
    511 {
    512 	size_t ssize;
    513 	int mib[6];
    514 	struct uvmexp_sysctl uvmexp;
    515 	struct swapent *sep;
    516 	u_int64_t totalsize, totalinuse;
    517 	int size, inuse, ncounted, i;
    518 	int rnswap, nswap;
    519 
    520 	mib[0] = CTL_KERN;
    521 	mib[1] = KERN_CP_TIME;
    522 	ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu;
    523 	if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) {
    524 		fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
    525 		    strerror(errno));
    526 		quit(23);
    527 	}
    528 
    529 	if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) {
    530 		int j;
    531 
    532 		warn("can't getloadavg");
    533 		for (j = 0; j < NUM_AVERAGES; j++)
    534 			si->load_avg[j] = 0.0;
    535 	}
    536 
    537 	/* convert cp_time counts to percentages */
    538 	for (i = 0; i < ncpu; i++) {
    539 	    int j = i * CPUSTATES;
    540 	    percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j,
    541 		cp_diff + j);
    542 	}
    543 
    544 	mib[0] = CTL_VM;
    545 	mib[1] = VM_UVMEXP2;
    546 	ssize = sizeof(uvmexp);
    547 	if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) {
    548 		fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n",
    549 		    strerror(errno));
    550 		quit(23);
    551 	}
    552 
    553 	/* convert memory stats to Kbytes */
    554 	memory_stats[0] = pagetok(uvmexp.active);
    555 	memory_stats[1] = pagetok(uvmexp.inactive);
    556 	memory_stats[2] = pagetok(uvmexp.wired);
    557 	memory_stats[3] = pagetok(uvmexp.execpages);
    558 	memory_stats[4] = pagetok(uvmexp.filepages);
    559 	memory_stats[5] = pagetok(uvmexp.free);
    560 
    561 	swap_stats[0] = swap_stats[1] = swap_stats[2] = 0;
    562 
    563 	do {
    564 		nswap = swapctl(SWAP_NSWAP, 0, 0);
    565 		if (nswap < 1)
    566 			break;
    567 		if (nswap > maxswap) {
    568 			if (swapp)
    569 				free(swapp);
    570 			swapp = sep = malloc(nswap * sizeof(*sep));
    571 			if (sep == NULL)
    572 				break;
    573 			maxswap = nswap;
    574 		} else
    575 			sep = swapp;
    576 		rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
    577 		if (nswap != rnswap)
    578 			break;
    579 
    580 		totalsize = totalinuse = ncounted = 0;
    581 		for (; rnswap-- > 0; sep++) {
    582 			ncounted++;
    583 			size = sep->se_nblks;
    584 			inuse = sep->se_inuse;
    585 			totalsize += size;
    586 			totalinuse += inuse;
    587 		}
    588 		swap_stats[0] = dbtob(totalsize) / 1024;
    589 		swap_stats[1] = dbtob(totalinuse) / 1024;
    590 		swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1];
    591 	} while (0);
    592 
    593 	swap_stats[4] = pagetok(uvmexp.poolpages);
    594 
    595 	get_network_kilobytes(&swap_stats[6], &swap_stats[7]);
    596 
    597 	memory_stats[6] = -1;
    598 	swap_stats[3] = swap_stats[5] = swap_stats[8] = -1;
    599 
    600 	/* set arrays and strings */
    601 	si->cpustates = cpu_states;
    602 	si->memory = memory_stats;
    603 	si->swap = swap_stats;
    604 	si->last_pid = -1;
    605 
    606 }
    607 
    608 static struct kinfo_proc2 *
    609 proc_from_thread(struct kinfo_lwp *pl)
    610 {
    611 	struct kinfo_proc2 *pp = thread_pbase;
    612 	int i;
    613 
    614 	for (i = 0; i < thread_nproc; i++, pp++)
    615 		if ((pid_t)pp->p_pid == (pid_t)pl->l_pid)
    616 			return pp;
    617 	return NULL;
    618 }
    619 
    620 static int
    621 uid_from_thread(struct kinfo_lwp *pl)
    622 {
    623 	struct kinfo_proc2 *pp;
    624 
    625 	if ((pp = proc_from_thread(pl)) == NULL)
    626 		return -1;
    627 	return pp->p_ruid;
    628 }
    629 
    630 caddr_t
    631 get_process_info(struct system_info *si, struct process_select *sel, int c)
    632 {
    633 	userprint = sel->usernames ? username : itoa7;
    634 
    635 	if ((threadmode = sel->threads) != 0)
    636 		return get_lwp_info(si, sel, proc_compares[c]);
    637 	else
    638 		return get_proc_info(si, sel, proc_compares[c]);
    639 }
    640 
    641 static caddr_t
    642 get_proc_info(struct system_info *si, struct process_select *sel,
    643 	      int (*compare)(struct proc **, struct proc **))
    644 {
    645 	int i;
    646 	int total_procs;
    647 	int active_procs;
    648 	struct kinfo_proc2 **prefp, **n;
    649 	struct kinfo_proc2 *pp;
    650 	int op, arg;
    651 
    652 	/* these are copied out of sel for speed */
    653 	int show_idle;
    654 	int show_system;
    655 	int show_uid;
    656 	char *show_command;
    657 
    658 	static struct handle handle;
    659 
    660 	procgen++;
    661 
    662 	if (sel->pid == (pid_t)-1) {
    663 		op = KERN_PROC_ALL;
    664 		arg = 0;
    665 	} else {
    666 		op = KERN_PROC_PID;
    667 		arg = sel->pid;
    668 	}
    669 
    670 	pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc);
    671 	if (pbase == NULL) {
    672 		if (sel->pid != (pid_t)-1) {
    673 			nproc = 0;
    674 		} else {
    675 			(void) fprintf(stderr, "top: Out of memory.\n");
    676 			quit(23);
    677 		}
    678 	}
    679 	if (nproc > onproc) {
    680 		n = (struct kinfo_proc2 **) realloc(pref,
    681 		    sizeof(struct kinfo_proc2 *) * nproc);
    682 		if (n == NULL) {
    683 			(void) fprintf(stderr, "top: Out of memory.\n");
    684 			quit(23);
    685 		}
    686 		pref = n;
    687 		onproc = nproc;
    688 	}
    689 	/* get a pointer to the states summary array */
    690 	si->procstates = process_states;
    691 
    692 	/* set up flags which define what we are going to select */
    693 	show_idle = sel->idle;
    694 	show_system = sel->system;
    695 	show_uid = sel->uid != -1;
    696 	show_command = sel->command;
    697 
    698 	/* count up process states and get pointers to interesting procs */
    699 	total_procs = 0;
    700 	active_procs = 0;
    701 	memset((char *)process_states, 0, sizeof(process_states));
    702 	prefp = pref;
    703 	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
    704 
    705 		/*
    706 		 * Place pointers to each valid proc structure in pref[].
    707 		 * Process slots that are actually in use have a non-zero
    708 		 * status field.  Processes with P_SYSTEM set are system
    709 		 * processes---these get ignored unless show_sysprocs is set.
    710 		 */
    711 		if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) {
    712 			total_procs++;
    713 			process_states[(unsigned char) pp->p_stat]++;
    714 			if (pp->p_stat != LSZOMB &&
    715 			    (show_idle || (pp->p_pctcpu != 0) ||
    716 			    (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) &&
    717 			    (!show_uid || pp->p_ruid == (uid_t)sel->uid) &&
    718 			    (!show_command ||
    719 			     strstr(get_command(sel, pp),
    720 				 show_command) != NULL)) {
    721 					*prefp++ = pp;
    722 					active_procs++;
    723 			}
    724 		}
    725 	}
    726 
    727 	/* if requested, sort the "interesting" processes */
    728 	if (compare != NULL) {
    729 		qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *),
    730 		    (int (*)(const void *, const void *))compare);
    731 	}
    732 
    733 	/* remember active and total counts */
    734 	si->p_total = total_procs;
    735 	si->p_active = pref_len = active_procs;
    736 
    737 	/* pass back a handle */
    738 	handle.next_proc = pref;
    739 	handle.remaining = active_procs;
    740 	handle.sel = sel;
    741 	return((caddr_t)&handle);
    742 }
    743 
    744 static caddr_t
    745 get_lwp_info(struct system_info *si, struct process_select *sel,
    746 	     int (*compare)(struct proc **, struct proc **))
    747 {
    748 	int i;
    749 	int total_lwps;
    750 	int active_lwps;
    751 	struct kinfo_lwp **lrefp, **n;
    752 	struct kinfo_lwp *lp;
    753 	struct kinfo_proc2 *pp;
    754 
    755 	/* these are copied out of sel for speed */
    756 	int show_idle;
    757 	int show_system;
    758 	int show_uid;
    759 	char *show_command;
    760 
    761 	static struct handle handle;
    762 
    763 	pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
    764 	    &thread_nproc);
    765 	if (pp == NULL) {
    766 		(void) fprintf(stderr, "top: Out of memory.\n");
    767 		quit(23);
    768 	}
    769 	if (thread_pbase == NULL || thread_nproc != thread_onproc) {
    770 		free(thread_pbase);
    771 		thread_onproc = thread_nproc;
    772 		thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc);
    773 		if (thread_pbase == NULL) {
    774 			(void) fprintf(stderr, "top: Out of memory.\n");
    775 			quit(23);
    776 		}
    777 	}
    778 	memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc);
    779 
    780 	lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp);
    781 	if (lbase == NULL) {
    782 #ifdef notyet
    783 		if (sel->pid != (pid_t)-1) {
    784 			nproc = 0;
    785 			nlwp = 0;
    786 		}
    787 		else
    788 #endif
    789 		{
    790 			(void) fprintf(stderr, "top: Out of memory.\n");
    791 			quit(23);
    792 		}
    793 	}
    794 	if (nlwp > onlwp) {
    795 		n = (struct kinfo_lwp **) realloc(lref,
    796 		    sizeof(struct kinfo_lwp *) * nlwp);
    797 		if (n == NULL) {
    798 			(void) fprintf(stderr, "top: Out of memory.\n");
    799 			quit(23);
    800 		}
    801 		lref = n;
    802 		onlwp = nlwp;
    803 	}
    804 	/* get a pointer to the states summary array */
    805 	si->procstates = process_states;
    806 
    807 	/* set up flags which define what we are going to select */
    808 	show_idle = sel->idle;
    809 	show_system = sel->system;
    810 	show_uid = sel->uid != -1;
    811 	show_command = sel->command;
    812 
    813 	/* count up thread states and get pointers to interesting threads */
    814 	total_lwps = 0;
    815 	active_lwps = 0;
    816 	memset((char *)process_states, 0, sizeof(process_states));
    817 	lrefp = lref;
    818 	for (lp = lbase, i = 0; i < nlwp; lp++, i++) {
    819 		if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid)
    820 			continue;
    821 
    822 		/*
    823 		 * Place pointers to each valid lwp structure in lref[].
    824 		 * thread slots that are actually in use have a non-zero
    825 		 * status field.  threads with L_SYSTEM set are system
    826 		 * threads---these get ignored unless show_sysprocs is set.
    827 		 */
    828 		if (lp->l_stat != 0 &&
    829 		    (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) {
    830 			total_lwps++;
    831 			process_states[(unsigned char) lp->l_stat]++;
    832 			if (lp->l_stat != LSZOMB &&
    833 			    (show_idle || (lp->l_pctcpu != 0) ||
    834 			     (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) &&
    835 			    (!show_uid || uid_from_thread(lp) == sel->uid) &&
    836 			    (!show_command ||
    837 			     ((pp = proc_from_thread(lp)) != NULL &&
    838 			      strstr(get_command(sel, pp),
    839 				     show_command) != NULL))) {
    840 				*lrefp++ = lp;
    841 				active_lwps++;
    842 			}
    843 		}
    844 	}
    845 
    846 	/* if requested, sort the "interesting" threads */
    847 	if (compare != NULL) {
    848 		qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *),
    849 		    (int (*)(const void *, const void *))compare);
    850 	}
    851 
    852 	/* remember active and total counts */
    853 	si->p_total = total_lwps;
    854 	si->p_active = lref_len = active_lwps;
    855 
    856 	/* pass back a handle */
    857 	handle.next_proc = (struct kinfo_proc2 **)lref;
    858 	handle.remaining = active_lwps;
    859 	handle.sel = sel;
    860 
    861 	return((caddr_t)&handle);
    862 }
    863 
    864 char *
    865 format_next_process(caddr_t handle, char *(*get_userid)(int))
    866 {
    867 
    868 	if (threadmode)
    869 		return format_next_lwp(handle, get_userid);
    870 	else
    871 		return format_next_proc(handle, get_userid);
    872 }
    873 
    874 
    875 char *
    876 format_next_proc(caddr_t handle, char *(*get_userid)(int))
    877 {
    878 	struct kinfo_proc2 *pp;
    879 	long cputime;
    880 	double pct, wcpu, cpu;
    881 	struct handle *hp;
    882 	const char *statep;
    883 #ifdef KI_NOCPU
    884 	char state[10];
    885 #endif
    886 	char wmesg[KI_WMESGLEN + 1];
    887 	static char fmt[MAX_COLS];		/* static area where result is built */
    888 
    889 	/* find and remember the next proc structure */
    890 	hp = (struct handle *)handle;
    891 	pp = *(hp->next_proc++);
    892 	hp->remaining--;
    893 
    894 	/* get the process's user struct and set cputime */
    895 
    896 #if 0
    897 	/* This does not produce the correct results */
    898 	cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
    899 #else
    900 	cputime = pp->p_rtime_sec;	/* This does not count interrupts */
    901 #endif
    902 
    903 	/* calculate the base for CPU percentages */
    904 	pct = pctdouble(pp->p_pctcpu);
    905 
    906 	if (pp->p_stat == LSSLEEP) {
    907 		strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg));
    908 		statep = wmesg;
    909 	} else
    910 		statep = state_abbrev[(unsigned)pp->p_stat];
    911 
    912 #ifdef KI_NOCPU
    913 	/* Post-1.5 change: add CPU number if appropriate */
    914 	if (pp->p_cpuid != KI_NOCPU && ncpu > 1) {
    915 		switch (pp->p_stat) {
    916 		case LSONPROC:
    917 		case LSRUN:
    918 		case LSSLEEP:
    919 		case LSIDL:
    920 			(void)snprintf(state, sizeof(state), "%.6s/%u",
    921 			     statep, (unsigned int)pp->p_cpuid);
    922 			statep = state;
    923 			break;
    924 		}
    925 	}
    926 #endif
    927 	wcpu = 100.0 * weighted_cpu(p_, pct, pp);
    928 	cpu = 100.0 * pct;
    929 
    930 	/* format this entry */
    931 	snprintf(fmt, sizeof(fmt),
    932 	    Proc_format,
    933 	    pp->p_pid,
    934 	    (*userprint)(pp->p_ruid),
    935 	    pp->p_priority,
    936 	    pp->p_nice - NZERO,
    937 	    format_k(pagetok(PROCSIZE(pp))),
    938 	    format_k(pagetok(pp->p_vm_rssize)),
    939 	    statep,
    940 	    format_time(cputime),
    941 	    (wcpu >= 100.0) ? 0 : 2, wcpu,
    942 	    (cpu >= 100.0) ? 0 : 2, cpu,
    943 	    get_command(hp->sel, pp));
    944 
    945 	/* return the result */
    946 	return(fmt);
    947 }
    948 
    949 static char *
    950 countable(char *p, size_t width)
    951 {
    952 	size_t len = strlen(p);
    953 	if (len < width) {		// shorter than width, ok
    954 		return p;
    955 	}
    956 	size_t first, last = len - 1;
    957 	for (first = len - 1; isdigit((unsigned char)p[first]); first--) {
    958 		continue;
    959 	}
    960 	if (first == len - 1) {		// no digits, ok
    961 		return p;
    962 	}
    963 	first++;
    964 	last = len - first;
    965 	if (width < last + 1) {		// if not enough for digits, done
    966 		return p;
    967 	}
    968 	size_t start = width - last - 1;	// compute starting point
    969 	p[start] = '*';			// put a star
    970 	memmove(p + start + 1, p + first, last + 1);	// move digits and NUL
    971 	return p;
    972 }
    973 
    974 static char *
    975 format_next_lwp(caddr_t handle, char *(*get_userid)(int))
    976 {
    977 	struct kinfo_proc2 *pp;
    978 	struct kinfo_lwp *pl;
    979 	long cputime;
    980 	double pct;
    981 	struct handle *hp;
    982 	const char *statep;
    983 #ifdef KI_NOCPU
    984 	char state[10];
    985 #endif
    986 	char wmesg[KI_WMESGLEN + 1];
    987 	static char fmt[MAX_COLS];		/* static area where result is built */
    988 	int uid;
    989 
    990 	/* find and remember the next proc structure */
    991 	hp = (struct handle *)handle;
    992 	pl = (struct kinfo_lwp *)*(hp->next_proc++);
    993 	hp->remaining--;
    994 	pp = proc_from_thread(pl);
    995 
    996 	/* get the process's user struct and set cputime */
    997 	uid = pp ? pp->p_ruid : 0;
    998 
    999 	cputime = pl->l_rtime_sec;
   1000 
   1001 	/* calculate the base for CPU percentages */
   1002 	pct = pctdouble(pl->l_pctcpu);
   1003 
   1004 	if (pl->l_stat == LSSLEEP) {
   1005 		strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg));
   1006 		statep = wmesg;
   1007 	} else
   1008 		statep = state_abbrev[(unsigned)pl->l_stat];
   1009 
   1010 #ifdef KI_NOCPU
   1011 	/* Post-1.5 change: add CPU number if appropriate */
   1012 	if (pl->l_cpuid != KI_NOCPU && ncpu > 1) {
   1013 		switch (pl->l_stat) {
   1014 		case LSONPROC:
   1015 		case LSRUN:
   1016 		case LSSLEEP:
   1017 		case LSIDL:
   1018 			(void)snprintf(state, sizeof(state), "%.6s/%u",
   1019 			     statep, (unsigned int)pl->l_cpuid);
   1020 			statep = state;
   1021 			break;
   1022 		}
   1023 	}
   1024 #endif
   1025 
   1026 	if (pl->l_name[0] == '\0') {
   1027 		pl->l_name[0] = '-';
   1028 		pl->l_name[1] = '\0';
   1029 	}
   1030 
   1031 	/* format this entry */
   1032 	snprintf(fmt,
   1033 	    sizeof(fmt),
   1034 	    Thread_format,
   1035 	    pl->l_pid,
   1036 	    pl->l_lid,
   1037 	    (*userprint)(uid),
   1038 	    pl->l_priority,
   1039 	    statep,
   1040 	    format_time(cputime),
   1041 	    100.0 * weighted_cpu(l_, pct, pl),
   1042 	    100.0 * pct,
   1043 	    countable(printable(pl->l_name), 9),
   1044 	    get_command(hp->sel, pp));
   1045 
   1046 	/* return the result */
   1047 	return(fmt);
   1048 }
   1049 
   1050 /* comparison routines for qsort */
   1051 
   1052 /*
   1053  * There are currently four possible comparison routines.  main selects
   1054  * one of these by indexing in to the array proc_compares.
   1055  *
   1056  * Possible keys are defined as macros below.  Currently these keys are
   1057  * defined:  percent CPU, CPU ticks, process state, resident set size,
   1058  * total virtual memory usage.  The process states are ordered as follows
   1059  * (from least to most important):  WAIT, zombie, sleep, stop, start, run.
   1060  * The array declaration below maps a process state index into a number
   1061  * that reflects this ordering.
   1062  */
   1063 
   1064 /*
   1065  * First, the possible comparison keys.  These are defined in such a way
   1066  * that they can be merely listed in the source code to define the actual
   1067  * desired ordering.
   1068  */
   1069 
   1070 #define ORDERKEY_PCTCPU(pfx) \
   1071 	if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
   1072 	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
   1073 
   1074 #define ORDERKEY_CPTICKS(pfx) \
   1075 	if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
   1076 		    - (pctcpu)(p1)->pfx ## rtime_sec,\
   1077 	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
   1078 
   1079 #define ORDERKEY_STATE(pfx) \
   1080 	if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
   1081 		      sorted_state[(int)(p1)->pfx ## stat] ) == 0)
   1082 
   1083 #define ORDERKEY_PRIO(pfx) \
   1084 	if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
   1085 
   1086 #define ORDERKEY_RSSIZE \
   1087 	if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
   1088 
   1089 #define ORDERKEY_MEM	\
   1090 	if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
   1091 #define ORDERKEY_SIZE(v1, v2)	\
   1092 	if ((result = (v2 - v1)) == 0)
   1093 
   1094 /*
   1095  * Now the array that maps process state to a weight.
   1096  * The order of the elements should match those in state_abbrev[]
   1097  */
   1098 
   1099 static int sorted_state[] = {
   1100 	0,	/*  (not used)	  ?	*/
   1101 	1,	/* "start"	SIDL	*/
   1102 	4,	/* "run"	SRUN	*/
   1103 	3,	/* "sleep"	SSLEEP	*/
   1104 	3,	/* "stop"	SSTOP	*/
   1105 	2,	/* "dead"	SDEAD	*/
   1106 	1,	/* "zomb"	SZOMB	*/
   1107 	5,	/* "onproc"	SONPROC	*/
   1108 };
   1109 
   1110 /* compare_cpu - the comparison function for sorting by CPU percentage */
   1111 
   1112 static int
   1113 compare_cpu(pp1, pp2)
   1114 	struct proc **pp1, **pp2;
   1115 {
   1116 	int result;
   1117 	pctcpu lresult;
   1118 
   1119 	if (threadmode) {
   1120 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
   1121 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
   1122 
   1123 		ORDERKEY_PCTCPU(l_)
   1124 		ORDERKEY_CPTICKS(l_)
   1125 		ORDERKEY_STATE(l_)
   1126 		ORDERKEY_PRIO(l_)
   1127 		return result;
   1128 	} else {
   1129 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1130 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1131 
   1132 		ORDERKEY_PCTCPU(p_)
   1133 		ORDERKEY_CPTICKS(p_)
   1134 		ORDERKEY_STATE(p_)
   1135 		ORDERKEY_PRIO(p_)
   1136 		ORDERKEY_RSSIZE
   1137 		ORDERKEY_MEM
   1138 		return result;
   1139 	}
   1140 
   1141 	return (result);
   1142 }
   1143 
   1144 /* compare_prio - the comparison function for sorting by process priority */
   1145 
   1146 static int
   1147 compare_prio(pp1, pp2)
   1148 	struct proc **pp1, **pp2;
   1149 {
   1150 	int result;
   1151 	pctcpu lresult;
   1152 
   1153 	if (threadmode) {
   1154 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
   1155 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
   1156 
   1157 		ORDERKEY_PRIO(l_)
   1158 		ORDERKEY_PCTCPU(l_)
   1159 		ORDERKEY_CPTICKS(l_)
   1160 		ORDERKEY_STATE(l_)
   1161 		return result;
   1162 	} else {
   1163 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1164 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1165 
   1166 		ORDERKEY_PRIO(p_)
   1167 		ORDERKEY_PCTCPU(p_)
   1168 		ORDERKEY_CPTICKS(p_)
   1169 		ORDERKEY_STATE(p_)
   1170 		ORDERKEY_RSSIZE
   1171 		ORDERKEY_MEM
   1172 		return result;
   1173 	}
   1174 
   1175 	return (result);
   1176 }
   1177 
   1178 /* compare_res - the comparison function for sorting by resident set size */
   1179 
   1180 static int
   1181 compare_res(pp1, pp2)
   1182 	struct proc **pp1, **pp2;
   1183 {
   1184 	int result;
   1185 	pctcpu lresult;
   1186 
   1187 	if (threadmode) {
   1188 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
   1189 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
   1190 
   1191 		ORDERKEY_PCTCPU(l_)
   1192 		ORDERKEY_CPTICKS(l_)
   1193 		ORDERKEY_STATE(l_)
   1194 		ORDERKEY_PRIO(l_)
   1195 		return result;
   1196 	} else {
   1197 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1198 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1199 
   1200 		ORDERKEY_RSSIZE
   1201 		ORDERKEY_MEM
   1202 		ORDERKEY_PCTCPU(p_)
   1203 		ORDERKEY_CPTICKS(p_)
   1204 		ORDERKEY_STATE(p_)
   1205 		ORDERKEY_PRIO(p_)
   1206 		return result;
   1207 	}
   1208 
   1209 	return (result);
   1210 }
   1211 
   1212 static int
   1213 compare_pid(pp1, pp2)
   1214 	struct proc **pp1, **pp2;
   1215 {
   1216 	if (threadmode) {
   1217 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
   1218 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
   1219 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
   1220 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
   1221 		if (p1 == NULL || p2 == NULL)
   1222 			return -1;
   1223 		return p2->p_pid - p1->p_pid;
   1224 	} else {
   1225 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1226 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1227 		return p2->p_pid - p1->p_pid;
   1228 	}
   1229 }
   1230 
   1231 static int
   1232 compare_command(pp1, pp2)
   1233 	struct proc **pp1, **pp2;
   1234 {
   1235 	if (threadmode) {
   1236 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
   1237 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
   1238 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
   1239 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
   1240 		if (p1 == NULL || p2 == NULL)
   1241 			return -1;
   1242 		return strcmp(p2->p_comm, p1->p_comm);
   1243 	} else {
   1244 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1245 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1246 		return strcmp(p2->p_comm, p1->p_comm);
   1247 	}
   1248 }
   1249 
   1250 static int
   1251 compare_username(pp1, pp2)
   1252 	struct proc **pp1, **pp2;
   1253 {
   1254 	if (threadmode) {
   1255 		struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
   1256 		struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
   1257 		struct kinfo_proc2 *p1 = proc_from_thread(l1);
   1258 		struct kinfo_proc2 *p2 = proc_from_thread(l2);
   1259 		if (p1 == NULL || p2 == NULL)
   1260 			return -1;
   1261 		return strcmp(p2->p_login, p1->p_login);
   1262 	} else {
   1263 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1264 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1265 		return strcmp(p2->p_login, p1->p_login);
   1266 	}
   1267 }
   1268 /* compare_size - the comparison function for sorting by total memory usage */
   1269 
   1270 static int
   1271 compare_size(pp1, pp2)
   1272 	struct proc **pp1, **pp2;
   1273 {
   1274 	int result;
   1275 	pctcpu lresult;
   1276 
   1277 	if (threadmode) {
   1278 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
   1279 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
   1280 
   1281 		ORDERKEY_PCTCPU(l_)
   1282 		ORDERKEY_CPTICKS(l_)
   1283 		ORDERKEY_STATE(l_)
   1284 		ORDERKEY_PRIO(l_)
   1285 		return result;
   1286 	} else {
   1287 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1288 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1289 
   1290 		ORDERKEY_MEM
   1291 		ORDERKEY_RSSIZE
   1292 		ORDERKEY_PCTCPU(p_)
   1293 		ORDERKEY_CPTICKS(p_)
   1294 		ORDERKEY_STATE(p_)
   1295 		ORDERKEY_PRIO(p_)
   1296 		return result;
   1297 	}
   1298 
   1299 	return (result);
   1300 }
   1301 
   1302 /* compare_state - the comparison function for sorting by process state */
   1303 
   1304 static int
   1305 compare_state(pp1, pp2)
   1306 	struct proc **pp1, **pp2;
   1307 {
   1308 	int result;
   1309 	pctcpu lresult;
   1310 
   1311 	if (threadmode) {
   1312 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
   1313 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
   1314 
   1315 		ORDERKEY_STATE(l_)
   1316 		ORDERKEY_PCTCPU(l_)
   1317 		ORDERKEY_CPTICKS(l_)
   1318 		ORDERKEY_PRIO(l_)
   1319 		return result;
   1320 	} else {
   1321 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1322 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1323 
   1324 		ORDERKEY_STATE(p_)
   1325 		ORDERKEY_PCTCPU(p_)
   1326 		ORDERKEY_CPTICKS(p_)
   1327 		ORDERKEY_PRIO(p_)
   1328 		ORDERKEY_RSSIZE
   1329 		ORDERKEY_MEM
   1330 		return result;
   1331 	}
   1332 
   1333 	return (result);
   1334 }
   1335 
   1336 /* compare_time - the comparison function for sorting by total CPU time */
   1337 
   1338 static int
   1339 compare_time(pp1, pp2)
   1340 	struct proc **pp1, **pp2;
   1341 {
   1342 	int result;
   1343 	pctcpu lresult;
   1344 
   1345 	if (threadmode) {
   1346 		struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
   1347 		struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
   1348 
   1349 		ORDERKEY_CPTICKS(l_)
   1350 		ORDERKEY_PCTCPU(l_)
   1351 		ORDERKEY_STATE(l_)
   1352 		ORDERKEY_PRIO(l_)
   1353 		return result;
   1354 	} else {
   1355 		struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
   1356 		struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
   1357 
   1358 		ORDERKEY_CPTICKS(p_)
   1359 		ORDERKEY_PCTCPU(p_)
   1360 		ORDERKEY_STATE(p_)
   1361 		ORDERKEY_PRIO(p_)
   1362 		ORDERKEY_MEM
   1363 		ORDERKEY_RSSIZE
   1364 		return result;
   1365 	}
   1366 
   1367 	return (result);
   1368 }
   1369 
   1370 
   1371 /*
   1372  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
   1373  *		the process does not exist.
   1374  *		It is EXTREMLY IMPORTANT that this function work correctly.
   1375  *		If top runs setuid root (as in SVR4), then this function
   1376  *		is the only thing that stands in the way of a serious
   1377  *		security problem.  It validates requests for the "kill"
   1378  *		and "renice" commands.
   1379  */
   1380 
   1381 int
   1382 proc_owner(pid)
   1383 	int pid;
   1384 {
   1385 	int cnt;
   1386 	struct kinfo_proc2 **prefp;
   1387 	struct kinfo_proc2 *pp;
   1388 
   1389 	if (threadmode)
   1390 		return(-1);
   1391 
   1392 	prefp = pref;
   1393 	cnt = pref_len;
   1394 	while (--cnt >= 0) {
   1395 		pp = *prefp++;
   1396 		if (pp->p_pid == (pid_t)pid)
   1397 			return(pp->p_ruid);
   1398 	}
   1399 	return(-1);
   1400 }
   1401 
   1402 /*
   1403  *  percentages(cnt, out, new, old, diffs) - calculate percentage change
   1404  *	between array "old" and "new", putting the percentages i "out".
   1405  *	"cnt" is size of each array and "diffs" is used for scratch space.
   1406  *	The array "old" is updated on each call.
   1407  *	The routine assumes modulo arithmetic.  This function is especially
   1408  *	useful on BSD mchines for calculating CPU state percentages.
   1409  */
   1410 
   1411 static void
   1412 percentages64(cnt, out, new, old, diffs)
   1413 	int cnt;
   1414 	int *out;
   1415 	u_int64_t *new;
   1416 	u_int64_t *old;
   1417 	u_int64_t *diffs;
   1418 {
   1419 	int i;
   1420 	u_int64_t change;
   1421 	u_int64_t total_change;
   1422 	u_int64_t *dp;
   1423 	u_int64_t half_total;
   1424 
   1425 	/* initialization */
   1426 	total_change = 0;
   1427 	dp = diffs;
   1428 
   1429 	/* calculate changes for each state and the overall change */
   1430 	for (i = 0; i < cnt; i++) {
   1431 		/*
   1432 		 * Don't worry about wrapping - even at hz=1GHz, a
   1433 		 * u_int64_t will last at least 544 years.
   1434 		 */
   1435 		change = *new - *old;
   1436 		total_change += (*dp++ = change);
   1437 		*old++ = *new++;
   1438 	}
   1439 
   1440 	/* avoid divide by zero potential */
   1441 	if (total_change == 0)
   1442 		total_change = 1;
   1443 
   1444 	/* calculate percentages based on overall change, rounding up */
   1445 	half_total = total_change / 2;
   1446 	for (i = 0; i < cnt; i++)
   1447 		*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
   1448 }
   1449