xref: /dragonfly/usr.bin/top/m_dragonfly.c (revision 2b3f93ea)
1 /*
2  * top - a top users display for Unix
3  *
4  * SYNOPSIS:  For DragonFly 2.x and later
5  *
6  * DESCRIPTION:
7  * Originally written for BSD4.4 system by Christos Zoulas.
8  * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
9  * Order support hacked in from top-3.5beta6/machine/m_aix41.c
10  *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
11  *
12  * This is the machine-dependent module for DragonFly 2.5.1
13  * Should work for:
14  *	DragonFly 2.x and above
15  *
16  * LIBS: -lkvm
17  *
18  * AUTHOR: Jan Lentfer <Jan.Lentfer@web.de>
19  * This module has been put together from different sources and is based on the
20  * work of many other people, e.g. Matthew Dillon, Simon Schubert, Jordan Gordeev.
21  *
22  * $FreeBSD: src/usr.bin/top/machine.c,v 1.29.2.2 2001/07/31 20:27:05 tmm Exp $
23  */
24 
25 #include <sys/user.h>
26 #include <sys/types.h>
27 #include <sys/time.h>
28 #include <sys/signal.h>
29 #include <sys/param.h>
30 
31 #include "os.h"
32 #include <err.h>
33 #include <fcntl.h>
34 #include <kvm.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <math.h>
38 #include <pwd.h>
39 #include <sys/errno.h>
40 #include <sys/sysctl.h>
41 #include <sys/vmmeter.h>
42 #include <sys/resource.h>
43 #include <sys/rtprio.h>
44 
45 /* Swap */
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/conf.h>
49 
50 #include <osreldate.h>		/* for changes in kernel structures */
51 
52 #include <sys/kinfo.h>
53 #include <kinfo.h>
54 #include "top.h"
55 #include "display.h"
56 #include "machine.h"
57 #include "screen.h"
58 #include "utils.h"
59 
60 int swapmode(int *retavail, int *retfree);
61 static int namelength;
62 static int cmdlength;
63 static int show_fullcmd;
64 
65 int n_cpus, enable_ncpus;
66 
67 /* get_process_info passes back a handle.  This is what it looks like: */
68 
69 struct handle {
70 	struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
71 	int remaining;		/* number of pointers remaining */
72 	int show_threads;
73 };
74 
75 /* declarations for load_avg */
76 #include "loadavg.h"
77 
78 #define PP(pp, field) ((pp)->kp_ ## field)
79 #define LP(pp, field) ((pp)->kp_lwp.kl_ ## field)
80 #define VP(pp, field) ((pp)->kp_vm_ ## field)
81 
82 /* what we consider to be process size: */
83 #define PROCSIZE(pp) (VP((pp), map_size) / 1024)
84 
85 /*
86  * These definitions control the format of the per-process area
87  */
88 
89 static char smp_header[] =
90 "   PID %-*.*s NICE  SIZE    RES    STATE   C   TIME   CTIME    CPU COMMAND";
91 
92 #define smp_Proc_format \
93 	"%6d %-*.*s %3d%7s %6s %8.8s %3d %6s %7s %5.2f%% %.*s"
94 
95 
96 static kvm_t *kd;
97 
98 /* values that we stash away in _init and use in later routines */
99 
100 static long lastpid;
101 
102 /* these are for calculating cpu state percentages */
103 
104 static struct kinfo_cputime *cp_time, *cp_old;
105 
106 /* these are for detailing the process states */
107 
108 enum {
109 	PS_STARTING = 0,
110 	PS_RUNNING,
111 	PS_STOPPED,
112 	PS_SLEEPING,
113 	PS_ZOMBIE,
114 	PS_DUMPING,
115 	PS_MAX,
116 };
117 
118 int process_states[PS_MAX + 1];
119 char *procstatenames[] = {
120 	[PS_STARTING]	= " starting, ",
121 	[PS_RUNNING]	= " running, ",
122 	[PS_STOPPED]	= " stopped, ",
123 	[PS_SLEEPING]	= " sleeping, ",
124 	[PS_ZOMBIE]	= " zombie, ",
125 	[PS_DUMPING]	= " dumping, ",
126 	[PS_MAX]	= NULL,
127 };
128 
129 /* process state names for the "STATE" column of the display */
130 const char *state_abbrev[] = {
131 	[PS_STARTING]	= "START",
132 	[PS_RUNNING]	= "RUN",
133 	[PS_STOPPED]	= "STOP",
134 	[PS_SLEEPING]	= "SLEEP",
135 	[PS_ZOMBIE]	= "ZOMBIE",
136 	[PS_DUMPING]	= "DUMP",
137 	[PS_MAX]	= NULL,
138 };
139 
140 /* these are for detailing the cpu states */
141 #define CPU_STATES 5
142 int *cpu_states;
143 int* cpu_averages;
144 char *cpustatenames[CPU_STATES + 1] = {
145 	"user", "nice", "system", "interrupt", "idle", NULL
146 };
147 
148 /* these are for detailing the memory statistics */
149 
150 long memory_stats[7];
151 char *memorynames[] = {
152 	"K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
153 	NULL
154 };
155 
156 long swap_stats[7];
157 char *swapnames[] = {
158 	/* 0           1            2           3            4       5 */
159 	"K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
160 	NULL
161 };
162 
163 
164 /* these are for keeping track of the proc array */
165 
166 static int nproc;
167 static int onproc = -1;
168 static int pref_len;
169 static struct kinfo_proc *pbase;
170 static struct kinfo_proc **pref;
171 
172 static uint64_t prev_pbase_time;	/* unit: us */
173 static struct kinfo_proc *prev_pbase;
174 static int prev_pbase_alloc;
175 static int prev_nproc;
176 static int fscale;
177 
178 /* these are for getting the memory statistics */
179 
180 static int pageshift;		/* log base 2 of the pagesize */
181 
182 /* define pagetok in terms of pageshift */
183 
184 #define pagetok(size) ((size) << pageshift)
185 
186 /* sorting orders. first is default */
187 char *ordernames[] = {
188   "cpu", "size", "res", "time", "pri", "thr", "pid", "ctime",  "pres", NULL
189 };
190 
191 /* compare routines */
192 int proc_compare (struct kinfo_proc **, struct kinfo_proc **);
193 int compare_size (struct kinfo_proc **, struct kinfo_proc **);
194 int compare_res (struct kinfo_proc **, struct kinfo_proc **);
195 int compare_time (struct kinfo_proc **, struct kinfo_proc **);
196 int compare_ctime (struct kinfo_proc **, struct kinfo_proc **);
197 int compare_prio(struct kinfo_proc **, struct kinfo_proc **);
198 int compare_thr (struct kinfo_proc **, struct kinfo_proc **);
199 int compare_pid (struct kinfo_proc **, struct kinfo_proc **);
200 int compare_pres(struct kinfo_proc **, struct kinfo_proc **);
201 
202 int (*proc_compares[]) (struct kinfo_proc **,struct kinfo_proc **) = {
203 	proc_compare,
204 	compare_size,
205 	compare_res,
206 	compare_time,
207 	compare_prio,
208 	compare_thr,
209 	compare_pid,
210 	compare_ctime,
211 	compare_pres,
212 	NULL
213 };
214 
215 static void
216 cputime_percentages(int out[CPU_STATES], struct kinfo_cputime *new,
217     struct kinfo_cputime *old)
218 {
219 	struct kinfo_cputime diffs;
220 	uint64_t total_change, half_total;
221 
222 	/* initialization */
223 	total_change = 0;
224 
225 	diffs.cp_user = new->cp_user - old->cp_user;
226 	diffs.cp_nice = new->cp_nice - old->cp_nice;
227 	diffs.cp_sys = new->cp_sys - old->cp_sys;
228 	diffs.cp_intr = new->cp_intr - old->cp_intr;
229 	diffs.cp_idle = new->cp_idle - old->cp_idle;
230 	total_change = diffs.cp_user + diffs.cp_nice + diffs.cp_sys +
231 	    diffs.cp_intr + diffs.cp_idle;
232 	old->cp_user = new->cp_user;
233 	old->cp_nice = new->cp_nice;
234 	old->cp_sys = new->cp_sys;
235 	old->cp_intr = new->cp_intr;
236 	old->cp_idle = new->cp_idle;
237 
238 	/* avoid divide by zero potential */
239 	if (total_change == 0)
240 		total_change = 1;
241 
242 	/* calculate percentages based on overall change, rounding up */
243 	half_total = total_change >> 1;
244 
245 	out[0] = ((diffs.cp_user * 1000LL + half_total) / total_change);
246 	out[1] = ((diffs.cp_nice * 1000LL + half_total) / total_change);
247 	out[2] = ((diffs.cp_sys * 1000LL + half_total) / total_change);
248 	out[3] = ((diffs.cp_intr * 1000LL + half_total) / total_change);
249 	out[4] = ((diffs.cp_idle * 1000LL + half_total) / total_change);
250 }
251 
252 int
253 machine_init(struct statics *statics)
254 {
255 	int pagesize;
256 	size_t prmlen;
257 	struct passwd *pw;
258 
259 	if (n_cpus < 1) {
260 		if (kinfo_get_cpus(&n_cpus))
261 			err(1, "kinfo_get_cpus failed");
262 	}
263 	/* get boot time */
264 
265 	prmlen = sizeof(fscale);
266 	if (sysctlbyname("kern.fscale", &fscale, &prmlen, NULL, 0) == -1)
267 		err(1, "sysctl kern.fscale failed");
268 
269 	while ((pw = getpwent()) != NULL) {
270 		if ((int)strlen(pw->pw_name) > namelength)
271 			namelength = strlen(pw->pw_name);
272 	}
273 	if (namelength < 8)
274 		namelength = 8;
275 	if (namelength > 13)
276 		namelength = 13;
277 
278 	if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
279 		return -1;
280 
281 	pbase = NULL;
282 	pref = NULL;
283 	nproc = 0;
284 	onproc = -1;
285 	prev_pbase = NULL;
286 	prev_pbase_alloc = 0;
287 	prev_pbase_time = 0;
288 	prev_nproc = 0;
289 	/*
290 	 * get the page size with "getpagesize" and calculate pageshift from
291 	 * it
292 	 */
293 	pagesize = getpagesize();
294 	pageshift = 0;
295 	while (pagesize > 1) {
296 		pageshift++;
297 		pagesize >>= 1;
298 	}
299 
300 	/* we only need the amount of log(2)1024 for our conversion */
301 	pageshift -= LOG1024;
302 
303 	/* fill in the statics information */
304 	statics->procstate_names = procstatenames;
305 	statics->cpustate_names = cpustatenames;
306 	statics->memory_names = memorynames;
307 	statics->unused01 = 0;
308 	statics->swap_names = swapnames;
309 	statics->order_names = ordernames;
310 	/* we need kvm descriptor in order to show full commands */
311 	statics->flags.fullcmds = kd != NULL;
312 	statics->flags.threads = 1;
313 
314 	/* all done! */
315 	return (0);
316 }
317 
318 char *
319 format_header(char *uname_field)
320 {
321 	static char Header[128];
322 
323 	snprintf(Header, sizeof(Header), smp_header,
324 	    namelength, namelength, uname_field);
325 
326 	if (screen_width <= 79)
327 		cmdlength = 80;
328 	else
329 		cmdlength = screen_width;
330 
331 	cmdlength = cmdlength - strlen(Header) + 6;
332 
333 	return Header;
334 }
335 
336 static int swappgsin = -1;
337 static int swappgsout = -1;
338 extern struct timeval timeout;
339 
340 void
341 get_system_info(struct system_info *si)
342 {
343 	size_t len;
344 	int cpu;
345 
346 	if (cpu_states == NULL) {
347 		cpu_states = malloc(sizeof(*cpu_states) * CPU_STATES * n_cpus);
348 		if (cpu_states == NULL)
349 			err(1, "malloc");
350 		bzero(cpu_states, sizeof(*cpu_states) * CPU_STATES * n_cpus);
351 	}
352 	if (cp_time == NULL) {
353 		cp_time = malloc(2 * n_cpus * sizeof(cp_time[0]));
354 		if (cp_time == NULL)
355 			err(1, "cp_time");
356 		cp_old = cp_time + n_cpus;
357 		len = n_cpus * sizeof(cp_old[0]);
358 		bzero(cp_time, len);
359 		if (sysctlbyname("kern.cputime", cp_old, &len, NULL, 0))
360 			err(1, "kern.cputime");
361 	}
362 	len = n_cpus * sizeof(cp_time[0]);
363 	bzero(cp_time, len);
364 	if (sysctlbyname("kern.cputime", cp_time, &len, NULL, 0))
365 		err(1, "kern.cputime");
366 
367 	getloadavg(si->load_avg, 3);
368 
369 	lastpid = 0;
370 
371 	/* convert cp_time counts to percentages */
372 	int combine_cpus = (enable_ncpus == 0 && n_cpus > 1);
373 	for (cpu = 0; cpu < n_cpus; ++cpu) {
374 		cputime_percentages(cpu_states + cpu * CPU_STATES,
375 		    &cp_time[cpu], &cp_old[cpu]);
376 	}
377 	if (combine_cpus) {
378 		if (cpu_averages == NULL) {
379 			cpu_averages = malloc(sizeof(*cpu_averages) * CPU_STATES);
380 			if (cpu_averages == NULL)
381 				err(1, "cpu_averages");
382 		}
383 		bzero(cpu_averages, sizeof(*cpu_averages) * CPU_STATES);
384 		for (cpu = 0; cpu < n_cpus; ++cpu) {
385 			int j = 0;
386 			cpu_averages[0] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
387 			cpu_averages[1] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
388 			cpu_averages[2] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
389 			cpu_averages[3] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
390 			cpu_averages[4] += *(cpu_states + ((cpu * CPU_STATES) + j++) );
391 		}
392 		for (int i = 0; i < CPU_STATES; ++i)
393 			cpu_averages[i] /= n_cpus;
394 	}
395 
396 	/* sum memory & swap statistics */
397 	{
398 		struct vmmeter vmm;
399 		struct vmstats vms;
400 		size_t vms_size = sizeof(vms);
401 		size_t vmm_size = sizeof(vmm);
402 		static unsigned int swap_delay = 0;
403 		static int swapavail = 0;
404 		static int swapfree = 0;
405 		static long bufspace = 0;
406 
407 		if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0))
408 			err(1, "sysctlbyname: vm.vmstats");
409 
410 		if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0))
411 			err(1, "sysctlbyname: vm.vmmeter");
412 
413 		if (kinfo_get_vfs_bufspace(&bufspace))
414 			err(1, "kinfo_get_vfs_bufspace");
415 
416 		/* convert memory stats to Kbytes */
417 		memory_stats[0] = pagetok(vms.v_active_count);
418 		memory_stats[1] = pagetok(vms.v_inactive_count);
419 		memory_stats[2] = pagetok(vms.v_wire_count);
420 		memory_stats[3] = pagetok(vms.v_cache_count);
421 		memory_stats[4] = bufspace / 1024;
422 		memory_stats[5] = pagetok(vms.v_free_count);
423 		memory_stats[6] = -1;
424 
425 		/* first interval */
426 		if (swappgsin < 0) {
427 			swap_stats[4] = 0;
428 			swap_stats[5] = 0;
429 		}
430 		/* compute differences between old and new swap statistic */
431 		else {
432 			swap_stats[4] = pagetok(((vmm.v_swappgsin - swappgsin)));
433 			swap_stats[5] = pagetok(((vmm.v_swappgsout - swappgsout)));
434 		}
435 
436 		swappgsin = vmm.v_swappgsin;
437 		swappgsout = vmm.v_swappgsout;
438 
439 		/* call CPU heavy swapmode() only for changes */
440 		if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
441 			swap_stats[3] = swapmode(&swapavail, &swapfree);
442 			swap_stats[0] = swapavail;
443 			swap_stats[1] = swapavail - swapfree;
444 			swap_stats[2] = swapfree;
445 		}
446 		swap_delay = 1;
447 		swap_stats[6] = -1;
448 	}
449 
450 	/* set arrays and strings */
451 	si->cpustates = combine_cpus == 1 ?
452 	    cpu_averages : cpu_states;
453 	si->memory = memory_stats;
454 	si->swap = swap_stats;
455 
456 
457 	if (lastpid > 0) {
458 		si->last_pid = lastpid;
459 	} else {
460 		si->last_pid = -1;
461 	}
462 }
463 
464 
465 static struct handle handle;
466 
467 static void
468 fixup_pctcpu(struct kinfo_proc *fixit, uint64_t d)
469 {
470 	struct kinfo_proc *pp;
471 	uint64_t ticks;
472 	int i;
473 
474 	if (prev_nproc == 0 || d == 0)
475 		return;
476 
477 	if (LP(fixit, pid) == -1) {
478 		/* Skip kernel "idle" threads */
479 		if (PP(fixit, stat) == SIDL)
480 			return;
481 		for (pp = prev_pbase, i = 0; i < prev_nproc; pp++, i++) {
482 			if (LP(pp, pid) == -1 &&
483 			    PP(pp, ktaddr) == PP(fixit, ktaddr))
484 				break;
485 		}
486 	} else {
487 		for (pp = prev_pbase, i = 0; i < prev_nproc; pp++, i++) {
488 			if (LP(pp, pid) == LP(fixit, pid) &&
489 			    LP(pp, tid) == LP(fixit, tid)) {
490 				if (PP(pp, paddr) != PP(fixit, paddr)) {
491 					/* pid/tid are reused */
492 					pp = NULL;
493 				}
494 				break;
495 			}
496 		}
497 	}
498 	if (i == prev_nproc || pp == NULL)
499 		return;
500 
501 	ticks = LP(fixit, iticks) - LP(pp, iticks);
502 	ticks += LP(fixit, sticks) - LP(pp, sticks);
503 	ticks += LP(fixit, uticks) - LP(pp, uticks);
504 	if (ticks > d * 1000)
505 		ticks = d * 1000;
506 	LP(fixit, pctcpu) = (ticks * (uint64_t)fscale) / d;
507 }
508 
509 caddr_t
510 get_process_info(struct system_info *si, struct process_select *sel,
511     int compare_index)
512 {
513 	struct timespec tv;
514 	uint64_t t, d = 0;
515 
516 	int i;
517 	int total_procs;
518 	int active_procs;
519 	struct kinfo_proc **prefp;
520 	struct kinfo_proc *pp;
521 
522 	/* these are copied out of sel for speed */
523 	int show_idle;
524 	int show_system;
525 	int show_uid;
526 	int show_threads;
527 	int kvmflags;
528 	char *match_command;
529 
530 	show_threads = sel->threads;
531 	show_system = sel->system;
532 
533 	kvmflags = 0;
534 	if (show_threads)
535 		kvmflags |= KERN_PROC_FLAG_LWP;
536 #ifdef KERN_PROC_FLAG_LWKT
537 	if (show_system)
538 		kvmflags |= KERN_PROC_FLAG_LWKT;
539 #endif
540 	pbase = kvm_getprocs(kd, KERN_PROC_ALL | kvmflags, 0, &nproc);
541 	if (nproc > onproc)
542 		pref = (struct kinfo_proc **)realloc(pref, sizeof(struct kinfo_proc *)
543 		    * (onproc = nproc));
544 	if (pref == NULL || pbase == NULL) {
545 		(void)fprintf(stderr, "top: Out of memory.\n");
546 		quit(23);
547 	}
548 
549 	clock_gettime(CLOCK_MONOTONIC_PRECISE, &tv);
550 	t = (tv.tv_sec * 1000000ULL) + (tv.tv_nsec / 1000ULL);
551 	if (prev_pbase_time > 0 && t > prev_pbase_time)
552 		d = t - prev_pbase_time;
553 
554 	/* get a pointer to the states summary array */
555 	si->procstates = process_states;
556 
557 	/* set up flags which define what we are going to select */
558 	show_idle = sel->idle;
559 	show_uid = sel->uid != -1;
560 	show_fullcmd = sel->fullcmd;
561 	match_command = sel->command;
562 
563 	/* count up process states and get pointers to interesting procs */
564 	total_procs = 0;
565 	active_procs = 0;
566 	memset((char *)process_states, 0, sizeof(process_states));
567 	prefp = pref;
568 	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
569 		/*
570 		 * Place pointers to each valid proc structure in pref[].
571 		 * Process slots that are actually in use have a non-zero
572 		 * status field.  Processes with P_SYSTEM set are system
573 		 * processes---these get ignored unless show_sysprocs is set.
574 		 */
575 		if ((show_system && (LP(pp, pid) == -1)) ||
576 		    (show_system || ((PP(pp, flags) & P_SYSTEM) == 0))) {
577 			int lpstate = LP(pp, stat);
578 			int pstate = PP(pp, stat);
579 			int state;
580 
581 			total_procs++;
582 
583 			switch (pstate) {
584 			case SIDL:
585 				state = PS_STARTING;
586 				break;
587 			case SACTIVE:
588 				switch (lpstate) {
589 				case LSRUN:
590 					state = PS_RUNNING;
591 					break;
592 				case LSSTOP:
593 					state = PS_STOPPED;
594 					break;
595 				case LSSLEEP:
596 					state = PS_SLEEPING;
597 					break;
598 				default:
599 					fprintf(stderr, "top: unknown LWP "
600 						"state: %d\n", lpstate);
601 					break;
602 				}
603 				break;
604 			case SSTOP:
605 				state = PS_STOPPED;
606 				break;
607 			case SZOMB:
608 				state = PS_ZOMBIE;
609 				break;
610 			case SCORE:
611 				state = PS_DUMPING;
612 				break;
613 			default:
614 				fprintf(stderr, "top: unknown process "
615 					"state: %d\n", pstate);
616 				break;
617 			}
618 			if (state < PS_MAX)
619 				process_states[state]++;
620 
621 			if (match_command != NULL &&
622 			    strstr(PP(pp, comm), match_command) == NULL) {
623 				/* Command does not match */
624 				continue;
625 			}
626 
627 			if (show_uid && PP(pp, ruid) != (uid_t)sel->uid) {
628 				/* UID does not match */
629 				continue;
630 			}
631 
632 			if (!show_system && LP(pp, pid) == -1) {
633 				/* Don't show system processes */
634 				continue;
635 			}
636 
637 			/* Fix up pctcpu before show_idle test */
638 			fixup_pctcpu(pp, d);
639 
640 			if (!show_idle && LP(pp, pctcpu) == 0 &&
641 			    lpstate != LSRUN) {
642 				/* Don't show idle processes */
643 				continue;
644 			}
645 
646 			*prefp++ = pp;
647 			active_procs++;
648 		}
649 	}
650 
651 	/*
652 	 * Save kinfo_procs for later pctcpu fixup.
653 	 */
654 	if (prev_pbase_alloc < nproc) {
655 		prev_pbase_alloc = nproc;
656 		prev_pbase = realloc(prev_pbase,
657 		    prev_pbase_alloc * sizeof(struct kinfo_proc));
658 		if (prev_pbase == NULL) {
659 			fprintf(stderr, "top: Out of memory.\n");
660 			quit(23);
661 		}
662 	}
663 	prev_nproc = nproc;
664 	prev_pbase_time = t;
665 	memcpy(prev_pbase, pbase, nproc * sizeof(struct kinfo_proc));
666 
667 	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *),
668 	    (int (*)(const void *, const void *))proc_compares[compare_index]);
669 
670 	/* remember active and total counts */
671 	si->p_total = total_procs;
672 	si->p_active = pref_len = active_procs;
673 
674 	/* pass back a handle */
675 	handle.next_proc = pref;
676 	handle.remaining = active_procs;
677 	handle.show_threads = show_threads;
678 	return ((caddr_t) & handle);
679 }
680 
681 char fmt[MAX_COLS];		/* static area where result is built */
682 
683 char *
684 format_next_process(caddr_t xhandle, char *(*get_userid) (int))
685 {
686 	struct kinfo_proc *pp;
687 	long cputime;
688 	long ccputime;
689 	double pct;
690 	struct handle *hp;
691 	char status[16];
692 	int state;
693 	int xnice;
694 	char *wmesg, *comm;
695 	char cputime_fmt[10], ccputime_fmt[10];
696 
697 	/* find and remember the next proc structure */
698 	hp = (struct handle *)xhandle;
699 	pp = *(hp->next_proc++);
700 	hp->remaining--;
701 
702 	/* get the process's command name */
703 	if (show_fullcmd) {
704 		char **comm_full = kvm_getargv(kd, pp, 0);
705 		if (comm_full != NULL)
706 			comm = *comm_full;
707 		else
708 			comm = PP(pp, comm);
709 	}
710 	else {
711 		comm = PP(pp, comm);
712 	}
713 
714 	/* the actual field to display */
715 	char cmdfield[MAX_COLS];
716 
717 	if (PP(pp, flags) & P_SYSTEM) {
718 		/* system process */
719 		snprintf(cmdfield, sizeof cmdfield, "[%s]", comm);
720 	} else if (hp->show_threads && PP(pp, nthreads) > 1) {
721 		/* display it as a thread */
722 		if (strcmp(PP(pp, comm), LP(pp, comm)) == 0) {
723 			snprintf(cmdfield, sizeof cmdfield, "%s{%d}", comm,
724 			    LP(pp, tid));
725 		} else {
726 			/* show thread name in addition to tid */
727 			snprintf(cmdfield, sizeof cmdfield, "%s{%d/%s}", comm,
728 			    LP(pp, tid), LP(pp, comm));
729 		}
730 	} else {
731 		snprintf(cmdfield, sizeof cmdfield, "%s", comm);
732 	}
733 
734 	/*
735 	 * Convert the process's runtime from microseconds to seconds.  This
736 	 * time includes the interrupt time to be in compliance with ps output.
737 	 */
738 	cputime = (LP(pp, uticks) + LP(pp, sticks) + LP(pp, iticks)) / 1000000;
739 	ccputime = cputime + PP(pp, cru).ru_stime.tv_sec + PP(pp, cru).ru_utime.tv_sec;
740 	format_time(cputime, cputime_fmt, sizeof(cputime_fmt));
741 	format_time(ccputime, ccputime_fmt, sizeof(ccputime_fmt));
742 
743 	/* calculate the base for cpu percentages */
744 	pct = pctdouble(LP(pp, pctcpu));
745 
746 	/* generate "STATE" field */
747 	state = PS_MAX;
748 	switch (PP(pp, stat)) {
749 	case SIDL:
750 		state = PS_STARTING;
751 		break;
752 	case SACTIVE:
753 		switch (LP(pp, stat)) {
754 		case LSRUN:
755 			if (LP(pp, tdflags) & TDF_RUNNING)
756 				sprintf(status, "CPU%d", LP(pp, cpuid));
757 			else
758 				state = PS_RUNNING;
759 			break;
760 		case LSSTOP:
761 			state = PS_STOPPED;
762 			break;
763 		case LSSLEEP:
764 			wmesg = LP(pp, wmesg);
765 			if (wmesg[0] != '\0')
766 				sprintf(status, "%.8s", wmesg); /* WMESGLEN */
767 			else
768 				state = PS_SLEEPING;
769 			break;
770 		default:
771 			sprintf(status, "?LP/%d", LP(pp, stat));
772 			break;
773 		}
774 		break;
775 	case SSTOP:
776 		state = PS_STOPPED;
777 		break;
778 	case SZOMB:
779 		state = PS_ZOMBIE;
780 		break;
781 	case SCORE:
782 		state = PS_DUMPING;
783 		break;
784 	default:
785 		sprintf(status, "?P/%d", PP(pp, stat));
786 		break;
787 	}
788 	if (state < PS_MAX)
789 		sprintf(status, "%.8s", state_abbrev[state]);
790 
791 	/*
792 	 * idle time 0 - 31 -> nice value +21 - +52 normal time      -> nice
793 	 * value -20 - +20 real time 0 - 31 -> nice value -52 - -21 thread
794 	 * 0 - 31 -> nice value -53 -
795 	 */
796 	switch (LP(pp, rtprio.type)) {
797 	case RTP_PRIO_REALTIME:
798 		xnice = PRIO_MIN - 1 - RTP_PRIO_MAX + LP(pp, rtprio.prio);
799 		break;
800 	case RTP_PRIO_IDLE:
801 		xnice = PRIO_MAX + 1 + LP(pp, rtprio.prio);
802 		break;
803 	case RTP_PRIO_THREAD:
804 		xnice = PRIO_MIN - 1 - RTP_PRIO_MAX - LP(pp, rtprio.prio);
805 		break;
806 	default:
807 		xnice = PP(pp, nice);
808 		break;
809 	}
810 
811 	/* format this entry */
812 	snprintf(fmt, sizeof(fmt),
813 	    smp_Proc_format,
814 	    (int)PP(pp, pid),
815 	    namelength, namelength,
816 	    get_userid(PP(pp, ruid)),
817 	    (int)xnice,
818 	    format_k(PROCSIZE(pp)),
819 	    format_k(pagetok(VP(pp, rssize))),
820 	    status,
821 	    LP(pp, cpuid),
822 	    cputime_fmt,
823 	    ccputime_fmt,
824 	    100.0 * pct,
825 	    cmdlength,
826 	    cmdfield);
827 
828 	/* return the result */
829 	return (fmt);
830 }
831 
832 /* comparison routines for qsort */
833 
834 /*
835  *  proc_compare - comparison function for "qsort"
836  *	Compares the resource consumption of two processes using five
837  *  	distinct keys.  The keys (in descending order of importance) are:
838  *  	percent cpu, cpu ticks, state, resident set size, total virtual
839  *  	memory usage.  The process states are ordered as follows (from least
840  *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
841  *  	array declaration below maps a process state index into a number
842  *  	that reflects this ordering.
843  */
844 
845 static unsigned char sorted_state[] =
846 {
847 	0,			/* not used		 */
848 	3,			/* sleep		 */
849 	1,			/* ABANDONED (WAIT)	 */
850 	6,			/* run			 */
851 	5,			/* start		 */
852 	2,			/* zombie		 */
853 	4			/* stop			 */
854 };
855 
856 
857 #define ORDERKEY_PCTCPU \
858   if (lresult = (long) LP(p2, pctcpu) - (long) LP(p1, pctcpu), \
859      (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
860 
861 #define CPTICKS(p)	(LP(p, uticks) + LP(p, sticks) + LP(p, iticks))
862 
863 #define ORDERKEY_CPTICKS \
864   if ((result = CPTICKS(p2) > CPTICKS(p1) ? 1 : \
865 		CPTICKS(p2) < CPTICKS(p1) ? -1 : 0) == 0)
866 
867 #define CTIME(p)	(((LP(p, uticks) + LP(p, sticks) + LP(p, iticks))/1000000) + \
868   PP(p, cru).ru_stime.tv_sec + PP(p, cru).ru_utime.tv_sec)
869 
870 #define ORDERKEY_CTIME \
871    if ((result = CTIME(p2) > CTIME(p1) ? 1 : \
872 		CTIME(p2) < CTIME(p1) ? -1 : 0) == 0)
873 
874 #define ORDERKEY_STATE \
875   if ((result = sorted_state[(unsigned char) PP(p2, stat)] - \
876                 sorted_state[(unsigned char) PP(p1, stat)]) == 0)
877 
878 #define ORDERKEY_PRIO \
879   if ((result = LP(p2, prio) - LP(p1, prio)) == 0)
880 
881 #define ORDERKEY_KTHREADS \
882   if ((result = (LP(p1, pid) == 0) - (LP(p2, pid) == 0)) == 0)
883 
884 #define ORDERKEY_KTHREADS_PRIO \
885   if ((result = LP(p2, tdprio) - LP(p1, tdprio)) == 0)
886 
887 #define ORDERKEY_RSSIZE \
888   if ((result = VP(p2, rssize) - VP(p1, rssize)) == 0)
889 
890 #define ORDERKEY_MEM \
891   if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
892 
893 #define ORDERKEY_PID \
894   if ( (result = PP(p1, pid) - PP(p2, pid)) == 0)
895 
896 #define ORDERKEY_PRSSIZE \
897   if((result = VP(p2, prssize) - VP(p1, prssize)) == 0)
898 
899 static __inline int
900 orderkey_kernidle(const struct kinfo_proc *p1, const struct kinfo_proc *p2)
901 {
902 	int p1_kidle = 0, p2_kidle = 0;
903 
904 	if (LP(p1, pid) == -1 && PP(p1, stat) == SIDL)
905 		p1_kidle = 1;
906 	if (LP(p2, pid) == -1 && PP(p2, stat) == SIDL)
907 		p2_kidle = 1;
908 
909 	if (!p2_kidle && p1_kidle)
910 		return 1;
911 	if (p2_kidle && !p1_kidle)
912 		return -1;
913 	return 0;
914 }
915 
916 #define ORDERKEY_KIDLE	if ((result = orderkey_kernidle(p1, p2)) == 0)
917 
918 /* compare_cpu - the comparison function for sorting by cpu percentage */
919 
920 int
921 proc_compare(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
922 {
923 	struct kinfo_proc *p1;
924 	struct kinfo_proc *p2;
925 	int result;
926 	pctcpu lresult;
927 
928 	/* remove one level of indirection */
929 	p1 = *(struct kinfo_proc **) pp1;
930 	p2 = *(struct kinfo_proc **) pp2;
931 
932 	ORDERKEY_KIDLE
933 	ORDERKEY_PCTCPU
934 	ORDERKEY_CPTICKS
935 	ORDERKEY_STATE
936 	ORDERKEY_PRIO
937 	ORDERKEY_RSSIZE
938 	ORDERKEY_MEM
939 	{}
940 
941 	return (result);
942 }
943 
944 /* compare_size - the comparison function for sorting by total memory usage */
945 
946 int
947 compare_size(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
948 {
949 	struct kinfo_proc *p1;
950 	struct kinfo_proc *p2;
951 	int result;
952 	pctcpu lresult;
953 
954 	/* remove one level of indirection */
955 	p1 = *(struct kinfo_proc **) pp1;
956 	p2 = *(struct kinfo_proc **) pp2;
957 
958 	ORDERKEY_MEM
959 	ORDERKEY_RSSIZE
960 	ORDERKEY_KIDLE
961 	ORDERKEY_PCTCPU
962 	ORDERKEY_CPTICKS
963 	ORDERKEY_STATE
964 	ORDERKEY_PRIO
965 	{}
966 
967 	return (result);
968 }
969 
970 /* compare_res - the comparison function for sorting by resident set size */
971 
972 int
973 compare_res(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
974 {
975 	struct kinfo_proc *p1;
976 	struct kinfo_proc *p2;
977 	int result;
978 	pctcpu lresult;
979 
980 	/* remove one level of indirection */
981 	p1 = *(struct kinfo_proc **) pp1;
982 	p2 = *(struct kinfo_proc **) pp2;
983 
984 	ORDERKEY_RSSIZE
985 	ORDERKEY_MEM
986 	ORDERKEY_KIDLE
987 	ORDERKEY_PCTCPU
988 	ORDERKEY_CPTICKS
989 	ORDERKEY_STATE
990 	ORDERKEY_PRIO
991 	{}
992 
993 	return (result);
994 }
995 
996 /* compare_pres - the comparison function for sorting by proportional resident set size */
997 
998 int
999 compare_pres(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1000 {
1001 	struct kinfo_proc *p1;
1002 	struct kinfo_proc *p2;
1003 	int result;
1004 	pctcpu lresult;
1005 
1006 	/* remove one level of indirection */
1007 	p1 = *(struct kinfo_proc **) pp1;
1008 	p2 = *(struct kinfo_proc **) pp2;
1009 
1010 	ORDERKEY_PRSSIZE
1011 	ORDERKEY_RSSIZE
1012 	ORDERKEY_MEM
1013 	ORDERKEY_KIDLE
1014 	ORDERKEY_PCTCPU
1015 	ORDERKEY_CPTICKS
1016 	ORDERKEY_STATE
1017 	ORDERKEY_PRIO
1018 	{}
1019 
1020 	return (result);
1021 }
1022 
1023 /* compare_time - the comparison function for sorting by total cpu time */
1024 
1025 int
1026 compare_time(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1027 {
1028 	struct kinfo_proc *p1;
1029 	struct kinfo_proc *p2;
1030 	int result;
1031 	pctcpu lresult;
1032 
1033 	/* remove one level of indirection */
1034 	p1 = *(struct kinfo_proc **) pp1;
1035 	p2 = *(struct kinfo_proc **) pp2;
1036 
1037 	ORDERKEY_KIDLE
1038 	ORDERKEY_CPTICKS
1039 	ORDERKEY_PCTCPU
1040 	ORDERKEY_KTHREADS
1041 	ORDERKEY_KTHREADS_PRIO
1042 	ORDERKEY_STATE
1043 	ORDERKEY_PRIO
1044 	ORDERKEY_RSSIZE
1045 	ORDERKEY_MEM
1046 	{}
1047 
1048 	return (result);
1049 }
1050 
1051 int
1052 compare_ctime(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1053 {
1054 	struct kinfo_proc *p1;
1055 	struct kinfo_proc *p2;
1056 	int result;
1057 	pctcpu lresult;
1058 
1059 	/* remove one level of indirection */
1060 	p1 = *(struct kinfo_proc **) pp1;
1061 	p2 = *(struct kinfo_proc **) pp2;
1062 
1063 	ORDERKEY_KIDLE
1064 	ORDERKEY_CTIME
1065 	ORDERKEY_PCTCPU
1066 	ORDERKEY_KTHREADS
1067 	ORDERKEY_KTHREADS_PRIO
1068 	ORDERKEY_STATE
1069 	ORDERKEY_PRIO
1070 	ORDERKEY_RSSIZE
1071 	ORDERKEY_MEM
1072 	{}
1073 
1074 	return (result);
1075 }
1076 
1077 /* compare_prio - the comparison function for sorting by cpu percentage */
1078 
1079 int
1080 compare_prio(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1081 {
1082 	struct kinfo_proc *p1;
1083 	struct kinfo_proc *p2;
1084 	int result;
1085 	pctcpu lresult;
1086 
1087 	/* remove one level of indirection */
1088 	p1 = *(struct kinfo_proc **) pp1;
1089 	p2 = *(struct kinfo_proc **) pp2;
1090 
1091 	ORDERKEY_KTHREADS
1092 	ORDERKEY_KTHREADS_PRIO
1093 	ORDERKEY_PRIO
1094 	ORDERKEY_KIDLE
1095 	ORDERKEY_CPTICKS
1096 	ORDERKEY_PCTCPU
1097 	ORDERKEY_STATE
1098 	ORDERKEY_RSSIZE
1099 	ORDERKEY_MEM
1100 	{}
1101 
1102 	return (result);
1103 }
1104 
1105 int
1106 compare_thr(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1107 {
1108 	struct kinfo_proc *p1;
1109 	struct kinfo_proc *p2;
1110 	int result;
1111 	pctcpu lresult;
1112 
1113 	/* remove one level of indirection */
1114 	p1 = *(struct kinfo_proc **)pp1;
1115 	p2 = *(struct kinfo_proc **)pp2;
1116 
1117 	ORDERKEY_KTHREADS
1118 	ORDERKEY_KTHREADS_PRIO
1119 	ORDERKEY_KIDLE
1120 	ORDERKEY_CPTICKS
1121 	ORDERKEY_PCTCPU
1122 	ORDERKEY_STATE
1123 	ORDERKEY_RSSIZE
1124 	ORDERKEY_MEM
1125 	{}
1126 
1127 	return (result);
1128 }
1129 
1130 /* compare_pid - the comparison function for sorting by process id */
1131 
1132 int
1133 compare_pid(struct kinfo_proc **pp1, struct kinfo_proc **pp2)
1134 {
1135 	struct kinfo_proc *p1;
1136 	struct kinfo_proc *p2;
1137 	int result;
1138 
1139 	/* remove one level of indirection */
1140 	p1 = *(struct kinfo_proc **) pp1;
1141 	p2 = *(struct kinfo_proc **) pp2;
1142 
1143 	ORDERKEY_PID
1144 	;
1145 
1146 	return(result);
1147 }
1148 
1149 /*
1150  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1151  *		the process does not exist.
1152  *		It is EXTREMLY IMPORTANT that this function work correctly.
1153  *		If top runs setuid root (as in SVR4), then this function
1154  *		is the only thing that stands in the way of a serious
1155  *		security problem.  It validates requests for the "kill"
1156  *		and "renice" commands.
1157  */
1158 
1159 int
1160 proc_owner(int pid)
1161 {
1162 	int xcnt;
1163 	struct kinfo_proc **prefp;
1164 	struct kinfo_proc *pp;
1165 
1166 	prefp = pref;
1167 	xcnt = pref_len;
1168 	while (--xcnt >= 0) {
1169 		pp = *prefp++;
1170 		if (PP(pp, pid) == (pid_t) pid) {
1171 			return ((int)PP(pp, ruid));
1172 		}
1173 	}
1174 	return (-1);
1175 }
1176 
1177 
1178 /*
1179  * swapmode is based on a program called swapinfo written
1180  * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
1181  */
1182 int
1183 swapmode(int *retavail, int *retfree)
1184 {
1185 	int n;
1186 	int pagesize = getpagesize();
1187 	struct kvm_swap swapary[1];
1188 
1189 	*retavail = 0;
1190 	*retfree = 0;
1191 
1192 #define CONVERT(v)	((quad_t)(v) * pagesize / 1024)
1193 
1194 	n = kvm_getswapinfo(kd, swapary, 1, 0);
1195 	if (n < 0 || swapary[0].ksw_total == 0)
1196 		return (0);
1197 
1198 	*retavail = CONVERT(swapary[0].ksw_total);
1199 	*retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
1200 
1201 	n = (int)((double)swapary[0].ksw_used * 100.0 /
1202 	    (double)swapary[0].ksw_total);
1203 	return (n);
1204 }
1205