1 /* $OpenBSD: machine.c,v 1.110 2020/08/26 16:21:28 kn Exp $ */ 2 3 /*- 4 * Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * AUTHOR: Thorsten Lockert <tholo@sigmasoft.com> 30 * Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu> 31 * Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no> 32 * Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com> 33 * Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org> 34 */ 35 36 #include <sys/param.h> /* DEV_BSIZE MAXCOMLEN PZERO */ 37 #include <sys/types.h> 38 #include <sys/signal.h> 39 #include <sys/mount.h> 40 #include <sys/proc.h> 41 #include <sys/sched.h> 42 #include <sys/swap.h> 43 #include <sys/sysctl.h> 44 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 #include <err.h> 50 #include <errno.h> 51 52 #include "top.h" 53 #include "display.h" 54 #include "machine.h" 55 #include "utils.h" 56 57 static int swapmode(int *, int *); 58 static char *state_abbr(struct kinfo_proc *); 59 static char *format_comm(struct kinfo_proc *); 60 static int cmd_matches(struct kinfo_proc *, char *); 61 static char **get_proc_args(struct kinfo_proc *); 62 63 /* get_process_info passes back a handle. This is what it looks like: */ 64 65 struct handle { 66 struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 67 }; 68 69 /* what we consider to be process size: */ 70 #define PROCSIZE(pp) ((pp)->p_vm_tsize + (pp)->p_vm_dsize + (pp)->p_vm_ssize) 71 72 /* 73 * These definitions control the format of the per-process area 74 */ 75 static char header[] = 76 " PID X PRI NICE SIZE RES STATE WAIT TIME CPU COMMAND"; 77 78 /* offsets in the header line to start alternative columns */ 79 #define UNAME_START 6 80 #define RTABLE_START 46 81 82 #define Proc_format \ 83 "%5d %-8.8s %3d %4d %5s %5s %-9s %-7.7s %6s %5.2f%% %s" 84 85 /* process state names for the "STATE" column of the display */ 86 char *state_abbrev[] = { 87 "", "start", "run", "sleep", "stop", "zomb", "dead", "onproc" 88 }; 89 90 /* these are for calculating cpu state percentages */ 91 static struct cpustats *cp_time; 92 static struct cpustats *cp_old; 93 static struct cpustats *cp_diff; 94 95 /* these are for detailing the process states */ 96 int process_states[8]; 97 char *procstatenames[] = { 98 "", " starting, ", " running, ", " idle, ", 99 " stopped, ", " zombie, ", " dead, ", " on processor, ", 100 NULL 101 }; 102 103 /* these are for detailing the cpu states */ 104 int64_t *cpu_states; 105 char *cpustatenames[] = { 106 "user", "nice", "sys", "spin", "intr", "idle", NULL 107 }; 108 109 /* this is for tracking which cpus are online */ 110 int *cpu_online; 111 112 /* these are for detailing the memory statistics */ 113 int memory_stats[10]; 114 char *memorynames[] = { 115 "Real: ", "K/", "K act/tot ", "Free: ", "K ", 116 "Cache: ", "K ", 117 "Swap: ", "K/", "K", 118 NULL 119 }; 120 121 /* these are names given to allowed sorting orders -- first is default */ 122 char *ordernames[] = { 123 "cpu", "size", "res", "time", "pri", "pid", "command", NULL 124 }; 125 126 /* these are for keeping track of the proc array */ 127 static int nproc; 128 static int onproc = -1; 129 static int pref_len; 130 static struct kinfo_proc *pbase; 131 static struct kinfo_proc **pref; 132 133 /* these are for getting the memory statistics */ 134 static int pageshift; /* log base 2 of the pagesize */ 135 136 /* define pagetok in terms of pageshift */ 137 #define pagetok(size) ((size) << pageshift) 138 139 int ncpu; 140 int ncpuonline; 141 int fscale; 142 143 unsigned int maxslp; 144 145 int 146 getfscale(void) 147 { 148 int mib[] = { CTL_KERN, KERN_FSCALE }; 149 size_t size = sizeof(fscale); 150 151 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 152 &fscale, &size, NULL, 0) == -1) 153 return (-1); 154 return fscale; 155 } 156 157 int 158 getncpu(void) 159 { 160 int mib[] = { CTL_HW, HW_NCPU }; 161 int numcpu; 162 size_t size = sizeof(numcpu); 163 164 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 165 &numcpu, &size, NULL, 0) == -1) 166 return (-1); 167 168 return (numcpu); 169 } 170 171 int 172 getncpuonline(void) 173 { 174 int mib[] = { CTL_HW, HW_NCPUONLINE }; 175 int numcpu; 176 size_t size = sizeof(numcpu); 177 178 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), 179 &numcpu, &size, NULL, 0) == -1) 180 return (-1); 181 182 return (numcpu); 183 } 184 185 int 186 machine_init(struct statics *statics) 187 { 188 int pagesize; 189 190 ncpu = getncpu(); 191 if (ncpu == -1) 192 return (-1); 193 if (getfscale() == -1) 194 return (-1); 195 cpu_states = calloc(ncpu, CPUSTATES * sizeof(int64_t)); 196 if (cpu_states == NULL) 197 err(1, NULL); 198 cp_time = calloc(ncpu, sizeof(*cp_time)); 199 cp_old = calloc(ncpu, sizeof(*cp_old)); 200 cp_diff = calloc(ncpu, sizeof(*cp_diff)); 201 if (cp_time == NULL || cp_old == NULL || cp_diff == NULL) 202 err(1, NULL); 203 cpu_online = calloc(ncpu, sizeof(*cpu_online)); 204 if (cpu_online == NULL) 205 err(1, NULL); 206 207 /* 208 * get the page size with "getpagesize" and calculate pageshift from 209 * it 210 */ 211 pagesize = getpagesize(); 212 pageshift = 0; 213 while (pagesize > 1) { 214 pageshift++; 215 pagesize >>= 1; 216 } 217 218 /* we only need the amount of log(2)1024 for our conversion */ 219 pageshift -= LOG1024; 220 221 /* fill in the statics information */ 222 statics->procstate_names = procstatenames; 223 statics->cpustate_names = cpustatenames; 224 statics->memory_names = memorynames; 225 statics->order_names = ordernames; 226 return (0); 227 } 228 229 char * 230 format_header(char *second_field, char *eighth_field) 231 { 232 char *second_fieldp = second_field, *eighth_fieldp = eighth_field, *ptr; 233 234 ptr = header + UNAME_START; 235 while (*second_fieldp != '\0') 236 *ptr++ = *second_fieldp++; 237 ptr = header + RTABLE_START; 238 while (*eighth_fieldp != '\0') 239 *ptr++ = *eighth_fieldp++; 240 return (header); 241 } 242 243 void 244 get_system_info(struct system_info *si) 245 { 246 static int cpustats_mib[] = {CTL_KERN, KERN_CPUSTATS, /*fillme*/0}; 247 static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; 248 static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; 249 static int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT}; 250 struct loadavg sysload; 251 struct uvmexp uvmexp; 252 struct bcachestats bcstats; 253 double *infoloadp; 254 size_t size; 255 int i; 256 int64_t *tmpstate; 257 258 size = sizeof(*cp_time); 259 for (i = 0; i < ncpu; i++) { 260 cpustats_mib[2] = i; 261 tmpstate = cpu_states + (CPUSTATES * i); 262 if (sysctl(cpustats_mib, 3, &cp_time[i], &size, NULL, 0) == -1) 263 warn("sysctl kern.cpustats failed"); 264 /* convert cpustats counts to percentages */ 265 (void) percentages(CPUSTATES, tmpstate, cp_time[i].cs_time, 266 cp_old[i].cs_time, cp_diff[i].cs_time); 267 /* note whether the cpu is online */ 268 cpu_online[i] = (cp_time[i].cs_flags & CPUSTATS_ONLINE) != 0; 269 } 270 271 size = sizeof(sysload); 272 if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) == -1) 273 warn("sysctl failed"); 274 infoloadp = si->load_avg; 275 for (i = 0; i < 3; i++) 276 *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; 277 278 279 /* get total -- systemwide main memory usage structure */ 280 size = sizeof(uvmexp); 281 if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) { 282 warn("sysctl failed"); 283 bzero(&uvmexp, sizeof(uvmexp)); 284 } 285 size = sizeof(bcstats); 286 if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) == -1) { 287 warn("sysctl failed"); 288 bzero(&bcstats, sizeof(bcstats)); 289 } 290 /* convert memory stats to Kbytes */ 291 memory_stats[0] = -1; 292 memory_stats[1] = pagetok(uvmexp.active); 293 memory_stats[2] = pagetok(uvmexp.npages - uvmexp.free); 294 memory_stats[3] = -1; 295 memory_stats[4] = pagetok(uvmexp.free); 296 memory_stats[5] = -1; 297 memory_stats[6] = pagetok(bcstats.numbufpages); 298 memory_stats[7] = -1; 299 300 if (!swapmode(&memory_stats[8], &memory_stats[9])) { 301 memory_stats[8] = 0; 302 memory_stats[9] = 0; 303 } 304 305 /* set arrays and strings */ 306 si->cpustates = cpu_states; 307 si->cpuonline = cpu_online; 308 si->memory = memory_stats; 309 si->last_pid = -1; 310 } 311 312 static struct handle handle; 313 314 struct kinfo_proc * 315 getprocs(int op, int arg, int *cnt) 316 { 317 size_t size; 318 int mib[6] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, 319 sizeof(struct kinfo_proc), 0}; 320 static int maxslp_mib[] = {CTL_VM, VM_MAXSLP}; 321 static struct kinfo_proc *procbase; 322 int st; 323 324 mib[2] = op; 325 mib[3] = arg; 326 327 size = sizeof(maxslp); 328 if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) == -1) { 329 warn("sysctl vm.maxslp failed"); 330 return (0); 331 } 332 retry: 333 free(procbase); 334 st = sysctl(mib, 6, NULL, &size, NULL, 0); 335 if (st == -1) { 336 /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */ 337 return (0); 338 } 339 size = 5 * size / 4; /* extra slop */ 340 if ((procbase = malloc(size)) == NULL) 341 return (0); 342 mib[5] = (int)(size / sizeof(struct kinfo_proc)); 343 st = sysctl(mib, 6, procbase, &size, NULL, 0); 344 if (st == -1) { 345 if (errno == ENOMEM) 346 goto retry; 347 /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */ 348 return (0); 349 } 350 *cnt = (int)(size / sizeof(struct kinfo_proc)); 351 return (procbase); 352 } 353 354 static char ** 355 get_proc_args(struct kinfo_proc *kp) 356 { 357 static char **s; 358 static size_t siz = 1023; 359 int mib[4]; 360 361 if (!s && !(s = malloc(siz))) 362 err(1, NULL); 363 364 mib[0] = CTL_KERN; 365 mib[1] = KERN_PROC_ARGS; 366 mib[2] = kp->p_pid; 367 mib[3] = KERN_PROC_ARGV; 368 for (;;) { 369 size_t space = siz; 370 if (sysctl(mib, 4, s, &space, NULL, 0) == 0) 371 break; 372 if (errno != ENOMEM) 373 return NULL; 374 siz *= 2; 375 if ((s = realloc(s, siz)) == NULL) 376 err(1, NULL); 377 } 378 return s; 379 } 380 381 static int 382 cmd_matches(struct kinfo_proc *proc, char *term) 383 { 384 extern int show_args; 385 char **args = NULL; 386 387 if (!term) { 388 /* No command filter set */ 389 return 1; 390 } else { 391 /* Filter set, process name needs to contain term */ 392 if (strstr(proc->p_comm, term)) 393 return 1; 394 /* If showing arguments, search those as well */ 395 if (show_args) { 396 args = get_proc_args(proc); 397 398 if (args == NULL) { 399 /* Failed to get args, so can't search them */ 400 return 0; 401 } 402 403 while (*args != NULL) { 404 if (strstr(*args, term)) 405 return 1; 406 args++; 407 } 408 } 409 } 410 return 0; 411 } 412 413 struct handle * 414 get_process_info(struct system_info *si, struct process_select *sel, 415 int (*compare) (const void *, const void *)) 416 { 417 int show_idle, show_system, show_threads, show_uid, show_pid, show_cmd; 418 int show_rtableid, hide_rtableid, hide_uid; 419 int total_procs, active_procs; 420 struct kinfo_proc **prefp, *pp; 421 int what = KERN_PROC_ALL; 422 423 show_system = sel->system; 424 show_threads = sel->threads; 425 426 if (show_system) 427 what = KERN_PROC_KTHREAD; 428 if (show_threads) 429 what |= KERN_PROC_SHOW_THREADS; 430 431 if ((pbase = getprocs(what, 0, &nproc)) == NULL) { 432 /* warnx("%s", kvm_geterr(kd)); */ 433 quit(23); 434 } 435 if (nproc > onproc) 436 pref = reallocarray(pref, (onproc = nproc), 437 sizeof(struct kinfo_proc *)); 438 if (pref == NULL) { 439 warnx("Out of memory."); 440 quit(23); 441 } 442 /* get a pointer to the states summary array */ 443 si->procstates = process_states; 444 445 /* set up flags which define what we are going to select */ 446 show_idle = sel->idle; 447 show_uid = sel->uid != (uid_t)-1; 448 hide_uid = sel->huid != (uid_t)-1; 449 show_pid = sel->pid != (pid_t)-1; 450 show_rtableid = sel->rtableid != -1; 451 hide_rtableid = sel->hrtableid != -1; 452 show_cmd = sel->command != NULL; 453 454 /* count up process states and get pointers to interesting procs */ 455 total_procs = 0; 456 active_procs = 0; 457 memset((char *) process_states, 0, sizeof(process_states)); 458 prefp = pref; 459 for (pp = pbase; pp < &pbase[nproc]; pp++) { 460 /* 461 * When showing threads, we want to ignore the structure 462 * that represents the entire process, which has TID == -1 463 */ 464 if (show_threads && pp->p_tid == -1) 465 continue; 466 /* 467 * Place pointers to each valid proc structure in pref[]. 468 * Process slots that are actually in use have a non-zero 469 * status field. 470 */ 471 if (pp->p_stat != 0) { 472 total_procs++; 473 process_states[(unsigned char) pp->p_stat]++; 474 if ((pp->p_psflags & PS_ZOMBIE) == 0 && 475 (show_idle || pp->p_pctcpu != 0 || 476 pp->p_stat == SRUN) && 477 (!hide_uid || pp->p_ruid != sel->huid) && 478 (!show_uid || pp->p_ruid == sel->uid) && 479 (!show_pid || pp->p_pid == sel->pid) && 480 (!hide_rtableid || pp->p_rtableid != sel->hrtableid) && 481 (!show_rtableid || pp->p_rtableid == sel->rtableid) && 482 (!show_cmd || cmd_matches(pp, sel->command))) { 483 *prefp++ = pp; 484 active_procs++; 485 } 486 } 487 } 488 489 qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare); 490 /* remember active and total counts */ 491 si->p_total = total_procs; 492 si->p_active = pref_len = active_procs; 493 494 /* pass back a handle */ 495 handle.next_proc = pref; 496 return &handle; 497 } 498 499 char fmt[MAX_COLS]; /* static area where result is built */ 500 501 static char * 502 state_abbr(struct kinfo_proc *pp) 503 { 504 static char buf[10]; 505 506 if (ncpu > 1 && pp->p_cpuid != KI_NOCPU) 507 snprintf(buf, sizeof buf, "%s/%llu", 508 state_abbrev[(unsigned char)pp->p_stat], pp->p_cpuid); 509 else 510 snprintf(buf, sizeof buf, "%s", 511 state_abbrev[(unsigned char)pp->p_stat]); 512 return buf; 513 } 514 515 static char * 516 format_comm(struct kinfo_proc *kp) 517 { 518 static char buf[MAX_COLS]; 519 char **p, **s; 520 extern int show_args; 521 522 if (!show_args) 523 return (kp->p_comm); 524 525 s = get_proc_args(kp); 526 if (s == NULL) 527 return kp->p_comm; 528 529 buf[0] = '\0'; 530 for (p = s; *p != NULL; p++) { 531 if (p != s) 532 strlcat(buf, " ", sizeof(buf)); 533 strlcat(buf, *p, sizeof(buf)); 534 } 535 if (buf[0] == '\0') 536 return (kp->p_comm); 537 return (buf); 538 } 539 540 void 541 skip_processes(struct handle *hndl, int n) 542 { 543 hndl->next_proc += n; 544 } 545 546 char * 547 format_next_process(struct handle *hndl, const char *(*get_userid)(uid_t, int), 548 int rtable, pid_t *pid) 549 { 550 struct kinfo_proc *pp; 551 int cputime; 552 double pct; 553 char second_buf[16], eighth_buf[8]; 554 555 /* find and remember the next proc structure */ 556 pp = *(hndl->next_proc++); 557 558 cputime = pp->p_rtime_sec + ((pp->p_rtime_usec + 500000) / 1000000); 559 560 /* calculate the base for cpu percentages */ 561 pct = (double)pp->p_pctcpu / fscale; 562 563 if (get_userid == NULL) 564 snprintf(second_buf, sizeof(second_buf), "%8d", pp->p_tid); 565 else 566 strlcpy(second_buf, (*get_userid)(pp->p_ruid, 0), 567 sizeof(second_buf)); 568 569 if (rtable) 570 snprintf(eighth_buf, sizeof(eighth_buf), "%7d", pp->p_rtableid); 571 else 572 strlcpy(eighth_buf, pp->p_wmesg[0] ? pp->p_wmesg : "-", 573 sizeof(eighth_buf)); 574 575 /* format this entry */ 576 snprintf(fmt, sizeof(fmt), Proc_format, pp->p_pid, second_buf, 577 pp->p_priority - PZERO, pp->p_nice - NZERO, 578 format_k(pagetok(PROCSIZE(pp))), 579 format_k(pagetok(pp->p_vm_rssize)), 580 (pp->p_stat == SSLEEP && pp->p_slptime > maxslp) ? 581 "idle" : state_abbr(pp), 582 eighth_buf, format_time(cputime), 100.0 * pct, 583 printable(format_comm(pp))); 584 585 *pid = pp->p_pid; 586 /* return the result */ 587 return (fmt); 588 } 589 590 /* comparison routine for qsort */ 591 static unsigned char sorted_state[] = 592 { 593 0, /* not used */ 594 4, /* start */ 595 5, /* run */ 596 2, /* sleep */ 597 3, /* stop */ 598 1 /* zombie */ 599 }; 600 601 extern int rev_order; 602 603 /* 604 * proc_compares - comparison functions for "qsort" 605 */ 606 607 /* 608 * First, the possible comparison keys. These are defined in such a way 609 * that they can be merely listed in the source code to define the actual 610 * desired ordering. 611 */ 612 613 #define ORDERKEY_PCTCPU \ 614 if ((result = (int)(p2->p_pctcpu - p1->p_pctcpu)) == 0) 615 #define ORDERKEY_CPUTIME \ 616 if ((result = p2->p_rtime_sec - p1->p_rtime_sec) == 0) \ 617 if ((result = p2->p_rtime_usec - p1->p_rtime_usec) == 0) 618 #define ORDERKEY_STATE \ 619 if ((result = sorted_state[(unsigned char)p2->p_stat] - \ 620 sorted_state[(unsigned char)p1->p_stat]) == 0) 621 #define ORDERKEY_PRIO \ 622 if ((result = p2->p_priority - p1->p_priority) == 0) 623 #define ORDERKEY_RSSIZE \ 624 if ((result = p2->p_vm_rssize - p1->p_vm_rssize) == 0) 625 #define ORDERKEY_MEM \ 626 if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0) 627 #define ORDERKEY_PID \ 628 if ((result = p1->p_pid - p2->p_pid) == 0) 629 #define ORDERKEY_CMD \ 630 if ((result = strcmp(p1->p_comm, p2->p_comm)) == 0) 631 632 /* remove one level of indirection and set sort order */ 633 #define SETORDER do { \ 634 if (rev_order) { \ 635 p1 = *(struct kinfo_proc **) v2; \ 636 p2 = *(struct kinfo_proc **) v1; \ 637 } else { \ 638 p1 = *(struct kinfo_proc **) v1; \ 639 p2 = *(struct kinfo_proc **) v2; \ 640 } \ 641 } while (0) 642 643 /* compare_cpu - the comparison function for sorting by cpu percentage */ 644 static int 645 compare_cpu(const void *v1, const void *v2) 646 { 647 struct kinfo_proc *p1, *p2; 648 int result; 649 650 SETORDER; 651 652 ORDERKEY_PCTCPU 653 ORDERKEY_CPUTIME 654 ORDERKEY_STATE 655 ORDERKEY_PRIO 656 ORDERKEY_RSSIZE 657 ORDERKEY_MEM 658 ; 659 return (result); 660 } 661 662 /* compare_size - the comparison function for sorting by total memory usage */ 663 static int 664 compare_size(const void *v1, const void *v2) 665 { 666 struct kinfo_proc *p1, *p2; 667 int result; 668 669 SETORDER; 670 671 ORDERKEY_MEM 672 ORDERKEY_RSSIZE 673 ORDERKEY_PCTCPU 674 ORDERKEY_CPUTIME 675 ORDERKEY_STATE 676 ORDERKEY_PRIO 677 ; 678 return (result); 679 } 680 681 /* compare_res - the comparison function for sorting by resident set size */ 682 static int 683 compare_res(const void *v1, const void *v2) 684 { 685 struct kinfo_proc *p1, *p2; 686 int result; 687 688 SETORDER; 689 690 ORDERKEY_RSSIZE 691 ORDERKEY_MEM 692 ORDERKEY_PCTCPU 693 ORDERKEY_CPUTIME 694 ORDERKEY_STATE 695 ORDERKEY_PRIO 696 ; 697 return (result); 698 } 699 700 /* compare_time - the comparison function for sorting by CPU time */ 701 static int 702 compare_time(const void *v1, const void *v2) 703 { 704 struct kinfo_proc *p1, *p2; 705 int result; 706 707 SETORDER; 708 709 ORDERKEY_CPUTIME 710 ORDERKEY_PCTCPU 711 ORDERKEY_STATE 712 ORDERKEY_PRIO 713 ORDERKEY_MEM 714 ORDERKEY_RSSIZE 715 ; 716 return (result); 717 } 718 719 /* compare_prio - the comparison function for sorting by CPU time */ 720 static int 721 compare_prio(const void *v1, const void *v2) 722 { 723 struct kinfo_proc *p1, *p2; 724 int result; 725 726 SETORDER; 727 728 ORDERKEY_PRIO 729 ORDERKEY_PCTCPU 730 ORDERKEY_CPUTIME 731 ORDERKEY_STATE 732 ORDERKEY_RSSIZE 733 ORDERKEY_MEM 734 ; 735 return (result); 736 } 737 738 static int 739 compare_pid(const void *v1, const void *v2) 740 { 741 struct kinfo_proc *p1, *p2; 742 int result; 743 744 SETORDER; 745 746 ORDERKEY_PID 747 ORDERKEY_PCTCPU 748 ORDERKEY_CPUTIME 749 ORDERKEY_STATE 750 ORDERKEY_PRIO 751 ORDERKEY_RSSIZE 752 ORDERKEY_MEM 753 ; 754 return (result); 755 } 756 757 static int 758 compare_cmd(const void *v1, const void *v2) 759 { 760 struct kinfo_proc *p1, *p2; 761 int result; 762 763 SETORDER; 764 765 ORDERKEY_CMD 766 ORDERKEY_PCTCPU 767 ORDERKEY_CPUTIME 768 ORDERKEY_STATE 769 ORDERKEY_PRIO 770 ORDERKEY_RSSIZE 771 ORDERKEY_MEM 772 ; 773 return (result); 774 } 775 776 777 int (*proc_compares[])(const void *, const void *) = { 778 compare_cpu, 779 compare_size, 780 compare_res, 781 compare_time, 782 compare_prio, 783 compare_pid, 784 compare_cmd, 785 NULL 786 }; 787 788 /* 789 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 790 * the process does not exist. 791 * It is EXTREMELY IMPORTANT that this function work correctly. 792 * If top runs setuid root (as in SVR4), then this function 793 * is the only thing that stands in the way of a serious 794 * security problem. It validates requests for the "kill" 795 * and "renice" commands. 796 */ 797 uid_t 798 proc_owner(pid_t pid) 799 { 800 struct kinfo_proc **prefp, *pp; 801 int cnt; 802 803 prefp = pref; 804 cnt = pref_len; 805 while (--cnt >= 0) { 806 pp = *prefp++; 807 if (pp->p_pid == pid) 808 return ((uid_t)pp->p_ruid); 809 } 810 return (uid_t)(-1); 811 } 812 813 /* 814 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org> 815 * to be based on the new swapctl(2) system call. 816 */ 817 static int 818 swapmode(int *used, int *total) 819 { 820 struct swapent *swdev; 821 int nswap, rnswap, i; 822 823 nswap = swapctl(SWAP_NSWAP, 0, 0); 824 if (nswap == 0) 825 return 0; 826 827 swdev = calloc(nswap, sizeof(*swdev)); 828 if (swdev == NULL) 829 return 0; 830 831 rnswap = swapctl(SWAP_STATS, swdev, nswap); 832 if (rnswap == -1) { 833 free(swdev); 834 return 0; 835 } 836 837 /* if rnswap != nswap, then what? */ 838 839 /* Total things up */ 840 *total = *used = 0; 841 for (i = 0; i < nswap; i++) { 842 if (swdev[i].se_flags & SWF_ENABLE) { 843 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE)); 844 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE)); 845 } 846 } 847 free(swdev); 848 return 1; 849 } 850