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