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