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