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