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