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