machine.c revision 1.29
1/* $OpenBSD: machine.c,v 1.29 2003/06/12 22:30:23 pvalchev 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(void) 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(struct statics *statics) 188{ 189 int pagesize; 190 191 stathz = getstathz(); 192 if (stathz == -1) 193 return (-1); 194 195 pbase = NULL; 196 pref = NULL; 197 onproc = -1; 198 nproc = 0; 199 200 /* get the page size with "getpagesize" and calculate pageshift from 201 * it */ 202 pagesize = getpagesize(); 203 pageshift = 0; 204 while (pagesize > 1) { 205 pageshift++; 206 pagesize >>= 1; 207 } 208 209 /* we only need the amount of log(2)1024 for our conversion */ 210 pageshift -= LOG1024; 211 212 /* fill in the statics information */ 213 statics->procstate_names = procstatenames; 214 statics->cpustate_names = cpustatenames; 215 statics->memory_names = memorynames; 216#ifdef ORDER 217 statics->order_names = ordernames; 218#endif 219 return (0); 220} 221 222char * 223format_header(char *uname_field) 224{ 225 char *ptr; 226 227 ptr = header + UNAME_START; 228 while (*uname_field != '\0') { 229 *ptr++ = *uname_field++; 230 } 231 return (header); 232} 233 234void 235get_system_info(si) 236 struct system_info *si; 237{ 238 static int sysload_mib[] = {CTL_VM, VM_LOADAVG}; 239 static int vmtotal_mib[] = {CTL_VM, VM_METER}; 240 static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME }; 241 struct loadavg sysload; 242 struct vmtotal vmtotal; 243 double *infoloadp; 244 int total, i; 245 size_t size; 246 247 size = sizeof(cp_time); 248 if (sysctl(cp_time_mib, 2, &cp_time, &size, NULL, 0) < 0) { 249 warn("sysctl kern.cp_time failed"); 250 total = 0; 251 } 252 253 size = sizeof(sysload); 254 if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) < 0) { 255 warn("sysctl failed"); 256 total = 0; 257 } 258 infoloadp = si->load_avg; 259 for (i = 0; i < 3; i++) 260 *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; 261 262 /* convert cp_time counts to percentages */ 263 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 264 265 /* get total -- systemwide main memory usage structure */ 266 size = sizeof(vmtotal); 267 if (sysctl(vmtotal_mib, 2, &vmtotal, &size, NULL, 0) < 0) { 268 warn("sysctl failed"); 269 bzero(&vmtotal, sizeof(vmtotal)); 270 } 271 /* convert memory stats to Kbytes */ 272 memory_stats[0] = -1; 273 memory_stats[1] = pagetok(vmtotal.t_arm); 274 memory_stats[2] = pagetok(vmtotal.t_rm); 275 memory_stats[3] = -1; 276 memory_stats[4] = pagetok(vmtotal.t_free); 277 memory_stats[5] = -1; 278#ifdef DOSWAP 279 if (!swapmode(&memory_stats[6], &memory_stats[7])) { 280 memory_stats[6] = 0; 281 memory_stats[7] = 0; 282 } 283#endif 284 285 /* set arrays and strings */ 286 si->cpustates = cpu_states; 287 si->memory = memory_stats; 288 si->last_pid = -1; 289} 290 291static struct handle handle; 292 293struct kinfo_proc * 294getprocs(int op, int arg, int *cnt) 295{ 296 size_t size = sizeof(int); 297 int mib[4] = {CTL_KERN, KERN_PROC, op, arg}; 298 int smib[2] = {CTL_KERN, KERN_NPROCS}; 299 static int maxslp_mib[] = {CTL_VM, VM_MAXSLP}; 300 static struct kinfo_proc *procbase; 301 int st; 302 303 size = sizeof(maxslp); 304 if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) < 0) { 305 warn("sysctl vm.maxslp failed"); 306 return (0); 307 } 308 309 st = sysctl(smib, 2, cnt, &size, NULL, 0); 310 if (st == -1) { 311 /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */ 312 return (0); 313 } 314 if (procbase) 315 free(procbase); 316 size = (6 * (*cnt) * sizeof(struct kinfo_proc)) / 5; 317 procbase = (struct kinfo_proc *)malloc(size); 318 if (procbase == NULL) 319 return (0); 320 st = sysctl(mib, 4, procbase, &size, NULL, 0); 321 if (st == -1) { 322 /* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */ 323 return (0); 324 } 325 if (size % sizeof(struct kinfo_proc) != 0) { 326 /* _kvm_err(kd, kd->program, 327 "proc size mismatch (%d total, %d chunks)", 328 size, sizeof(struct kinfo_proc)); */ 329 return (0); 330 } 331 return (procbase); 332} 333 334caddr_t 335get_process_info(struct system_info *si, struct process_select *sel, 336 int (*compare)(const void *, const void *)) 337{ 338 int show_idle, show_system, show_uid, show_command; 339 int total_procs, active_procs, i; 340 struct kinfo_proc **prefp, *pp; 341 342 if ((pbase = getprocs(KERN_PROC_KTHREAD, 0, &nproc)) == NULL) { 343 /* warnx("%s", kvm_geterr(kd)); */ 344 quit(23); 345 } 346 if (nproc > onproc) 347 pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) 348 * (onproc = nproc)); 349 if (pref == NULL) { 350 warnx("Out of memory."); 351 quit(23); 352 } 353 /* get a pointer to the states summary array */ 354 si->procstates = process_states; 355 356 /* set up flags which define what we are going to select */ 357 show_idle = sel->idle; 358 show_system = sel->system; 359 show_uid = sel->uid != -1; 360 show_command = sel->command != NULL; 361 362 /* count up process states and get pointers to interesting procs */ 363 total_procs = 0; 364 active_procs = 0; 365 memset((char *) process_states, 0, sizeof(process_states)); 366 prefp = pref; 367 for (pp = pbase, i = 0; i < nproc; pp++, i++) { 368 /* 369 * Place pointers to each valid proc structure in pref[]. 370 * Process slots that are actually in use have a non-zero 371 * status field. Processes with SSYS set are system 372 * processes---these get ignored unless show_sysprocs is set. 373 */ 374 if (PP(pp, p_stat) != 0 && 375 (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0))) { 376 total_procs++; 377 process_states[(unsigned char) PP(pp, p_stat)]++; 378 if ((PP(pp, p_stat) != SZOMB) && 379 (show_idle || (PP(pp, p_pctcpu) != 0) || 380 (PP(pp, p_stat) == SRUN)) && 381 (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t) sel->uid)) { 382 *prefp++ = pp; 383 active_procs++; 384 } 385 } 386 } 387 388 /* if requested, sort the "interesting" processes */ 389 if (compare != NULL) { 390 qsort((char *) pref, active_procs, sizeof(struct kinfo_proc *), compare); 391 } 392 /* remember active and total counts */ 393 si->p_total = total_procs; 394 si->p_active = pref_len = active_procs; 395 396 /* pass back a handle */ 397 handle.next_proc = pref; 398 handle.remaining = active_procs; 399 return ((caddr_t) & handle); 400} 401 402char fmt[MAX_COLS]; /* static area where result is built */ 403 404char * 405format_next_process(caddr_t handle, char *(*get_userid)()) 406{ 407 char waddr[sizeof(void *) * 2 + 3]; /* Hexify void pointer */ 408 struct kinfo_proc *pp; 409 struct handle *hp; 410 char *p_wait; 411 int cputime; 412 double pct; 413 414 /* find and remember the next proc structure */ 415 hp = (struct handle *) handle; 416 pp = *(hp->next_proc++); 417 hp->remaining--; 418 419 /* get the process's user struct and set cputime */ 420 if ((PP(pp, p_flag) & P_INMEM) == 0) { 421 /* 422 * Print swapped processes as <pname> 423 */ 424 char *comm = PP(pp, p_comm); 425#define COMSIZ sizeof(PP(pp, p_comm)) 426 char buf[COMSIZ]; 427 (void) strncpy(buf, comm, COMSIZ); 428 comm[0] = '<'; 429 (void) strncpy(&comm[1], buf, COMSIZ - 2); 430 comm[COMSIZ - 2] = '\0'; 431 (void) strncat(comm, ">", COMSIZ - 1); 432 comm[COMSIZ - 1] = '\0'; 433 } 434 cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz; 435 436 /* calculate the base for cpu percentages */ 437 pct = pctdouble(PP(pp, p_pctcpu)); 438 439 if (PP(pp, p_wchan)) 440 if (PP(pp, p_wmesg)) 441 p_wait = EP(pp, e_wmesg); 442 else { 443 snprintf(waddr, sizeof(waddr), "%lx", 444 (unsigned long) (PP(pp, p_wchan)) & ~KERNBASE); 445 p_wait = waddr; 446 } 447 else 448 p_wait = "-"; 449 450 /* format this entry */ 451 snprintf(fmt, MAX_COLS, 452 Proc_format, 453 PP(pp, p_pid), 454 (*get_userid) (EP(pp, e_pcred.p_ruid)), 455 PP(pp, p_priority) - PZERO, 456 PP(pp, p_nice) - NZERO, 457 format_k(pagetok(PROCSIZE(pp))), 458 format_k(pagetok(VP(pp, vm_rssize))), 459 (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > maxslp) 460 ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)], 461 p_wait, 462 format_time(cputime), 463 100.0 * pct, 464 printable(PP(pp, p_comm))); 465 466 /* return the result */ 467 return (fmt); 468} 469 470/* comparison routine for qsort */ 471static unsigned char sorted_state[] = 472{ 473 0, /* not used */ 474 4, /* start */ 475 5, /* run */ 476 2, /* sleep */ 477 3, /* stop */ 478 1 /* zombie */ 479}; 480#ifdef ORDER 481 482/* 483 * proc_compares - comparison functions for "qsort" 484 */ 485 486/* 487 * First, the possible comparison keys. These are defined in such a way 488 * that they can be merely listed in the source code to define the actual 489 * desired ordering. 490 */ 491 492 493#define ORDERKEY_PCTCPU \ 494 if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \ 495 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 496#define ORDERKEY_CPUTIME \ 497 if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \ 498 if ((result = PP(p2, p_rtime.tv_usec) - \ 499 PP(p1, p_rtime.tv_usec)) == 0) 500#define ORDERKEY_STATE \ 501 if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \ 502 sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) 503#define ORDERKEY_PRIO \ 504 if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0) 505#define ORDERKEY_RSSIZE \ 506 if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0) 507#define ORDERKEY_MEM \ 508 if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0) 509 510 511/* compare_cpu - the comparison function for sorting by cpu percentage */ 512int 513compare_cpu(const void *v1, const void *v2) 514{ 515 struct proc **pp1 = (struct proc **) v1; 516 struct proc **pp2 = (struct proc **) v2; 517 struct kinfo_proc *p1; 518 struct kinfo_proc *p2; 519 int result; 520 pctcpu lresult; 521 522 /* remove one level of indirection */ 523 p1 = *(struct kinfo_proc **) pp1; 524 p2 = *(struct kinfo_proc **) pp2; 525 526 ORDERKEY_PCTCPU 527 ORDERKEY_CPUTIME 528 ORDERKEY_STATE 529 ORDERKEY_PRIO 530 ORDERKEY_RSSIZE 531 ORDERKEY_MEM 532 ; 533 return (result); 534} 535 536/* compare_size - the comparison function for sorting by total memory usage */ 537int 538compare_size(const void *v1, const void *v2) 539{ 540 struct proc **pp1 = (struct proc **) v1; 541 struct proc **pp2 = (struct proc **) v2; 542 struct kinfo_proc *p1; 543 struct kinfo_proc *p2; 544 int result; 545 pctcpu lresult; 546 547 /* remove one level of indirection */ 548 p1 = *(struct kinfo_proc **) pp1; 549 p2 = *(struct kinfo_proc **) pp2; 550 551 ORDERKEY_MEM 552 ORDERKEY_RSSIZE 553 ORDERKEY_PCTCPU 554 ORDERKEY_CPUTIME 555 ORDERKEY_STATE 556 ORDERKEY_PRIO 557 ; 558 return (result); 559} 560 561/* compare_res - the comparison function for sorting by resident set size */ 562int 563compare_res(const void *v1, const void *v2) 564{ 565 struct proc **pp1 = (struct proc **) v1; 566 struct proc **pp2 = (struct proc **) v2; 567 struct kinfo_proc *p1; 568 struct kinfo_proc *p2; 569 int result; 570 pctcpu lresult; 571 572 /* remove one level of indirection */ 573 p1 = *(struct kinfo_proc **) pp1; 574 p2 = *(struct kinfo_proc **) pp2; 575 576 ORDERKEY_RSSIZE 577 ORDERKEY_MEM 578 ORDERKEY_PCTCPU 579 ORDERKEY_CPUTIME 580 ORDERKEY_STATE 581 ORDERKEY_PRIO 582 ; 583 return (result); 584} 585 586/* compare_time - the comparison function for sorting by CPU time */ 587int 588compare_time(const void *v1, const void *v2) 589{ 590 struct proc **pp1 = (struct proc **) v1; 591 struct proc **pp2 = (struct proc **) v2; 592 struct kinfo_proc *p1; 593 struct kinfo_proc *p2; 594 int result; 595 pctcpu lresult; 596 597 /* remove one level of indirection */ 598 p1 = *(struct kinfo_proc **) pp1; 599 p2 = *(struct kinfo_proc **) pp2; 600 601 ORDERKEY_CPUTIME 602 ORDERKEY_PCTCPU 603 ORDERKEY_STATE 604 ORDERKEY_PRIO 605 ORDERKEY_MEM 606 ORDERKEY_RSSIZE 607 ; 608 return (result); 609} 610 611/* compare_prio - the comparison function for sorting by CPU time */ 612int 613compare_prio(const void *v1, const void *v2) 614{ 615 struct proc **pp1 = (struct proc **) v1; 616 struct proc **pp2 = (struct proc **) v2; 617 struct kinfo_proc *p1; 618 struct kinfo_proc *p2; 619 int result; 620 pctcpu lresult; 621 622 /* remove one level of indirection */ 623 p1 = *(struct kinfo_proc **) pp1; 624 p2 = *(struct kinfo_proc **) pp2; 625 626 ORDERKEY_PRIO 627 ORDERKEY_PCTCPU 628 ORDERKEY_CPUTIME 629 ORDERKEY_STATE 630 ORDERKEY_RSSIZE 631 ORDERKEY_MEM 632 ; 633 return (result); 634} 635 636int (*proc_compares[]) () = { 637 compare_cpu, 638 compare_size, 639 compare_res, 640 compare_time, 641 compare_prio, 642 NULL 643}; 644#else 645/* 646 * proc_compare - comparison function for "qsort" 647 * Compares the resource consumption of two processes using five 648 * distinct keys. The keys (in descending order of importance) are: 649 * percent cpu, cpu ticks, state, resident set size, total virtual 650 * memory usage. The process states are ordered as follows (from least 651 * to most important): zombie, sleep, stop, start, run. The array 652 * declaration below maps a process state index into a number that 653 * reflects this ordering. 654 */ 655int 656proc_compare(const void *v1, const void *v2) 657{ 658 struct proc **pp1 = (struct proc **) v1; 659 struct proc **pp2 = (struct proc **) v2; 660 struct kinfo_proc *p1; 661 struct kinfo_proc *p2; 662 int result; 663 pctcpu lresult; 664 665 /* remove one level of indirection */ 666 p1 = *(struct kinfo_proc **) pp1; 667 p2 = *(struct kinfo_proc **) pp2; 668 669 /* compare percent cpu (pctcpu) */ 670 if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0) { 671 /* use CPU usage to break the tie */ 672 if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0) { 673 /* use process state to break the tie */ 674 if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - 675 sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) { 676 /* use priority to break the tie */ 677 if ((result = PP(p2, p_priority) - 678 PP(p1, p_priority)) == 0) { 679 /* use resident set size (rssize) to 680 * break the tie */ 681 if ((result = VP(p2, vm_rssize) - 682 VP(p1, vm_rssize)) == 0) { 683 /* use total memory to break 684 * the tie */ 685 result = PROCSIZE(p2) - PROCSIZE(p1); 686 } 687 } 688 } 689 } 690 } else { 691 result = lresult < 0 ? -1 : 1; 692 } 693 return (result); 694} 695#endif 696 697/* 698 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 699 * the process does not exist. 700 * It is EXTREMLY IMPORTANT that this function work correctly. 701 * If top runs setuid root (as in SVR4), then this function 702 * is the only thing that stands in the way of a serious 703 * security problem. It validates requests for the "kill" 704 * and "renice" commands. 705 */ 706int 707proc_owner(pid_t pid) 708{ 709 struct kinfo_proc **prefp, *pp; 710 int cnt; 711 712 prefp = pref; 713 cnt = pref_len; 714 while (--cnt >= 0) { 715 pp = *prefp++; 716 if (PP(pp, p_pid) == pid) { 717 return ((int) EP(pp, e_pcred.p_ruid)); 718 } 719 } 720 return (-1); 721} 722#ifdef DOSWAP 723/* 724 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org> 725 * to be based on the new swapctl(2) system call. 726 */ 727static int 728swapmode(int *used, int *total) 729{ 730 int nswap, rnswap, i; 731 struct swapent *swdev; 732 733 nswap = swapctl(SWAP_NSWAP, 0, 0); 734 if (nswap == 0) 735 return 0; 736 737 swdev = malloc(nswap * sizeof(*swdev)); 738 if (swdev == NULL) 739 return 0; 740 741 rnswap = swapctl(SWAP_STATS, swdev, nswap); 742 if (rnswap == -1) 743 return 0; 744 745 /* if rnswap != nswap, then what? */ 746 747 /* Total things up */ 748 *total = *used = 0; 749 for (i = 0; i < nswap; i++) { 750 if (swdev[i].se_flags & SWF_ENABLE) { 751 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE)); 752 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE)); 753 } 754 } 755 756 free(swdev); 757 return 1; 758} 759#endif 760