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