machine.c revision 1.19
1/* $OpenBSD: machine.c,v 1.19 2000/06/18 17:59:56 niklas Exp $ */ 2 3/* 4 * top - a top users display for Unix 5 * 6 * SYNOPSIS: For an OpenBSD system 7 * 8 * DESCRIPTION: 9 * This is the machine-dependent module for OpenBSD 10 * Tested on: 11 * i386 12 * 13 * LIBS: -lkvm 14 * 15 * TERMCAP: -ltermlib 16 * 17 * CFLAGS: -DHAVE_GETOPT -DORDER 18 * 19 * AUTHOR: Thorsten Lockert <tholo@sigmasoft.com> 20 * Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu> 21 * Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no> 22 * Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com> 23 * Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org> 24 */ 25 26#include <sys/types.h> 27#include <sys/signal.h> 28#include <sys/param.h> 29 30#define DOSWAP 31 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <limits.h> 36#include <err.h> 37#include <nlist.h> 38#include <math.h> 39#include <kvm.h> 40#include <unistd.h> 41#include <sys/errno.h> 42#include <sys/sysctl.h> 43#include <sys/dir.h> 44#include <sys/dkstat.h> 45#include <sys/file.h> 46#include <sys/time.h> 47#include <sys/resource.h> 48 49#ifdef DOSWAP 50#include <sys/swap.h> 51#include <err.h> 52#endif 53 54static int check_nlist __P((struct nlist *)); 55static int getkval __P((unsigned long, int *, int, char *)); 56static int swapmode __P((int *, int *)); 57 58#include "top.h" 59#include "display.h" 60#include "machine.h" 61#include "utils.h" 62 63/* get_process_info passes back a handle. This is what it looks like: */ 64 65struct handle 66{ 67 struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 68 int remaining; /* number of pointers remaining */ 69}; 70 71/* declarations for load_avg */ 72#include "loadavg.h" 73 74#define PP(pp, field) ((pp)->kp_proc . field) 75#define EP(pp, field) ((pp)->kp_eproc . field) 76#define VP(pp, field) ((pp)->kp_eproc.e_vm . field) 77 78/* what we consider to be process size: */ 79#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize)) 80 81/* definitions for indices in the nlist array */ 82#define X_CP_TIME 0 83 84static struct nlist nlst[] = { 85 { "_cp_time" }, /* 0 */ 86 { 0 } 87}; 88 89/* 90 * These definitions control the format of the per-process area 91 */ 92 93static char header[] = 94 " PID X PRI NICE SIZE RES STATE WAIT TIME CPU COMMAND"; 95/* 0123456 -- field to fill in starts at header+6 */ 96#define UNAME_START 6 97 98#define Proc_format \ 99 "%5d %-8.8s %3d %4d %5s %5s %-5s %-6.6s %6s %5.2f%% %.14s" 100 101 102/* process state names for the "STATE" column of the display */ 103/* the extra nulls in the string "run" are for adding a slash and 104 the processor number when needed */ 105 106char *state_abbrev[] = 107{ 108 "", "start", "run\0\0\0", "sleep", "stop", "zomb", 109}; 110 111 112static kvm_t *kd; 113 114/* these are retrieved from the kernel in _init */ 115 116static int stathz; 117 118/* these are offsets obtained via nlist and used in the get_ functions */ 119 120static unsigned long cp_time_offset; 121 122/* these are for calculating cpu state percentages */ 123static long cp_time[CPUSTATES]; 124static long cp_old[CPUSTATES]; 125static long cp_diff[CPUSTATES]; 126 127/* these are for detailing the process states */ 128 129int process_states[7]; 130char *procstatenames[] = { 131 "", " starting, ", " running, ", " idle, ", " stopped, ", " zombie, ", 132 NULL 133}; 134 135/* these are for detailing the cpu states */ 136 137int cpu_states[CPUSTATES]; 138char *cpustatenames[] = { 139 "user", "nice", "system", "interrupt", "idle", NULL 140}; 141 142/* these are for detailing the memory statistics */ 143 144int memory_stats[8]; 145char *memorynames[] = { 146 "Real: ", "K/", "K act/tot ", "Free: ", "K ", 147#ifdef DOSWAP 148 "Swap: ", "K/", "K used/tot", 149#endif 150 NULL 151}; 152 153#ifdef ORDER 154/* these are names given to allowed sorting orders -- first is default */ 155 156char *ordernames[] = {"cpu", "size", "res", "time", "pri", NULL}; 157#endif 158 159/* these are for keeping track of the proc array */ 160 161static int nproc; 162static int onproc = -1; 163static int pref_len; 164static struct kinfo_proc *pbase; 165static struct kinfo_proc **pref; 166 167/* these are for getting the memory statistics */ 168 169static int pageshift; /* log base 2 of the pagesize */ 170 171/* define pagetok in terms of pageshift */ 172 173#define pagetok(size) ((size) << pageshift) 174 175int 176getstathz() 177{ 178 int mib[2]; 179 struct clockinfo cinf; 180 size_t size = sizeof(cinf); 181 182 mib[0] = CTL_KERN; 183 mib[1] = KERN_CLOCKRATE; 184 if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1) 185 return (-1); 186 return (cinf.stathz); 187} 188 189int 190machine_init(statics) 191struct statics *statics; 192{ 193 register int i = 0; 194 register int pagesize; 195 char errbuf[_POSIX2_LINE_MAX]; 196 197 if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) { 198 warnx("%s", errbuf); 199 return(-1); 200 } 201 202 setegid(getgid()); 203 setgid(getgid()); 204 205 /* get the list of symbols we want to access in the kernel */ 206 if (kvm_nlist(kd, nlst) < 0) { 207 warnx("nlist failed"); 208 return(-1); 209 } 210 211 /* make sure they were all found */ 212 if (i > 0 && check_nlist(nlst) > 0) 213 return(-1); 214 215 stathz = getstathz(); 216 if (stathz == -1) 217 return(-1); 218 219 /* stash away certain offsets for later use */ 220 cp_time_offset = nlst[X_CP_TIME].n_value; 221 222 pbase = NULL; 223 pref = NULL; 224 onproc = -1; 225 nproc = 0; 226 227 /* get the page size with "getpagesize" and calculate pageshift from it */ 228 pagesize = getpagesize(); 229 pageshift = 0; 230 while (pagesize > 1) 231 { 232 pageshift++; 233 pagesize >>= 1; 234 } 235 236 /* we only need the amount of log(2)1024 for our conversion */ 237 pageshift -= LOG1024; 238 239 /* fill in the statics information */ 240 statics->procstate_names = procstatenames; 241 statics->cpustate_names = cpustatenames; 242 statics->memory_names = memorynames; 243#ifdef ORDER 244 statics->order_names = ordernames; 245#endif 246 247 /* all done! */ 248 return(0); 249} 250 251char *format_header(uname_field) 252 253register char *uname_field; 254 255{ 256 register char *ptr; 257 258 ptr = header + UNAME_START; 259 while (*uname_field != '\0') 260 { 261 *ptr++ = *uname_field++; 262 } 263 264 return(header); 265} 266 267void 268get_system_info(si) 269 270struct system_info *si; 271 272{ 273 int total; 274 275 /* get the cp_time array */ 276 (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time), 277 "_cp_time"); 278 279 /* convert load averages to doubles */ 280 { 281 register int i; 282 register double *infoloadp; 283 struct loadavg sysload; 284 size_t size = sizeof(sysload); 285 static int mib[] = { CTL_VM, VM_LOADAVG }; 286 287 if (sysctl(mib, 2, &sysload, &size, NULL, 0) < 0) { 288 warn("sysctl failed"); 289 bzero(&total, sizeof(total)); 290 } 291 292 infoloadp = si->load_avg; 293 for (i = 0; i < 3; i++) 294 *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; 295 } 296 297 /* convert cp_time counts to percentages */ 298 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 299 300 /* sum memory statistics */ 301 { 302 struct vmtotal total; 303 size_t size = sizeof(total); 304 static int mib[] = { CTL_VM, VM_METER }; 305 306 /* get total -- systemwide main memory usage structure */ 307 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { 308 warn("sysctl failed"); 309 bzero(&total, sizeof(total)); 310 } 311 /* convert memory stats to Kbytes */ 312 memory_stats[0] = -1; 313 memory_stats[1] = pagetok(total.t_arm); 314 memory_stats[2] = pagetok(total.t_rm); 315 memory_stats[3] = -1; 316 memory_stats[4] = pagetok(total.t_free); 317 memory_stats[5] = -1; 318#ifdef DOSWAP 319 if (!swapmode(&memory_stats[6], &memory_stats[7])) { 320 memory_stats[6] = 0; 321 memory_stats[7] = 0; 322 } 323#endif 324 } 325 326 /* set arrays and strings */ 327 si->cpustates = cpu_states; 328 si->memory = memory_stats; 329 si->last_pid = -1; 330} 331 332static struct handle handle; 333 334caddr_t get_process_info(si, sel, compare) 335 336struct system_info *si; 337struct process_select *sel; 338int (*compare) __P((const void *, const void *)); 339 340{ 341 register int i; 342 register int total_procs; 343 register int active_procs; 344 register struct kinfo_proc **prefp; 345 register struct kinfo_proc *pp; 346 347 /* these are copied out of sel for speed */ 348 int show_idle; 349 int show_system; 350 int show_uid; 351 int show_command; 352 353 354 if ((pbase = kvm_getprocs(kd, KERN_PROC_KTHREAD, 0, &nproc)) == NULL) { 355 warnx("%s", kvm_geterr(kd)); 356 quit(23); 357 } 358 if (nproc > onproc) 359 pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) 360 * (onproc = nproc)); 361 if (pref == NULL) { 362 warnx("Out of memory."); 363 quit(23); 364 } 365 /* get a pointer to the states summary array */ 366 si->procstates = process_states; 367 368 /* set up flags which define what we are going to select */ 369 show_idle = sel->idle; 370 show_system = sel->system; 371 show_uid = sel->uid != -1; 372 show_command = sel->command != NULL; 373 374 /* count up process states and get pointers to interesting procs */ 375 total_procs = 0; 376 active_procs = 0; 377 memset((char *)process_states, 0, sizeof(process_states)); 378 prefp = pref; 379 for (pp = pbase, i = 0; i < nproc; pp++, i++) 380 { 381 /* 382 * Place pointers to each valid proc structure in pref[]. 383 * Process slots that are actually in use have a non-zero 384 * status field. Processes with SSYS set are system 385 * processes---these get ignored unless show_sysprocs is set. 386 */ 387 if (PP(pp, p_stat) != 0 && 388 (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0))) 389 { 390 total_procs++; 391 process_states[(unsigned char) PP(pp, p_stat)]++; 392 if ((PP(pp, p_stat) != SZOMB) && 393 (show_idle || (PP(pp, p_pctcpu) != 0) || 394 (PP(pp, p_stat) == SRUN)) && 395 (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid)) 396 { 397 *prefp++ = pp; 398 active_procs++; 399 } 400 } 401 } 402 403 /* if requested, sort the "interesting" processes */ 404 if (compare != NULL) 405 { 406 qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare); 407 } 408 409 /* remember active and total counts */ 410 si->p_total = total_procs; 411 si->p_active = pref_len = active_procs; 412 413 /* pass back a handle */ 414 handle.next_proc = pref; 415 handle.remaining = active_procs; 416 return((caddr_t)&handle); 417} 418 419char fmt[MAX_COLS]; /* static area where result is built */ 420 421char *format_next_process(handle, get_userid) 422 423caddr_t handle; 424char *(*get_userid)(); 425 426{ 427 register struct kinfo_proc *pp; 428 register int cputime; 429 register double pct; 430 struct handle *hp; 431 char waddr[sizeof(void *) * 2 + 3]; /* Hexify void pointer */ 432 char *p_wait; 433 434 /* find and remember the next proc structure */ 435 hp = (struct handle *)handle; 436 pp = *(hp->next_proc++); 437 hp->remaining--; 438 439 440 /* get the process's user struct and set cputime */ 441 if ((PP(pp, p_flag) & P_INMEM) == 0) { 442 /* 443 * Print swapped processes as <pname> 444 */ 445 char *comm = PP(pp, p_comm); 446#define COMSIZ sizeof(PP(pp, p_comm)) 447 char buf[COMSIZ]; 448 (void) strncpy(buf, comm, COMSIZ); 449 comm[0] = '<'; 450 (void) strncpy(&comm[1], buf, COMSIZ - 2); 451 comm[COMSIZ - 2] = '\0'; 452 (void) strncat(comm, ">", COMSIZ - 1); 453 comm[COMSIZ - 1] = '\0'; 454 } 455 456 cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz; 457 458 /* calculate the base for cpu percentages */ 459 pct = pctdouble(PP(pp, p_pctcpu)); 460 461 if (PP(pp, p_wchan)) 462 if (PP(pp, p_wmesg)) 463 p_wait = EP(pp, e_wmesg); 464 else { 465 snprintf(waddr, sizeof(waddr), "%lx", 466 (unsigned long)(PP(pp, p_wchan)) & ~KERNBASE); 467 p_wait = waddr; 468 } 469 else 470 p_wait = "-"; 471 472 /* format this entry */ 473 snprintf(fmt, MAX_COLS, 474 Proc_format, 475 PP(pp, p_pid), 476 (*get_userid)(EP(pp, e_pcred.p_ruid)), 477 PP(pp, p_priority) - PZERO, 478 PP(pp, p_nice) - NZERO, 479 format_k(pagetok(PROCSIZE(pp))), 480 format_k(pagetok(VP(pp, vm_rssize))), 481 (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > MAXSLP) 482 ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)], 483 p_wait, 484 format_time(cputime), 485 100.0 * pct, 486 printable(PP(pp, p_comm))); 487 488 /* return the result */ 489 return(fmt); 490} 491 492 493/* 494 * check_nlist(nlst) - checks the nlist to see if any symbols were not 495 * found. For every symbol that was not found, a one-line 496 * message is printed to stderr. The routine returns the 497 * number of symbols NOT found. 498 */ 499 500static int check_nlist(nlst) 501 502register struct nlist *nlst; 503 504{ 505 register int i; 506 507 /* check to see if we got ALL the symbols we requested */ 508 /* this will write one line to stderr for every symbol not found */ 509 510 i = 0; 511 while (nlst->n_name != NULL) 512 { 513 if (nlst->n_type == 0) 514 { 515 /* this one wasn't found */ 516 (void) fprintf(stderr, "kernel: no symbol named `%s'\n", 517 nlst->n_name); 518 i = 1; 519 } 520 nlst++; 521 } 522 523 return(i); 524} 525 526 527/* 528 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 529 * "offset" is the byte offset into the kernel for the desired value, 530 * "ptr" points to a buffer into which the value is retrieved, 531 * "size" is the size of the buffer (and the object to retrieve), 532 * "refstr" is a reference string used when printing error meessages, 533 * if "refstr" starts with a '!', then a failure on read will not 534 * be fatal (this may seem like a silly way to do things, but I 535 * really didn't want the overhead of another argument). 536 * 537 */ 538 539static int getkval(offset, ptr, size, refstr) 540 541unsigned long offset; 542int *ptr; 543int size; 544char *refstr; 545 546{ 547 if (kvm_read(kd, offset, ptr, size) != size) 548 { 549 if (*refstr == '!') 550 { 551 return(0); 552 } 553 else 554 { 555 warn("kvm_read for %s", refstr); 556 quit(23); 557 } 558 } 559 return(1); 560} 561 562/* comparison routine for qsort */ 563 564static unsigned char sorted_state[] = 565{ 566 0, /* not used */ 567 4, /* start */ 568 5, /* run */ 569 2, /* sleep */ 570 3, /* stop */ 571 1 /* zombie */ 572}; 573 574#ifdef ORDER 575 576/* 577 * proc_compares - comparison functions for "qsort" 578 */ 579 580/* 581 * First, the possible comparison keys. These are defined in such a way 582 * that they can be merely listed in the source code to define the actual 583 * desired ordering. 584 */ 585 586 587#define ORDERKEY_PCTCPU \ 588 if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \ 589 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 590#define ORDERKEY_CPUTIME \ 591 if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \ 592 if ((result = PP(p2, p_rtime.tv_usec) - \ 593 PP(p1, p_rtime.tv_usec)) == 0) 594#define ORDERKEY_STATE \ 595 if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \ 596 sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) 597#define ORDERKEY_PRIO \ 598 if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0) 599#define ORDERKEY_RSSIZE \ 600 if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0) 601#define ORDERKEY_MEM \ 602 if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0) 603 604 605/* compare_cpu - the comparison function for sorting by cpu percentage */ 606 607int 608compare_cpu(v1, v2) 609 610const void *v1, *v2; 611 612{ 613 register struct proc **pp1 = (struct proc **)v1; 614 register struct proc **pp2 = (struct proc **)v2; 615 register struct kinfo_proc *p1; 616 register struct kinfo_proc *p2; 617 register int result; 618 register pctcpu lresult; 619 620 /* remove one level of indirection */ 621 p1 = *(struct kinfo_proc **) pp1; 622 p2 = *(struct kinfo_proc **) pp2; 623 624 ORDERKEY_PCTCPU 625 ORDERKEY_CPUTIME 626 ORDERKEY_STATE 627 ORDERKEY_PRIO 628 ORDERKEY_RSSIZE 629 ORDERKEY_MEM 630 ; 631 return(result); 632} 633 634/* compare_size - the comparison function for sorting by total memory usage */ 635 636int 637compare_size(v1, v2) 638 639const void *v1, *v2; 640 641{ 642 register struct proc **pp1 = (struct proc **)v1; 643 register struct proc **pp2 = (struct proc **)v2; 644 register struct kinfo_proc *p1; 645 register struct kinfo_proc *p2; 646 register int result; 647 register pctcpu lresult; 648 649 /* remove one level of indirection */ 650 p1 = *(struct kinfo_proc **) pp1; 651 p2 = *(struct kinfo_proc **) pp2; 652 653 ORDERKEY_MEM 654 ORDERKEY_RSSIZE 655 ORDERKEY_PCTCPU 656 ORDERKEY_CPUTIME 657 ORDERKEY_STATE 658 ORDERKEY_PRIO 659 ; 660 661 return(result); 662} 663 664/* compare_res - the comparison function for sorting by resident set size */ 665 666int 667compare_res(v1, v2) 668 669const void *v1, *v2; 670 671{ 672 register struct proc **pp1 = (struct proc **)v1; 673 register struct proc **pp2 = (struct proc **)v2; 674 register struct kinfo_proc *p1; 675 register struct kinfo_proc *p2; 676 register int result; 677 register pctcpu lresult; 678 679 /* remove one level of indirection */ 680 p1 = *(struct kinfo_proc **) pp1; 681 p2 = *(struct kinfo_proc **) pp2; 682 683 ORDERKEY_RSSIZE 684 ORDERKEY_MEM 685 ORDERKEY_PCTCPU 686 ORDERKEY_CPUTIME 687 ORDERKEY_STATE 688 ORDERKEY_PRIO 689 ; 690 691 return(result); 692} 693 694/* compare_time - the comparison function for sorting by CPU time */ 695 696int 697compare_time(v1, v2) 698 699const void *v1, *v2; 700 701{ 702 register struct proc **pp1 = (struct proc **)v1; 703 register struct proc **pp2 = (struct proc **)v2; 704 register struct kinfo_proc *p1; 705 register struct kinfo_proc *p2; 706 register int result; 707 register pctcpu lresult; 708 709 /* remove one level of indirection */ 710 p1 = *(struct kinfo_proc **) pp1; 711 p2 = *(struct kinfo_proc **) pp2; 712 713 ORDERKEY_CPUTIME 714 ORDERKEY_PCTCPU 715 ORDERKEY_STATE 716 ORDERKEY_PRIO 717 ORDERKEY_MEM 718 ORDERKEY_RSSIZE 719 ; 720 721 return(result); 722} 723 724/* compare_prio - the comparison function for sorting by CPU time */ 725 726int 727compare_prio(v1, v2) 728 729const void *v1, *v2; 730 731{ 732 register struct proc **pp1 = (struct proc **)v1; 733 register struct proc **pp2 = (struct proc **)v2; 734 register struct kinfo_proc *p1; 735 register struct kinfo_proc *p2; 736 register int result; 737 register pctcpu lresult; 738 739 /* remove one level of indirection */ 740 p1 = *(struct kinfo_proc **) pp1; 741 p2 = *(struct kinfo_proc **) pp2; 742 743 ORDERKEY_PRIO 744 ORDERKEY_PCTCPU 745 ORDERKEY_CPUTIME 746 ORDERKEY_STATE 747 ORDERKEY_RSSIZE 748 ORDERKEY_MEM 749 ; 750 751 return(result); 752} 753 754int (*proc_compares[])() = { 755 compare_cpu, 756 compare_size, 757 compare_res, 758 compare_time, 759 compare_prio, 760 NULL 761}; 762#else 763/* 764 * proc_compare - comparison function for "qsort" 765 * Compares the resource consumption of two processes using five 766 * distinct keys. The keys (in descending order of importance) are: 767 * percent cpu, cpu ticks, state, resident set size, total virtual 768 * memory usage. The process states are ordered as follows (from least 769 * to most important): zombie, sleep, stop, start, run. The array 770 * declaration below maps a process state index into a number that 771 * reflects this ordering. 772 */ 773 774int 775proc_compare(v1, v2) 776 777const void *v1, *v2; 778 779{ 780 register struct proc **pp1 = (struct proc **)v1; 781 register struct proc **pp2 = (struct proc **)v2; 782 register struct kinfo_proc *p1; 783 register struct kinfo_proc *p2; 784 register int result; 785 register pctcpu lresult; 786 787 /* remove one level of indirection */ 788 p1 = *(struct kinfo_proc **) pp1; 789 p2 = *(struct kinfo_proc **) pp2; 790 791 /* compare percent cpu (pctcpu) */ 792 if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0) 793 { 794 /* use CPU usage to break the tie */ 795 if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0) 796 { 797 /* use process state to break the tie */ 798 if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - 799 sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) 800 { 801 /* use priority to break the tie */ 802 if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0) 803 { 804 /* use resident set size (rssize) to break the tie */ 805 if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0) 806 { 807 /* use total memory to break the tie */ 808 result = PROCSIZE(p2) - PROCSIZE(p1); 809 } 810 } 811 } 812 } 813 } 814 else 815 { 816 result = lresult < 0 ? -1 : 1; 817 } 818 819 return(result); 820} 821#endif 822 823/* 824 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 825 * the process does not exist. 826 * It is EXTREMLY IMPORTANT that this function work correctly. 827 * If top runs setuid root (as in SVR4), then this function 828 * is the only thing that stands in the way of a serious 829 * security problem. It validates requests for the "kill" 830 * and "renice" commands. 831 */ 832 833int proc_owner(pid) 834 835pid_t pid; 836 837{ 838 register int cnt; 839 register struct kinfo_proc **prefp; 840 register struct kinfo_proc *pp; 841 842 prefp = pref; 843 cnt = pref_len; 844 while (--cnt >= 0) 845 { 846 pp = *prefp++; 847 if (PP(pp, p_pid) == pid) 848 { 849 return((int)EP(pp, e_pcred.p_ruid)); 850 } 851 } 852 return(-1); 853} 854 855#ifdef DOSWAP 856/* 857 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org> 858 * to be based on the new swapctl(2) system call. 859 */ 860static int 861swapmode(used, total) 862int *used; 863int *total; 864{ 865 int nswap, rnswap, i; 866 struct swapent *swdev; 867 868 nswap = swapctl(SWAP_NSWAP, 0, 0); 869 if (nswap == 0) 870 return 0; 871 872 swdev = malloc(nswap * sizeof(*swdev)); 873 if(swdev == NULL) 874 return 0; 875 876 rnswap = swapctl(SWAP_STATS, swdev, nswap); 877 if(rnswap == -1) 878 return 0; 879 880 /* if rnswap != nswap, then what? */ 881 882 /* Total things up */ 883 *total = *used = 0; 884 for (i = 0; i < nswap; i++) { 885 if (swdev[i].se_flags & SWF_ENABLE) { 886 *used += (swdev[i].se_inuse / (1024/DEV_BSIZE)); 887 *total += (swdev[i].se_nblks / (1024/DEV_BSIZE)); 888 } 889 } 890 891 free (swdev); 892 return 1; 893} 894#endif 895