1 /* $NetBSD: m_netbsd.c,v 1.10 2009/07/27 16:26:48 njoly 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.10 2009/07/27 16:26:48 njoly Exp $ 41 */ 42 #include <sys/cdefs.h> 43 44 #ifndef lint 45 __RCSID("$NetBSD: m_netbsd.c,v 1.10 2009/07/27 16:26:48 njoly 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 & L_INMEM) == 0) 790 pretty = "<>"; 791 else if ((pp->p_flag & P_SYSTEM) != 0) 792 pretty = "[]"; 793 794 if (pretty[0] != '\0') { 795 /* 796 * Print swapped processes as <pname> and 797 * system processes as [pname] 798 */ 799 char *comm = pp->p_comm; 800 #define COMSIZ sizeof(pp->p_comm) 801 char buf[COMSIZ]; 802 (void) strncpy(buf, comm, COMSIZ); 803 comm[0] = pretty[0]; 804 (void) strncpy(&comm[1], buf, COMSIZ - 2); 805 comm[COMSIZ - 2] = '\0'; 806 (void) strncat(comm, &pretty[1], COMSIZ - 1); 807 comm[COMSIZ - 1] = '\0'; 808 } 809 810 #if 0 811 /* This does not produce the correct results */ 812 cputime = pp->p_uticks + pp->p_sticks + pp->p_iticks; 813 #else 814 cputime = pp->p_rtime_sec; /* This does not count interrupts */ 815 #endif 816 817 /* calculate the base for CPU percentages */ 818 pct = pctdouble(pp->p_pctcpu); 819 820 if (pp->p_stat == LSSLEEP) { 821 strlcpy(wmesg, pp->p_wmesg, sizeof(wmesg)); 822 statep = wmesg; 823 } else 824 statep = state_abbrev[(unsigned)pp->p_stat]; 825 826 #ifdef KI_NOCPU 827 /* Post-1.5 change: add CPU number if appropriate */ 828 if (pp->p_cpuid != KI_NOCPU && ncpu > 1) { 829 switch (pp->p_stat) { 830 case LSONPROC: 831 case LSRUN: 832 case LSSLEEP: 833 case LSIDL: 834 (void)snprintf(state, sizeof(state), "%.6s/%d", 835 statep, get_cpunum(pp->p_cpuid)); 836 statep = state; 837 break; 838 } 839 } 840 #endif 841 wcpu = 100.0 * weighted_cpu(p_, pct, pp); 842 cpu = 100.0 * pct; 843 844 /* format this entry */ 845 sprintf(fmt, 846 Proc_format, 847 pp->p_pid, 848 (*userprint)(pp->p_ruid), 849 pp->p_priority, 850 pp->p_nice - NZERO, 851 format_k(pagetok(PROCSIZE(pp))), 852 format_k(pagetok(pp->p_vm_rssize)), 853 statep, 854 format_time(cputime), 855 (wcpu >= 100.0) ? 0 : 2, wcpu, 856 (cpu >= 100.0) ? 0 : 2, cpu, 857 printable(pp->p_comm)); 858 859 /* return the result */ 860 return(fmt); 861 } 862 863 static char * 864 format_next_lwp(caddr_t handle, char *(*get_userid)(int)) 865 { 866 struct kinfo_proc2 *pp; 867 struct kinfo_lwp *pl; 868 long cputime; 869 double pct; 870 struct handle *hp; 871 const char *statep; 872 static char gone[] = "<gone>"; 873 #ifdef KI_NOCPU 874 char state[10]; 875 #endif 876 char wmesg[KI_WMESGLEN + 1]; 877 static char fmt[MAX_COLS]; /* static area where result is built */ 878 const char *pretty = ""; 879 char *comm; 880 int uid; 881 882 /* find and remember the next proc structure */ 883 hp = (struct handle *)handle; 884 pl = (struct kinfo_lwp *)*(hp->next_proc++); 885 hp->remaining--; 886 pp = proc_from_thread(pl); 887 888 /* get the process's user struct and set cputime */ 889 if (pp) { 890 comm = pp->p_comm; 891 #if 0 892 /* XXX needs to be per thread but is not. just ignore for now. */ 893 if ((pp->p_flag & L_INMEM) == 0) 894 pretty = "<>"; 895 else 896 #endif 897 if ((pp->p_flag & P_SYSTEM) != 0) 898 pretty = "[]"; 899 900 if (pretty[0] != '\0' && comm[0] != pretty[0]) { 901 /* 902 * Print swapped processes as <pname> and 903 * system processes as [pname] 904 */ 905 #define COMSIZ sizeof(pp->p_comm) 906 char buf[COMSIZ]; 907 (void) strncpy(buf, comm, COMSIZ); 908 comm[0] = pretty[0]; 909 (void) strncpy(&comm[1], buf, COMSIZ - 2); 910 comm[COMSIZ - 2] = '\0'; 911 (void) strncat(comm, &pretty[1], COMSIZ - 1); 912 comm[COMSIZ - 1] = '\0'; 913 } 914 uid = pp->p_ruid; 915 } else { 916 comm = gone; 917 uid = 0; 918 } 919 920 cputime = pl->l_rtime_sec; 921 922 /* calculate the base for CPU percentages */ 923 pct = pctdouble(pl->l_pctcpu); 924 925 if (pl->l_stat == LSSLEEP) { 926 strlcpy(wmesg, pl->l_wmesg, sizeof(wmesg)); 927 statep = wmesg; 928 } else 929 statep = state_abbrev[(unsigned)pl->l_stat]; 930 931 #ifdef KI_NOCPU 932 /* Post-1.5 change: add CPU number if appropriate */ 933 if (pl->l_cpuid != KI_NOCPU && ncpu > 1) { 934 switch (pl->l_stat) { 935 case LSONPROC: 936 case LSRUN: 937 case LSSLEEP: 938 case LSIDL: 939 (void)snprintf(state, sizeof(state), "%.6s/%d", 940 statep, get_cpunum(pl->l_cpuid)); 941 statep = state; 942 break; 943 } 944 } 945 #endif 946 947 if (pl->l_name[0] == '\0') { 948 pl->l_name[0] = '-'; 949 pl->l_name[1] = '\0'; 950 } 951 952 /* format this entry */ 953 sprintf(fmt, 954 Thread_format, 955 pl->l_pid, 956 pl->l_lid, 957 (*userprint)(uid), 958 pl->l_priority, 959 statep, 960 format_time(cputime), 961 100.0 * weighted_cpu(l_, pct, pl), 962 100.0 * pct, 963 printable(comm), 964 printable(pl->l_name)); 965 966 /* return the result */ 967 return(fmt); 968 } 969 970 /* comparison routines for qsort */ 971 972 /* 973 * There are currently four possible comparison routines. main selects 974 * one of these by indexing in to the array proc_compares. 975 * 976 * Possible keys are defined as macros below. Currently these keys are 977 * defined: percent CPU, CPU ticks, process state, resident set size, 978 * total virtual memory usage. The process states are ordered as follows 979 * (from least to most important): WAIT, zombie, sleep, stop, start, run. 980 * The array declaration below maps a process state index into a number 981 * that reflects this ordering. 982 */ 983 984 /* 985 * First, the possible comparison keys. These are defined in such a way 986 * that they can be merely listed in the source code to define the actual 987 * desired ordering. 988 */ 989 990 #define ORDERKEY_PCTCPU(pfx) \ 991 if (lresult = (pctcpu)(p2)->pfx ## pctcpu - (pctcpu)(p1)->pfx ## pctcpu,\ 992 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 993 994 #define ORDERKEY_CPTICKS(pfx) \ 995 if (lresult = (pctcpu)(p2)->pfx ## rtime_sec \ 996 - (pctcpu)(p1)->pfx ## rtime_sec,\ 997 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 998 999 #define ORDERKEY_STATE(pfx) \ 1000 if ((result = sorted_state[(int)(p2)->pfx ## stat] - \ 1001 sorted_state[(int)(p1)->pfx ## stat] ) == 0) 1002 1003 #define ORDERKEY_PRIO(pfx) \ 1004 if ((result = (p2)->pfx ## priority - (p1)->pfx ## priority) == 0) 1005 1006 #define ORDERKEY_RSSIZE \ 1007 if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0) 1008 1009 #define ORDERKEY_MEM \ 1010 if ((result = (PROCSIZE(p2) - PROCSIZE(p1))) == 0) 1011 #define ORDERKEY_SIZE(v1, v2) \ 1012 if ((result = (v2 - v1)) == 0) 1013 1014 /* 1015 * Now the array that maps process state to a weight. 1016 * The order of the elements should match those in state_abbrev[] 1017 */ 1018 1019 static int sorted_state[] = { 1020 0, /* (not used) ? */ 1021 1, /* "start" SIDL */ 1022 4, /* "run" SRUN */ 1023 3, /* "sleep" SSLEEP */ 1024 3, /* "stop" SSTOP */ 1025 2, /* "dead" SDEAD */ 1026 1, /* "zomb" SZOMB */ 1027 5, /* "onproc" SONPROC */ 1028 }; 1029 1030 /* compare_cpu - the comparison function for sorting by CPU percentage */ 1031 1032 static int 1033 compare_cpu(pp1, pp2) 1034 struct proc **pp1, **pp2; 1035 { 1036 int result; 1037 pctcpu lresult; 1038 1039 if (threadmode) { 1040 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1041 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1042 1043 ORDERKEY_PCTCPU(l_) 1044 ORDERKEY_CPTICKS(l_) 1045 ORDERKEY_STATE(l_) 1046 ORDERKEY_PRIO(l_) 1047 return result; 1048 } else { 1049 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1050 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1051 1052 ORDERKEY_PCTCPU(p_) 1053 ORDERKEY_CPTICKS(p_) 1054 ORDERKEY_STATE(p_) 1055 ORDERKEY_PRIO(p_) 1056 ORDERKEY_RSSIZE 1057 ORDERKEY_MEM 1058 return result; 1059 } 1060 1061 return (result); 1062 } 1063 1064 /* compare_prio - the comparison function for sorting by process priority */ 1065 1066 static int 1067 compare_prio(pp1, pp2) 1068 struct proc **pp1, **pp2; 1069 { 1070 int result; 1071 pctcpu lresult; 1072 1073 if (threadmode) { 1074 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1075 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1076 1077 ORDERKEY_PRIO(l_) 1078 ORDERKEY_PCTCPU(l_) 1079 ORDERKEY_CPTICKS(l_) 1080 ORDERKEY_STATE(l_) 1081 return result; 1082 } else { 1083 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1084 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1085 1086 ORDERKEY_PRIO(p_) 1087 ORDERKEY_PCTCPU(p_) 1088 ORDERKEY_CPTICKS(p_) 1089 ORDERKEY_STATE(p_) 1090 ORDERKEY_RSSIZE 1091 ORDERKEY_MEM 1092 return result; 1093 } 1094 1095 return (result); 1096 } 1097 1098 /* compare_res - the comparison function for sorting by resident set size */ 1099 1100 static int 1101 compare_res(pp1, pp2) 1102 struct proc **pp1, **pp2; 1103 { 1104 int result; 1105 pctcpu lresult; 1106 1107 if (threadmode) { 1108 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1109 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1110 1111 ORDERKEY_PCTCPU(l_) 1112 ORDERKEY_CPTICKS(l_) 1113 ORDERKEY_STATE(l_) 1114 ORDERKEY_PRIO(l_) 1115 return result; 1116 } else { 1117 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1118 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1119 1120 ORDERKEY_RSSIZE 1121 ORDERKEY_MEM 1122 ORDERKEY_PCTCPU(p_) 1123 ORDERKEY_CPTICKS(p_) 1124 ORDERKEY_STATE(p_) 1125 ORDERKEY_PRIO(p_) 1126 return result; 1127 } 1128 1129 return (result); 1130 } 1131 1132 static int 1133 compare_pid(pp1, pp2) 1134 struct proc **pp1, **pp2; 1135 { 1136 if (threadmode) { 1137 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 1138 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 1139 struct kinfo_proc2 *p1 = proc_from_thread(l1); 1140 struct kinfo_proc2 *p2 = proc_from_thread(l2); 1141 return p2->p_pid - p1->p_pid; 1142 } else { 1143 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1144 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1145 return p2->p_pid - p1->p_pid; 1146 } 1147 } 1148 1149 static int 1150 compare_command(pp1, pp2) 1151 struct proc **pp1, **pp2; 1152 { 1153 if (threadmode) { 1154 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 1155 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 1156 struct kinfo_proc2 *p1 = proc_from_thread(l1); 1157 struct kinfo_proc2 *p2 = proc_from_thread(l2); 1158 return strcmp(p2->p_comm, p1->p_comm); 1159 } else { 1160 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1161 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1162 return strcmp(p2->p_comm, p1->p_comm); 1163 } 1164 } 1165 1166 static int 1167 compare_username(pp1, pp2) 1168 struct proc **pp1, **pp2; 1169 { 1170 if (threadmode) { 1171 struct kinfo_lwp *l1 = *(struct kinfo_lwp **) pp1; 1172 struct kinfo_lwp *l2 = *(struct kinfo_lwp **) pp2; 1173 struct kinfo_proc2 *p1 = proc_from_thread(l1); 1174 struct kinfo_proc2 *p2 = proc_from_thread(l2); 1175 return strcmp(p2->p_login, p1->p_login); 1176 } else { 1177 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1178 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1179 return strcmp(p2->p_login, p1->p_login); 1180 } 1181 } 1182 /* compare_size - the comparison function for sorting by total memory usage */ 1183 1184 static int 1185 compare_size(pp1, pp2) 1186 struct proc **pp1, **pp2; 1187 { 1188 int result; 1189 pctcpu lresult; 1190 1191 if (threadmode) { 1192 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1193 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1194 1195 ORDERKEY_PCTCPU(l_) 1196 ORDERKEY_CPTICKS(l_) 1197 ORDERKEY_STATE(l_) 1198 ORDERKEY_PRIO(l_) 1199 return result; 1200 } else { 1201 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1202 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1203 1204 ORDERKEY_MEM 1205 ORDERKEY_RSSIZE 1206 ORDERKEY_PCTCPU(p_) 1207 ORDERKEY_CPTICKS(p_) 1208 ORDERKEY_STATE(p_) 1209 ORDERKEY_PRIO(p_) 1210 return result; 1211 } 1212 1213 return (result); 1214 } 1215 1216 /* compare_state - the comparison function for sorting by process state */ 1217 1218 static int 1219 compare_state(pp1, pp2) 1220 struct proc **pp1, **pp2; 1221 { 1222 int result; 1223 pctcpu lresult; 1224 1225 if (threadmode) { 1226 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1227 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1228 1229 ORDERKEY_STATE(l_) 1230 ORDERKEY_PCTCPU(l_) 1231 ORDERKEY_CPTICKS(l_) 1232 ORDERKEY_PRIO(l_) 1233 return result; 1234 } else { 1235 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1236 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1237 1238 ORDERKEY_STATE(p_) 1239 ORDERKEY_PCTCPU(p_) 1240 ORDERKEY_CPTICKS(p_) 1241 ORDERKEY_PRIO(p_) 1242 ORDERKEY_RSSIZE 1243 ORDERKEY_MEM 1244 return result; 1245 } 1246 1247 return (result); 1248 } 1249 1250 /* compare_time - the comparison function for sorting by total CPU time */ 1251 1252 static int 1253 compare_time(pp1, pp2) 1254 struct proc **pp1, **pp2; 1255 { 1256 int result; 1257 pctcpu lresult; 1258 1259 if (threadmode) { 1260 struct kinfo_lwp *p1 = *(struct kinfo_lwp **) pp1; 1261 struct kinfo_lwp *p2 = *(struct kinfo_lwp **) pp2; 1262 1263 ORDERKEY_CPTICKS(l_) 1264 ORDERKEY_PCTCPU(l_) 1265 ORDERKEY_STATE(l_) 1266 ORDERKEY_PRIO(l_) 1267 return result; 1268 } else { 1269 struct kinfo_proc2 *p1 = *(struct kinfo_proc2 **) pp1; 1270 struct kinfo_proc2 *p2 = *(struct kinfo_proc2 **) pp2; 1271 1272 ORDERKEY_CPTICKS(p_) 1273 ORDERKEY_PCTCPU(p_) 1274 ORDERKEY_STATE(p_) 1275 ORDERKEY_PRIO(p_) 1276 ORDERKEY_MEM 1277 ORDERKEY_RSSIZE 1278 return result; 1279 } 1280 1281 return (result); 1282 } 1283 1284 1285 /* 1286 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 1287 * the process does not exist. 1288 * It is EXTREMLY IMPORTANT that this function work correctly. 1289 * If top runs setuid root (as in SVR4), then this function 1290 * is the only thing that stands in the way of a serious 1291 * security problem. It validates requests for the "kill" 1292 * and "renice" commands. 1293 */ 1294 1295 int 1296 proc_owner(pid) 1297 int pid; 1298 { 1299 int cnt; 1300 struct kinfo_proc2 **prefp; 1301 struct kinfo_proc2 *pp; 1302 1303 if (threadmode) 1304 return(-1); 1305 1306 prefp = pref; 1307 cnt = pref_len; 1308 while (--cnt >= 0) { 1309 pp = *prefp++; 1310 if (pp->p_pid == (pid_t)pid) 1311 return(pp->p_ruid); 1312 } 1313 return(-1); 1314 } 1315 1316 /* 1317 * percentages(cnt, out, new, old, diffs) - calculate percentage change 1318 * between array "old" and "new", putting the percentages i "out". 1319 * "cnt" is size of each array and "diffs" is used for scratch space. 1320 * The array "old" is updated on each call. 1321 * The routine assumes modulo arithmetic. This function is especially 1322 * useful on BSD mchines for calculating CPU state percentages. 1323 */ 1324 1325 static void 1326 percentages64(cnt, out, new, old, diffs) 1327 int cnt; 1328 int *out; 1329 u_int64_t *new; 1330 u_int64_t *old; 1331 u_int64_t *diffs; 1332 { 1333 int i; 1334 u_int64_t change; 1335 u_int64_t total_change; 1336 u_int64_t *dp; 1337 u_int64_t half_total; 1338 1339 /* initialization */ 1340 total_change = 0; 1341 dp = diffs; 1342 1343 /* calculate changes for each state and the overall change */ 1344 for (i = 0; i < cnt; i++) { 1345 /* 1346 * Don't worry about wrapping - even at hz=1GHz, a 1347 * u_int64_t will last at least 544 years. 1348 */ 1349 change = *new - *old; 1350 total_change += (*dp++ = change); 1351 *old++ = *new++; 1352 } 1353 1354 /* avoid divide by zero potential */ 1355 if (total_change == 0) 1356 total_change = 1; 1357 1358 /* calculate percentages based on overall change, rounding up */ 1359 half_total = total_change / 2; 1360 for (i = 0; i < cnt; i++) 1361 *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); 1362 } 1363