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 * 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 * 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 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 * 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 * 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 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 * 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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