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