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