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