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