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