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