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