Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_netbsd.c
blob7871e045fe12e683a3f30b85b059306d70f03134
1 /* $NetBSD: m_netbsd.c,v 1.10 2009/07/27 16:26:48 njoly Exp $ */
3 /*
4 * top - a top users display for Unix
6 * SYNOPSIS: For a NetBSD-1.5 (or later) system
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.
25 * LIBS: -lkvm
27 * CFLAGS: -DHAVE_GETOPT -DORDER -DHAVE_STRERROR
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>
40 * $Id: m_netbsd.c,v 1.11 2009/10/21 21:11:57 rmind Exp $
42 #include <sys/cdefs.h>
44 #ifndef lint
45 __RCSID("$NetBSD: m_netbsd.c,v 1.10 2009/07/27 16:26:48 njoly Exp $");
46 #endif
48 #include <sys/param.h>
49 #include <sys/sysctl.h>
50 #include <sys/sched.h>
51 #include <sys/swap.h>
53 #include <uvm/uvm_extern.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <kvm.h>
58 #include <math.h>
59 #include <nlist.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
65 #include "os.h"
66 #include "top.h"
67 #include "machine.h"
68 #include "utils.h"
69 #include "display.h"
70 #include "loadavg.h"
71 #include "username.h"
73 static void percentages64 __P((int, int *, u_int64_t *, u_int64_t *,
74 u_int64_t *));
75 static int get_cpunum __P((u_int64_t));
78 /* get_process_info passes back a handle. This is what it looks like: */
80 struct handle {
81 struct kinfo_proc2 **next_proc; /* points to next valid proc pointer */
82 int remaining; /* number of pointers remaining */
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))))
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
101 * These definitions control the format of the per-process area
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%% %.12s"
111 static char Thread_header[] =
112 " PID LID X PRI STATE TIME WCPU CPU COMMAND NAME";
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%% %-12.12s %.12s"
119 * Process state names for the "STATE" column of the display.
122 const char *state_abbrev[] = {
123 "", "IDLE", "RUN", "SLEEP", "STOP", "ZOMB", "DEAD", "CPU"
126 static kvm_t *kd;
128 static char *(*userprint)(int);
130 /* these are retrieved from the kernel in _init */
132 static double logcpu;
133 static int hz;
134 static int ccpu;
136 /* these are for calculating CPU state percentages */
138 static int ncpu = 0;
139 static u_int64_t *cp_time;
140 static u_int64_t *cp_id;
141 static u_int64_t *cp_old;
142 static u_int64_t *cp_diff;
144 /* these are for detailing the process states */
146 int process_states[8];
147 const char *procstatenames[] = {
148 "", " idle, ", " runnable, ", " sleeping, ", " stopped, ",
149 " zombie, ", " dead, ", " on CPU, ",
150 NULL
153 /* these are for detailing the CPU states */
155 int *cpu_states;
156 const char *cpustatenames[] = {
157 "user", "nice", "system", "interrupt", "idle", NULL
160 /* these are for detailing the memory statistics */
162 long memory_stats[7];
163 const char *memorynames[] = {
164 "K Act, ", "K Inact, ", "K Wired, ", "K Exec, ", "K File, ",
165 "K Free, ",
166 NULL
169 long swap_stats[4];
170 const char *swapnames[] = {
171 "K Total, ", "K Used, ", "K Free, ",
172 NULL
176 /* these are names given to allowed sorting orders -- first is default */
177 const char *ordernames[] = {
178 "cpu",
179 "pri",
180 "res",
181 "size",
182 "state",
183 "time",
184 "pid",
185 "command",
186 "username",
187 NULL
190 /* forward definitions for comparison functions */
191 static int compare_cpu __P((struct proc **, struct proc **));
192 static int compare_prio __P((struct proc **, struct proc **));
193 static int compare_res __P((struct proc **, struct proc **));
194 static int compare_size __P((struct proc **, struct proc **));
195 static int compare_state __P((struct proc **, struct proc **));
196 static int compare_time __P((struct proc **, struct proc **));
197 static int compare_pid __P((struct proc **, struct proc **));
198 static int compare_command __P((struct proc **, struct proc **));
199 static int compare_username __P((struct proc **, struct proc **));
201 int (*proc_compares[]) __P((struct proc **, struct proc **)) = {
202 compare_cpu,
203 compare_prio,
204 compare_res,
205 compare_size,
206 compare_state,
207 compare_time,
208 compare_pid,
209 compare_command,
210 compare_username,
211 NULL
214 static char *format_next_lwp(caddr_t, char *(*)(int));
215 static char *format_next_proc(caddr_t, char *(*)(int));
217 static caddr_t get_proc_info(struct system_info *, struct process_select *,
218 int (*)(struct proc **, struct proc **));
219 static caddr_t get_lwp_info(struct system_info *, struct process_select *,
220 int (*)(struct proc **, struct proc **));
222 /* these are for keeping track of the proc array */
224 static int nproc;
225 static int onproc = -1;
226 static int nlwp;
227 static int onlwp = -1;
228 static int pref_len;
229 static int lref_len;
230 static struct kinfo_proc2 *pbase;
231 static struct kinfo_lwp *lbase;
232 static struct kinfo_proc2 **pref;
233 static struct kinfo_lwp **lref;
234 static int maxswap;
235 static void *swapp;
236 static int procgen;
237 static int thread_nproc;
238 static int thread_onproc = -1;
239 static struct kinfo_proc2 *thread_pbase;
241 /* these are for getting the memory statistics */
243 static int pageshift; /* log base 2 of the pagesize */
245 int threadmode;
247 /* define pagetok in terms of pageshift */
249 #define pagetok(size) ((size) << pageshift)
251 static int
252 get_cpunum(id)
253 u_int64_t id;
255 int i = 0;
256 for (i = 0; i < ncpu; i++)
257 if (id == cp_id[i])
258 return i;
259 return -1;
263 machine_init(statics)
264 struct statics *statics;
266 int pagesize;
267 int mib[2];
268 size_t size;
269 struct clockinfo clockinfo;
270 struct timeval boottime;
272 if ((kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL)
273 return -1;
275 mib[0] = CTL_HW;
276 mib[1] = HW_NCPU;
277 size = sizeof(ncpu);
278 if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1) {
279 fprintf(stderr, "top: sysctl hw.ncpu failed: %s\n",
280 strerror(errno));
281 return(-1);
283 statics->ncpu = ncpu;
284 cp_time = malloc(sizeof(cp_time[0]) * CPUSTATES * ncpu);
285 mib[0] = CTL_KERN;
286 mib[1] = KERN_CP_TIME;
287 size = sizeof(cp_time[0]) * CPUSTATES * ncpu;
288 if (sysctl(mib, 2, cp_time, &size, NULL, 0) < 0) {
289 fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
290 strerror(errno));
291 return(-1);
294 /* Handle old call that returned only aggregate */
295 if (size == sizeof(cp_time[0]) * CPUSTATES)
296 ncpu = 1;
298 cp_id = malloc(sizeof(cp_id[0]) * ncpu);
299 mib[0] = CTL_KERN;
300 mib[1] = KERN_CP_ID;
301 size = sizeof(cp_id[0]) * ncpu;
302 if (sysctl(mib, 2, cp_id, &size, NULL, 0) < 0) {
303 fprintf(stderr, "top: sysctl kern.cp_id failed: %s\n",
304 strerror(errno));
305 return(-1);
307 cpu_states = malloc(sizeof(cpu_states[0]) * CPUSTATES * ncpu);
308 cp_old = malloc(sizeof(cp_old[0]) * CPUSTATES * ncpu);
309 cp_diff = malloc(sizeof(cp_diff[0]) * CPUSTATES * ncpu);
310 if (cpu_states == NULL || cp_time == NULL || cp_old == NULL ||
311 cp_diff == NULL) {
312 fprintf(stderr, "top: machine_init: %s\n",
313 strerror(errno));
314 return(-1);
317 mib[0] = CTL_KERN;
318 mib[1] = KERN_CCPU;
319 size = sizeof(ccpu);
320 if (sysctl(mib, 2, &ccpu, &size, NULL, 0) == -1) {
321 fprintf(stderr, "top: sysctl kern.ccpu failed: %s\n",
322 strerror(errno));
323 return(-1);
326 mib[0] = CTL_KERN;
327 mib[1] = KERN_CLOCKRATE;
328 size = sizeof(clockinfo);
329 if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1) {
330 fprintf(stderr, "top: sysctl kern.clockrate failed: %s\n",
331 strerror(errno));
332 return(-1);
334 hz = clockinfo.stathz;
336 /* this is used in calculating WCPU -- calculate it ahead of time */
337 logcpu = log(loaddouble(ccpu));
339 pbase = NULL;
340 lbase = NULL;
341 pref = NULL;
342 nproc = 0;
343 onproc = -1;
344 nlwp = 0;
345 onlwp = -1;
346 /* get the page size with "getpagesize" and calculate pageshift from it */
347 pagesize = getpagesize();
348 pageshift = 0;
349 while (pagesize > 1) {
350 pageshift++;
351 pagesize >>= 1;
354 /* we only need the amount of log(2)1024 for our conversion */
355 pageshift -= LOG1024;
357 /* fill in the statics information */
358 #ifdef notyet
359 statics->ncpu = ncpu;
360 #endif
361 statics->procstate_names = procstatenames;
362 statics->cpustate_names = cpustatenames;
363 statics->memory_names = memorynames;
364 statics->swap_names = swapnames;
365 statics->order_names = ordernames;
366 statics->flags.threads = 1;
368 mib[0] = CTL_KERN;
369 mib[1] = KERN_BOOTTIME;
370 size = sizeof(boottime);
371 if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
372 boottime.tv_sec != 0)
373 statics->boottime = boottime.tv_sec;
374 else
375 statics->boottime = 0;
376 /* all done! */
377 return(0);
380 char *
381 format_process_header(struct process_select *sel, caddr_t handle, int count)
384 char *header;
385 char *ptr;
386 const char *uname_field = sel->usernames ? "USERNAME" : " UID ";
388 if (sel->threads) {
389 header = Thread_header;
390 ptr = header + THREAD_UNAME_START;
391 } else {
392 header = Proc_header;
393 ptr = header + PROC_UNAME_START;
396 while (*uname_field != '\0') {
397 *ptr++ = *uname_field++;
400 return(header);
403 char *
404 format_header(char *uname_field)
406 char *header = Proc_header;
407 char *ptr = header + PROC_UNAME_START;
409 while (*uname_field != '\0') {
410 *ptr++ = *uname_field++;
413 return(header);
416 void
417 get_system_info(struct system_info *si)
419 size_t ssize;
420 int mib[2];
421 struct uvmexp_sysctl uvmexp;
422 struct swapent *sep;
423 u_int64_t totalsize, totalinuse;
424 int size, inuse, ncounted, i;
425 int rnswap, nswap;
427 mib[0] = CTL_KERN;
428 mib[1] = KERN_CP_TIME;
429 ssize = sizeof(cp_time[0]) * CPUSTATES * ncpu;
430 if (sysctl(mib, 2, cp_time, &ssize, NULL, 0) < 0) {
431 fprintf(stderr, "top: sysctl kern.cp_time failed: %s\n",
432 strerror(errno));
433 quit(23);
436 if (getloadavg(si->load_avg, NUM_AVERAGES) < 0) {
437 int j;
439 warn("can't getloadavg");
440 for (j = 0; j < NUM_AVERAGES; j++)
441 si->load_avg[j] = 0.0;
444 /* convert cp_time counts to percentages */
445 for (i = 0; i < ncpu; i++) {
446 int j = i * CPUSTATES;
447 percentages64(CPUSTATES, cpu_states + j, cp_time + j, cp_old + j,
448 cp_diff + j);
451 mib[0] = CTL_VM;
452 mib[1] = VM_UVMEXP2;
453 ssize = sizeof(uvmexp);
454 if (sysctl(mib, 2, &uvmexp, &ssize, NULL, 0) < 0) {
455 fprintf(stderr, "top: sysctl vm.uvmexp2 failed: %s\n",
456 strerror(errno));
457 quit(23);
460 /* convert memory stats to Kbytes */
461 memory_stats[0] = pagetok(uvmexp.active);
462 memory_stats[1] = pagetok(uvmexp.inactive);
463 memory_stats[2] = pagetok(uvmexp.wired);
464 memory_stats[3] = pagetok(uvmexp.execpages);
465 memory_stats[4] = pagetok(uvmexp.filepages);
466 memory_stats[5] = pagetok(uvmexp.free);
468 swap_stats[0] = swap_stats[1] = swap_stats[2] = 0;
470 do {
471 nswap = swapctl(SWAP_NSWAP, 0, 0);
472 if (nswap < 1)
473 break;
474 if (nswap > maxswap) {
475 if (swapp)
476 free(swapp);
477 swapp = sep = malloc(nswap * sizeof(*sep));
478 if (sep == NULL)
479 break;
480 maxswap = nswap;
481 } else
482 sep = swapp;
483 rnswap = swapctl(SWAP_STATS, (void *)sep, nswap);
484 if (nswap != rnswap)
485 break;
487 totalsize = totalinuse = ncounted = 0;
488 for (; rnswap-- > 0; sep++) {
489 ncounted++;
490 size = sep->se_nblks;
491 inuse = sep->se_inuse;
492 totalsize += size;
493 totalinuse += inuse;
495 swap_stats[0] = dbtob(totalsize) / 1024;
496 swap_stats[1] = dbtob(totalinuse) / 1024;
497 swap_stats[2] = dbtob(totalsize) / 1024 - swap_stats[1];
498 } while (0);
500 memory_stats[6] = -1;
501 swap_stats[3] = -1;
503 /* set arrays and strings */
504 si->cpustates = cpu_states;
505 si->memory = memory_stats;
506 si->swap = swap_stats;
507 si->last_pid = -1;
511 static struct kinfo_proc2 *
512 proc_from_thread(struct kinfo_lwp *pl)
514 struct kinfo_proc2 *pp = thread_pbase;
515 int i;
517 for (i = 0; i < thread_nproc; i++, pp++)
518 if ((pid_t)pp->p_pid == (pid_t)pl->l_pid)
519 return pp;
520 return NULL;
523 static int
524 uid_from_thread(struct kinfo_lwp *pl)
526 struct kinfo_proc2 *pp;
528 if ((pp = proc_from_thread(pl)) == NULL)
529 return -1;
530 return pp->p_ruid;
533 caddr_t
534 get_process_info(struct system_info *si, struct process_select *sel, int c)
536 userprint = sel->usernames ? username : itoa7;
538 if ((threadmode = sel->threads) != 0)
539 return get_lwp_info(si, sel, proc_compares[c]);
540 else
541 return get_proc_info(si, sel, proc_compares[c]);
544 static caddr_t
545 get_proc_info(struct system_info *si, struct process_select *sel,
546 int (*compare)(struct proc **, struct proc **))
548 int i;
549 int total_procs;
550 int active_procs;
551 struct kinfo_proc2 **prefp, **n;
552 struct kinfo_proc2 *pp;
553 int op, arg;
555 /* these are copied out of sel for speed */
556 int show_idle;
557 int show_system;
558 int show_uid;
559 int show_command;
561 static struct handle handle;
563 procgen++;
565 if (sel->pid == (pid_t)-1) {
566 op = KERN_PROC_ALL;
567 arg = 0;
568 } else {
569 op = KERN_PROC_PID;
570 arg = sel->pid;
573 pbase = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &nproc);
574 if (pbase == NULL) {
575 if (sel->pid != (pid_t)-1) {
576 nproc = 0;
577 } else {
578 (void) fprintf(stderr, "top: Out of memory.\n");
579 quit(23);
582 if (nproc > onproc) {
583 n = (struct kinfo_proc2 **) realloc(pref,
584 sizeof(struct kinfo_proc2 *) * nproc);
585 if (n == NULL) {
586 (void) fprintf(stderr, "top: Out of memory.\n");
587 quit(23);
589 pref = n;
590 onproc = nproc;
592 /* get a pointer to the states summary array */
593 si->procstates = process_states;
595 /* set up flags which define what we are going to select */
596 show_idle = sel->idle;
597 show_system = sel->system;
598 show_uid = sel->uid != -1;
599 show_command = sel->command != NULL;
601 /* count up process states and get pointers to interesting procs */
602 total_procs = 0;
603 active_procs = 0;
604 memset((char *)process_states, 0, sizeof(process_states));
605 prefp = pref;
606 for (pp = pbase, i = 0; i < nproc; pp++, i++) {
609 * Place pointers to each valid proc structure in pref[].
610 * Process slots that are actually in use have a non-zero
611 * status field. Processes with P_SYSTEM set are system
612 * processes---these get ignored unless show_sysprocs is set.
614 if (pp->p_stat != 0 && (show_system || ((pp->p_flag & P_SYSTEM) == 0))) {
615 total_procs++;
616 process_states[(unsigned char) pp->p_stat]++;
617 if (pp->p_stat != LSZOMB &&
618 (show_idle || (pp->p_pctcpu != 0) ||
619 (pp->p_stat == LSRUN || pp->p_stat == LSONPROC)) &&
620 (!show_uid || pp->p_ruid == (uid_t)sel->uid)) {
621 *prefp++ = pp;
622 active_procs++;
627 /* if requested, sort the "interesting" processes */
628 if (compare != NULL) {
629 qsort((char *)pref, active_procs, sizeof(struct kinfo_proc2 *),
630 (int (*)(const void *, const void *))compare);
633 /* remember active and total counts */
634 si->p_total = total_procs;
635 si->p_active = pref_len = active_procs;
637 /* pass back a handle */
638 handle.next_proc = pref;
639 handle.remaining = active_procs;
640 return((caddr_t)&handle);
643 static caddr_t
644 get_lwp_info(struct system_info *si, struct process_select *sel,
645 int (*compare)(struct proc **, struct proc **))
647 int i;
648 int total_lwps;
649 int active_lwps;
650 struct kinfo_lwp **lrefp, **n;
651 struct kinfo_lwp *lp;
652 struct kinfo_proc2 *pp;
654 /* these are copied out of sel for speed */
655 int show_idle;
656 int show_system;
657 int show_uid;
658 int show_command;
660 static struct handle handle;
662 pp = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc2),
663 &thread_nproc);
664 if (pp == NULL) {
665 (void) fprintf(stderr, "top: Out of memory.\n");
666 quit(23);
668 if (thread_pbase == NULL || thread_nproc != thread_onproc) {
669 free(thread_pbase);
670 thread_onproc = thread_nproc;
671 thread_pbase = calloc(sizeof(struct kinfo_proc2), thread_nproc);
672 if (thread_pbase == NULL) {
673 (void) fprintf(stderr, "top: Out of memory.\n");
674 quit(23);
677 memcpy(thread_pbase, pp, sizeof(struct kinfo_proc2) * thread_nproc);
679 lbase = kvm_getlwps(kd, -1, 0, sizeof(struct kinfo_lwp), &nlwp);
680 if (lbase == NULL) {
681 #ifdef notyet
682 if (sel->pid != (pid_t)-1) {
683 nproc = 0;
684 nlwp = 0;
686 else
687 #endif
689 (void) fprintf(stderr, "top: Out of memory.\n");
690 quit(23);
693 if (nlwp > onlwp) {
694 n = (struct kinfo_lwp **) realloc(lref,
695 sizeof(struct kinfo_lwp *) * nlwp);
696 if (n == NULL) {
697 (void) fprintf(stderr, "top: Out of memory.\n");
698 quit(23);
700 lref = n;
701 onlwp = nlwp;
703 /* get a pointer to the states summary array */
704 si->procstates = process_states;
706 /* set up flags which define what we are going to select */
707 show_idle = sel->idle;
708 show_system = sel->system;
709 show_uid = sel->uid != -1;
710 show_command = sel->command != NULL;
712 /* count up thread states and get pointers to interesting threads */
713 total_lwps = 0;
714 active_lwps = 0;
715 memset((char *)process_states, 0, sizeof(process_states));
716 lrefp = lref;
717 for (lp = lbase, i = 0; i < nlwp; lp++, i++) {
718 if (sel->pid != (pid_t)-1 && sel->pid != (pid_t)lp->l_pid)
719 continue;
722 * Place pointers to each valid lwp structure in lref[].
723 * thread slots that are actually in use have a non-zero
724 * status field. threads with L_SYSTEM set are system
725 * threads---these get ignored unless show_sysprocs is set.
727 if (lp->l_stat != 0 && (show_system || ((lp->l_flag & LW_SYSTEM) == 0))) {
728 total_lwps++;
729 process_states[(unsigned char) lp->l_stat]++;
730 if (lp->l_stat != LSZOMB &&
731 (show_idle || (lp->l_pctcpu != 0) ||
732 (lp->l_stat == LSRUN || lp->l_stat == LSONPROC)) &&
733 (!show_uid || uid_from_thread(lp) == sel->uid)) {
734 *lrefp++ = lp;
735 active_lwps++;
740 /* if requested, sort the "interesting" threads */
741 if (compare != NULL) {
742 qsort((char *)lref, active_lwps, sizeof(struct kinfo_lwp *),
743 (int (*)(const void *, const void *))compare);
746 /* remember active and total counts */
747 si->p_total = total_lwps;
748 si->p_active = lref_len = active_lwps;
750 /* pass back a handle */
751 handle.next_proc = (struct kinfo_proc2 **)lref;
752 handle.remaining = active_lwps;
754 return((caddr_t)&handle);
757 char *
758 format_next_process(caddr_t handle, char *(*get_userid)(int))
761 if (threadmode)
762 return format_next_lwp(handle, get_userid);
763 else
764 return format_next_proc(handle, get_userid);
768 char *
769 format_next_proc(caddr_t handle, char *(*get_userid)(int))
771 struct kinfo_proc2 *pp;
772 long cputime;
773 double pct, wcpu, cpu;
774 struct handle *hp;
775 const char *statep;
776 #ifdef KI_NOCPU
777 char state[10];
778 #endif
779 char wmesg[KI_WMESGLEN + 1];
780 static char fmt[MAX_COLS]; /* static area where result is built */
781 const char *pretty = "";
783 /* find and remember the next proc structure */
784 hp = (struct handle *)handle;
785 pp = *(hp->next_proc++);
786 hp->remaining--;
788 /* get the process's user struct and set cputime */
789 if ((pp->p_flag & P_SYSTEM) != 0)
790 pretty = "[]";
792 if (pretty[0] != '\0') {
794 * Print swapped processes as <pname> and
795 * system processes as [pname]
797 char *comm = pp->p_comm;
798 #define COMSIZ sizeof(pp->p_comm)
799 char buf[COMSIZ];
800 (void) strncpy(buf, comm, COMSIZ);
801 comm[0] = pretty[0];
802 (void) strncpy(&comm[1], buf, COMSIZ - 2);
803 comm[COMSIZ - 2] = '\0';
804 (void) strncat(comm, &pretty[1], COMSIZ - 1);
805 comm[COMSIZ - 1] = '\0';
808 #if 0
809 /* This does not produce the correct results */
810 cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks;
811 #else
812 cputime = pp->p_rtime_sec; /* This does not count interrupts */
813 #endif
815 /* calculate the base for CPU percentages */
816 pct = pctdouble(pp->p_pctcpu);
818 if (pp->p_stat == LSSLEEP) {
819 strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg));
820 statep = wmesg;
821 } else
822 statep = state_abbrev[(unsigned)pp->p_stat];
824 #ifdef KI_NOCPU
825 /* Post-1.5 change: add CPU number if appropriate */
826 if (pp->p_cpuid != KI_NOCPU && ncpu > 1) {
827 switch (pp->p_stat) {
828 case LSONPROC:
829 case LSRUN:
830 case LSSLEEP:
831 case LSIDL:
832 (void)snprintf(state, sizeof(state), "%.6s/%d",
833 statep, get_cpunum(pp->p_cpuid));
834 statep = state;
835 break;
838 #endif
839 wcpu = 100.0 * weighted_cpu(p_, pct, pp);
840 cpu = 100.0 * pct;
842 /* format this entry */
843 sprintf(fmt,
844 Proc_format,
845 pp->p_pid,
846 (*userprint)(pp->p_ruid),
847 pp->p_priority,
848 pp->p_nice - NZERO,
849 format_k(pagetok(PROCSIZE(pp))),
850 format_k(pagetok(pp->p_vm_rssize)),
851 statep,
852 format_time(cputime),
853 (wcpu >= 100.0) ? 0 : 2, wcpu,
854 (cpu >= 100.0) ? 0 : 2, cpu,
855 printable(pp->p_comm));
857 /* return the result */
858 return(fmt);
861 static char *
862 format_next_lwp(caddr_t handle, char *(*get_userid)(int))
864 struct kinfo_proc2 *pp;
865 struct kinfo_lwp *pl;
866 long cputime;
867 double pct;
868 struct handle *hp;
869 const char *statep;
870 static char gone[] = "<gone>";
871 #ifdef KI_NOCPU
872 char state[10];
873 #endif
874 char wmesg[KI_WMESGLEN + 1];
875 static char fmt[MAX_COLS]; /* static area where result is built */
876 const char *pretty = "";
877 char *comm;
878 int uid;
880 /* find and remember the next proc structure */
881 hp = (struct handle *)handle;
882 pl = (struct kinfo_lwp *)*(hp->next_proc++);
883 hp->remaining--;
884 pp = proc_from_thread(pl);
886 /* get the process's user struct and set cputime */
887 if (pp) {
888 comm = pp->p_comm;
889 if ((pp->p_flag & P_SYSTEM) != 0)
890 pretty = "[]";
892 if (pretty[0] != '\0' && comm[0] != pretty[0]) {
894 * Print swapped processes as <pname> and
895 * system processes as [pname]
897 #define COMSIZ sizeof(pp->p_comm)
898 char buf[COMSIZ];
899 (void) strncpy(buf, comm, COMSIZ);
900 comm[0] = pretty[0];
901 (void) strncpy(&comm[1], buf, COMSIZ - 2);
902 comm[COMSIZ - 2] = '\0';
903 (void) strncat(comm, &pretty[1], COMSIZ - 1);
904 comm[COMSIZ - 1] = '\0';
906 uid = pp->p_ruid;
907 } else {
908 comm = gone;
909 uid = 0;
912 cputime = pl->l_rtime_sec;
914 /* calculate the base for CPU percentages */
915 pct = pctdouble(pl->l_pctcpu);
917 if (pl->l_stat == LSSLEEP) {
918 strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg));
919 statep = wmesg;
920 } else
921 statep = state_abbrev[(unsigned)pl->l_stat];
923 #ifdef KI_NOCPU
924 /* Post-1.5 change: add CPU number if appropriate */
925 if (pl->l_cpuid != KI_NOCPU && ncpu > 1) {
926 switch (pl->l_stat) {
927 case LSONPROC:
928 case LSRUN:
929 case LSSLEEP:
930 case LSIDL:
931 (void)snprintf(state, sizeof(state), "%.6s/%d",
932 statep, get_cpunum(pl->l_cpuid));
933 statep = state;
934 break;
937 #endif
939 if (pl->l_name[0] == '\0') {
940 pl->l_name[0] = '-';
941 pl->l_name[1] = '\0';
944 /* format this entry */
945 sprintf(fmt,
946 Thread_format,
947 pl->l_pid,
948 pl->l_lid,
949 (*userprint)(uid),
950 pl->l_priority,
951 statep,
952 format_time(cputime),
953 100.0 * weighted_cpu(l_, pct, pl),
954 100.0 * pct,
955 printable(comm),
956 printable(pl->l_name));
958 /* return the result */
959 return(fmt);
962 /* comparison routines for qsort */
965 * There are currently four possible comparison routines. main selects
966 * one of these by indexing in to the array proc_compares.
968 * Possible keys are defined as macros below. Currently these keys are
969 * defined: percent CPU, CPU ticks, process state, resident set size,
970 * total virtual memory usage. The process states are ordered as follows
971 * (from least to most important): WAIT, zombie, sleep, stop, start, run.
972 * The array declaration below maps a process state index into a number
973 * that reflects this ordering.
977 * First, the possible comparison keys. These are defined in such a way
978 * that they can be merely listed in the source code to define the actual
979 * desired ordering.
982 #define ORDERKEY_PCTCPU(pfx) \
983 if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\
984 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
986 #define ORDERKEY_CPTICKS(pfx) \
987 if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \
988 - (pctcpu)(p1)->pfx ## rtime_sec,\
989 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
991 #define ORDERKEY_STATE(pfx) \
992 if ((result = sorted_state[(int)(p2)->pfx ## stat] - \
993 sorted_state[(int)(p1)->pfx ## stat] ) == 0)
995 #define ORDERKEY_PRIO(pfx) \
996 if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0)
998 #define ORDERKEY_RSSIZE \
999 if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0)
1001 #define ORDERKEY_MEM \
1002 if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0)
1003 #define ORDERKEY_SIZE(v1, v2) \
1004 if ((result = (v2 - v1)) == 0)
1007 * Now the array that maps process state to a weight.
1008 * The order of the elements should match those in state_abbrev[]
1011 static int sorted_state[] = {
1012 0, /* (not used) ? */
1013 1, /* "start" SIDL */
1014 4, /* "run" SRUN */
1015 3, /* "sleep" SSLEEP */
1016 3, /* "stop" SSTOP */
1017 2, /* "dead" SDEAD */
1018 1, /* "zomb" SZOMB */
1019 5, /* "onproc" SONPROC */
1022 /* compare_cpu - the comparison function for sorting by CPU percentage */
1024 static int
1025 compare_cpu(pp1, pp2)
1026 struct proc **pp1, **pp2;
1028 int result;
1029 pctcpu lresult;
1031 if (threadmode) {
1032 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1033 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1035 ORDERKEY_PCTCPU(l_)
1036 ORDERKEY_CPTICKS(l_)
1037 ORDERKEY_STATE(l_)
1038 ORDERKEY_PRIO(l_)
1039 return result;
1040 } else {
1041 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1042 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1044 ORDERKEY_PCTCPU(p_)
1045 ORDERKEY_CPTICKS(p_)
1046 ORDERKEY_STATE(p_)
1047 ORDERKEY_PRIO(p_)
1048 ORDERKEY_RSSIZE
1049 ORDERKEY_MEM
1050 return result;
1053 return (result);
1056 /* compare_prio - the comparison function for sorting by process priority */
1058 static int
1059 compare_prio(pp1, pp2)
1060 struct proc **pp1, **pp2;
1062 int result;
1063 pctcpu lresult;
1065 if (threadmode) {
1066 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1067 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1069 ORDERKEY_PRIO(l_)
1070 ORDERKEY_PCTCPU(l_)
1071 ORDERKEY_CPTICKS(l_)
1072 ORDERKEY_STATE(l_)
1073 return result;
1074 } else {
1075 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1076 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1078 ORDERKEY_PRIO(p_)
1079 ORDERKEY_PCTCPU(p_)
1080 ORDERKEY_CPTICKS(p_)
1081 ORDERKEY_STATE(p_)
1082 ORDERKEY_RSSIZE
1083 ORDERKEY_MEM
1084 return result;
1087 return (result);
1090 /* compare_res - the comparison function for sorting by resident set size */
1092 static int
1093 compare_res(pp1, pp2)
1094 struct proc **pp1, **pp2;
1096 int result;
1097 pctcpu lresult;
1099 if (threadmode) {
1100 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1101 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1103 ORDERKEY_PCTCPU(l_)
1104 ORDERKEY_CPTICKS(l_)
1105 ORDERKEY_STATE(l_)
1106 ORDERKEY_PRIO(l_)
1107 return result;
1108 } else {
1109 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1110 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1112 ORDERKEY_RSSIZE
1113 ORDERKEY_MEM
1114 ORDERKEY_PCTCPU(p_)
1115 ORDERKEY_CPTICKS(p_)
1116 ORDERKEY_STATE(p_)
1117 ORDERKEY_PRIO(p_)
1118 return result;
1121 return (result);
1124 static int
1125 compare_pid(pp1, pp2)
1126 struct proc **pp1, **pp2;
1128 if (threadmode) {
1129 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
1130 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
1131 struct kinfo_proc2 *p1 = proc_from_thread(l1);
1132 struct kinfo_proc2 *p2 = proc_from_thread(l2);
1133 return p2->p_pid - p1->p_pid;
1134 } else {
1135 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1136 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1137 return p2->p_pid - p1->p_pid;
1141 static int
1142 compare_command(pp1, pp2)
1143 struct proc **pp1, **pp2;
1145 if (threadmode) {
1146 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
1147 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
1148 struct kinfo_proc2 *p1 = proc_from_thread(l1);
1149 struct kinfo_proc2 *p2 = proc_from_thread(l2);
1150 return strcmp(p2->p_comm, p1->p_comm);
1151 } else {
1152 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1153 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1154 return strcmp(p2->p_comm, p1->p_comm);
1158 static int
1159 compare_username(pp1, pp2)
1160 struct proc **pp1, **pp2;
1162 if (threadmode) {
1163 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1;
1164 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2;
1165 struct kinfo_proc2 *p1 = proc_from_thread(l1);
1166 struct kinfo_proc2 *p2 = proc_from_thread(l2);
1167 return strcmp(p2->p_login, p1->p_login);
1168 } else {
1169 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1170 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1171 return strcmp(p2->p_login, p1->p_login);
1174 /* compare_size - the comparison function for sorting by total memory usage */
1176 static int
1177 compare_size(pp1, pp2)
1178 struct proc **pp1, **pp2;
1180 int result;
1181 pctcpu lresult;
1183 if (threadmode) {
1184 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1185 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1187 ORDERKEY_PCTCPU(l_)
1188 ORDERKEY_CPTICKS(l_)
1189 ORDERKEY_STATE(l_)
1190 ORDERKEY_PRIO(l_)
1191 return result;
1192 } else {
1193 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1194 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1196 ORDERKEY_MEM
1197 ORDERKEY_RSSIZE
1198 ORDERKEY_PCTCPU(p_)
1199 ORDERKEY_CPTICKS(p_)
1200 ORDERKEY_STATE(p_)
1201 ORDERKEY_PRIO(p_)
1202 return result;
1205 return (result);
1208 /* compare_state - the comparison function for sorting by process state */
1210 static int
1211 compare_state(pp1, pp2)
1212 struct proc **pp1, **pp2;
1214 int result;
1215 pctcpu lresult;
1217 if (threadmode) {
1218 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1219 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1221 ORDERKEY_STATE(l_)
1222 ORDERKEY_PCTCPU(l_)
1223 ORDERKEY_CPTICKS(l_)
1224 ORDERKEY_PRIO(l_)
1225 return result;
1226 } else {
1227 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1228 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1230 ORDERKEY_STATE(p_)
1231 ORDERKEY_PCTCPU(p_)
1232 ORDERKEY_CPTICKS(p_)
1233 ORDERKEY_PRIO(p_)
1234 ORDERKEY_RSSIZE
1235 ORDERKEY_MEM
1236 return result;
1239 return (result);
1242 /* compare_time - the comparison function for sorting by total CPU time */
1244 static int
1245 compare_time(pp1, pp2)
1246 struct proc **pp1, **pp2;
1248 int result;
1249 pctcpu lresult;
1251 if (threadmode) {
1252 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1;
1253 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2;
1255 ORDERKEY_CPTICKS(l_)
1256 ORDERKEY_PCTCPU(l_)
1257 ORDERKEY_STATE(l_)
1258 ORDERKEY_PRIO(l_)
1259 return result;
1260 } else {
1261 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1;
1262 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2;
1264 ORDERKEY_CPTICKS(p_)
1265 ORDERKEY_PCTCPU(p_)
1266 ORDERKEY_STATE(p_)
1267 ORDERKEY_PRIO(p_)
1268 ORDERKEY_MEM
1269 ORDERKEY_RSSIZE
1270 return result;
1273 return (result);
1278 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1279 * the process does not exist.
1280 * It is EXTREMLY IMPORTANT that this function work correctly.
1281 * If top runs setuid root (as in SVR4), then this function
1282 * is the only thing that stands in the way of a serious
1283 * security problem. It validates requests for the "kill"
1284 * and "renice" commands.
1288 proc_owner(pid)
1289 int pid;
1291 int cnt;
1292 struct kinfo_proc2 **prefp;
1293 struct kinfo_proc2 *pp;
1295 if (threadmode)
1296 return(-1);
1298 prefp = pref;
1299 cnt = pref_len;
1300 while (--cnt >= 0) {
1301 pp = *prefp++;
1302 if (pp->p_pid == (pid_t)pid)
1303 return(pp->p_ruid);
1305 return(-1);
1309 * percentages(cnt, out, new, old, diffs) - calculate percentage change
1310 * between array "old" and "new", putting the percentages i "out".
1311 * "cnt" is size of each array and "diffs" is used for scratch space.
1312 * The array "old" is updated on each call.
1313 * The routine assumes modulo arithmetic. This function is especially
1314 * useful on BSD mchines for calculating CPU state percentages.
1317 static void
1318 percentages64(cnt, out, new, old, diffs)
1319 int cnt;
1320 int *out;
1321 u_int64_t *new;
1322 u_int64_t *old;
1323 u_int64_t *diffs;
1325 int i;
1326 u_int64_t change;
1327 u_int64_t total_change;
1328 u_int64_t *dp;
1329 u_int64_t half_total;
1331 /* initialization */
1332 total_change = 0;
1333 dp = diffs;
1335 /* calculate changes for each state and the overall change */
1336 for (i = 0; i < cnt; i++) {
1338 * Don't worry about wrapping - even at hz=1GHz, a
1339 * u_int64_t will last at least 544 years.
1341 change = *new - *old;
1342 total_change += (*dp++ = change);
1343 *old++ = *new++;
1346 /* avoid divide by zero potential */
1347 if (total_change == 0)
1348 total_change = 1;
1350 /* calculate percentages based on overall change, rounding up */
1351 half_total = total_change / 2;
1352 for (i = 0; i < cnt; i++)
1353 *out++ = (int)((*diffs++ * 1000 + half_total) / total_change);