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