1/* 2 * Copyright (c) 1984 through 2008, William LeFebvre 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * * Neither the name of William LeFebvre nor the names of other 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33/* 34 * top - a top users display for Unix 35 * 36 * SYNOPSIS: any hp9000 running hpux version 9 37 * 38 * DESCRIPTION: 39 * This is the machine-dependent module for HPUX 9. 40 * This makes top work on (at least) the following systems: 41 * hp9000s800 42 * hp9000s700 43 * This may make top work on the following, but we aren't sure: 44 * hp9000s300 45 * 46 * LIBS: 47 * 48 * CFLAGS: -DHAVE_GETOPT 49 * 50 * AUTHOR: Kevin Schmidt <kevin@mcl.ucsb.edu> 51 * adapted from Christos Zoulas <christos@ee.cornell.edu> 52 */ 53 54#include "config.h" 55#include <sys/types.h> 56#include <sys/signal.h> 57#include <sys/param.h> 58 59#include <stdio.h> 60#include <nlist.h> 61#include <math.h> 62#include <sys/dir.h> 63#include <sys/user.h> 64#include <sys/proc.h> 65#include <sys/dk.h> 66#include <sys/vm.h> 67#include <sys/file.h> 68#include <sys/time.h> 69#ifndef hpux 70# define P_RSSIZE(p) (p)->p_rssize 71# define P_TSIZE(p) (p)->p_tsize 72# define P_DSIZE(p) (p)->p_dsize 73# define P_SSIZE(p) (p)->p_ssize 74#else 75# include <sys/pstat.h> 76# define __PST2P(p, field) \ 77 ((p)->p_upreg ? ((struct pst_status *) (p)->p_upreg)->field : 0) 78# define P_RSSIZE(p) __PST2P(p, pst_rssize) 79# define P_TSIZE(p) __PST2P(p, pst_tsize) 80# define P_DSIZE(p) __PST2P(p, pst_dsize) 81# define P_SSIZE(p) __PST2P(p, pst_ssize) 82# ifdef __hp9000s700 83# define p_percentcpu(p) ((p)->p_pctcpu) 84# define p_time_exact(p) ((p)->p_time) 85# else 86/* The following 4 #defines are per HPUX-9.0's <sys/proc.h> */ 87# define PCT_NORM 9 /* log2(PCT_BASE) */ 88# define PCT_BASE (1<<PCT_NORM) 89# define p_percentcpu(p) ((p)->p_fractioncpu/(float)(PCT_BASE*HZ)) 90# define p_time_exact(p) (time.tv_sec-((p)->p_swaptime)) 91# endif /* __hp9000s700 */ 92#endif /* hpux */ 93 94#include "top.h" 95#include "machine.h" 96#include "utils.h" 97 98#define VMUNIX "/hp-ux" 99#define KMEM "/dev/kmem" 100#define MEM "/dev/mem" 101#ifdef DOSWAP 102#define SWAP "/dev/dmem" 103#endif 104 105/* get_process_info passes back a handle. This is what it looks like: */ 106 107struct handle 108{ 109 struct proc **next_proc; /* points to next valid proc pointer */ 110 int remaining; /* number of pointers remaining */ 111}; 112 113/* declarations for load_avg */ 114#include "loadavg.h" 115 116/* define what weighted cpu is. */ 117#define weighted_cpu(pct, pp) ((p_time_exact(pp)) == 0 ? 0.0 : \ 118 ((pct) / (1.0 - exp((p_time_exact(pp)) * logcpu)))) 119 120/* what we consider to be process size: */ 121#define PROCSIZE(pp) (P_TSIZE(pp) + P_DSIZE(pp) + P_SSIZE(pp)) 122 123/* definitions for indices in the nlist array */ 124#define X_AVENRUN 0 125#define X_CCPU 1 126#define X_NPROC 2 127#define X_PROC 3 128#define X_TOTAL 4 129#define X_CP_TIME 5 130#define X_MPID 6 131 132/* 133 * Steinar Haug from University of Trondheim, NORWAY pointed out that 134 * the HP 9000 system 800 doesn't have _hz defined in the kernel. He 135 * provided a patch to work around this. We've improved on this patch 136 * here and set the constant X_HZ only when _hz is available in the 137 * kernel. Code in this module that uses X_HZ is surrounded with 138 * appropriate ifdefs. 139 */ 140 141#ifndef hp9000s300 142#define X_HZ 7 143#endif 144 145 146static struct nlist nlst[] = { 147 { "_avenrun" }, /* 0 */ 148 { "_cexp" }, /* 1 */ 149 { "_nproc" }, /* 2 */ 150 { "_proc" }, /* 3 */ 151 { "_total" }, /* 4 */ 152 { "_cp_time" }, /* 5 */ 153 { "_mpid" }, /* 6 */ 154#ifdef X_HZ 155 { "_hz" }, /* 7 */ 156#endif 157 { 0 } 158}; 159 160/* 161 * These definitions control the format of the per-process area 162 */ 163 164static char header[] = 165 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 166/* 0123456 -- field to fill in starts at header+6 */ 167#define UNAME_START 6 168 169#define Proc_format \ 170 "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s" 171 172/* process state names for the "STATE" column of the display */ 173/* the extra nulls in the string "run" are for adding a slash and 174 the processor number when needed */ 175 176char *state_abbrev[] = 177{ 178 "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop" 179}; 180 181 182static int kmem; 183 184/* values that we stash away in _init and use in later routines */ 185 186static double logcpu; 187 188/* these are retrieved from the kernel in _init */ 189 190static unsigned long proc; 191static int nproc; 192static long hz; 193static load_avg ccpu; 194static int ncpu = 0; 195 196/* these are offsets obtained via nlist and used in the get_ functions */ 197static unsigned long mpid_offset; 198static unsigned long avenrun_offset; 199static unsigned long total_offset; 200static unsigned long cp_time_offset; 201 202/* these are for calculating cpu state percentages */ 203 204static long cp_time[CPUSTATES]; 205static long cp_old[CPUSTATES]; 206static long cp_diff[CPUSTATES]; 207 208/* these are for detailing the process states */ 209 210int process_states[7]; 211char *procstatenames[] = { 212 "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ", 213 " zombie, ", " stopped, ", 214 NULL 215}; 216 217/* these are for detailing the cpu states */ 218 219int cpu_states[9]; 220char *cpustatenames[] = { 221 "usr", "nice", "sys", "idle", "", "", "", "intr", "ker", 222 NULL 223}; 224 225/* these are for detailing the memory statistics */ 226 227long memory_stats[8]; 228char *memorynames[] = { 229 "Real: ", "K act, ", "K tot ", "Virtual: ", "K act, ", 230 "K tot, ", "K free", NULL 231}; 232 233/* these are for keeping track of the proc array */ 234 235static int bytes; 236static int pref_len; 237static struct proc *pbase; 238static struct proc **pref; 239static struct pst_status *pst; 240 241/* these are for getting the memory statistics */ 242 243static int pageshift; /* log base 2 of the pagesize */ 244 245/* define pagetok in terms of pageshift */ 246 247#define pagetok(size) ((size) << pageshift) 248 249/* useful externals */ 250extern int errno; 251extern char *sys_errlist[]; 252 253long lseek(); 254long time(); 255 256machine_init(statics) 257 258struct statics *statics; 259 260{ 261 register int i = 0; 262 register int pagesize; 263 264 if ((kmem = open(KMEM, O_RDONLY)) == -1) { 265 perror(KMEM); 266 return(-1); 267 } 268#ifdef hp9000s800 269 /* 800 names don't have leading underscores */ 270 for (i = 0; nlst[i].n_name; nlst[i++].n_name++) 271 continue; 272#endif 273 274 /* get the list of symbols we want to access in the kernel */ 275 (void) nlist(VMUNIX, nlst); 276 if (nlst[0].n_type == 0) 277 { 278 fprintf(stderr, "top: nlist failed\n"); 279 return(-1); 280 } 281 282 /* make sure they were all found */ 283 if (check_nlist(nlst) > 0) 284 { 285 return(-1); 286 } 287 288 /* get the symbol values out of kmem */ 289 (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc), 290 nlst[X_PROC].n_name); 291 (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc), 292 nlst[X_NPROC].n_name); 293 (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu), 294 nlst[X_CCPU].n_name); 295#ifdef X_HZ 296 (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz), 297 nlst[X_HZ].n_name); 298#else 299 hz = HZ; 300#endif 301 302 /* stash away certain offsets for later use */ 303 mpid_offset = nlst[X_MPID].n_value; 304 avenrun_offset = nlst[X_AVENRUN].n_value; 305 total_offset = nlst[X_TOTAL].n_value; 306 cp_time_offset = nlst[X_CP_TIME].n_value; 307 308 /* this is used in calculating WCPU -- calculate it ahead of time */ 309 logcpu = log(loaddouble(ccpu)); 310 311 /* allocate space for proc structure array and array of pointers */ 312 bytes = nproc * sizeof(struct proc); 313 pbase = (struct proc *)malloc(bytes); 314 pref = (struct proc **)malloc(nproc * sizeof(struct proc *)); 315 pst = (struct pst_status *)malloc(nproc * sizeof(struct pst_status)); 316 317 /* Just in case ... */ 318 if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL) 319 { 320 fprintf(stderr, "top: can't allocate sufficient memory\n"); 321 return(-1); 322 } 323 324 /* get the page size with "getpagesize" and calculate pageshift from it */ 325 pagesize = getpagesize(); 326 pageshift = 0; 327 while (pagesize > 1) 328 { 329 pageshift++; 330 pagesize >>= 1; 331 } 332 333 /* we only need the amount of log(2)1024 for our conversion */ 334 pageshift -= LOG1024; 335 336 /* fill in the statics information */ 337 statics->procstate_names = procstatenames; 338 statics->cpustate_names = cpustatenames; 339 statics->memory_names = memorynames; 340 341 /* all done! */ 342 return(0); 343} 344 345char *format_header(uname_field) 346 347register char *uname_field; 348 349{ 350 register char *ptr; 351 352 ptr = header + UNAME_START; 353 while (*uname_field != '\0') 354 { 355 *ptr++ = *uname_field++; 356 } 357 358 return(header); 359} 360 361void 362get_system_info(si) 363 364struct system_info *si; 365 366{ 367 load_avg avenrun[3]; 368 long total; 369 370 /* get the cp_time array */ 371 (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time), 372 "_cp_time"); 373 374 /* get load average array */ 375 (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), 376 "_avenrun"); 377 378 /* get mpid -- process id of last process */ 379 (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid), 380 "_mpid"); 381 382 /* convert load averages to doubles */ 383 { 384 register int i; 385 register double *infoloadp; 386 register load_avg *sysloadp; 387 388 infoloadp = si->load_avg; 389 sysloadp = avenrun; 390 for (i = 0; i < 3; i++) 391 { 392 *infoloadp++ = loaddouble(*sysloadp++); 393 } 394 } 395 396 /* convert cp_time counts to percentages */ 397 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 398 399 /* sum memory statistics */ 400 { 401 struct vmtotal total; 402 403 /* get total -- systemwide main memory usage structure */ 404 (void) getkval(total_offset, (int *)(&total), sizeof(total), 405 "_total"); 406 /* convert memory stats to Kbytes */ 407 memory_stats[0] = -1; 408 memory_stats[1] = pagetok(total.t_arm); 409 memory_stats[2] = pagetok(total.t_rm); 410 memory_stats[3] = -1; 411 memory_stats[4] = pagetok(total.t_avm); 412 memory_stats[5] = pagetok(total.t_vm); 413 memory_stats[6] = pagetok(total.t_free); 414 } 415 416 /* set arrays and strings */ 417 si->cpustates = cpu_states; 418 si->memory = memory_stats; 419} 420 421static struct handle handle; 422 423caddr_t get_process_info(si, sel, i) 424 425struct system_info *si; 426struct process_select *sel; 427int i; 428 429{ 430 register int i; 431 register int total_procs; 432 register int active_procs; 433 register struct proc **prefp; 434 register struct proc *pp; 435 436 /* these are copied out of sel for speed */ 437 int show_idle; 438 int show_system; 439 int show_uid; 440 int show_command; 441 442 /* read all the proc structures in one fell swoop */ 443 (void) getkval(proc, (int *)pbase, bytes, "proc array"); 444 for (i = 0; i < nproc; ++i) { 445 if (pstat(PSTAT_PROC, &pst[i], sizeof(pst[i]), 0, pbase[i].p_pid) != 1) 446 pbase[i].p_upreg = (preg_t *) 0; 447 else 448 pbase[i].p_upreg = (preg_t *) &pst[i]; 449 pbase[i].p_nice = pst[i].pst_nice; 450 pbase[i].p_cpticks = pst[i].pst_cpticks; 451 } 452 453 454 /* get a pointer to the states summary array */ 455 si->procstates = process_states; 456 457 /* set up flags which define what we are going to select */ 458 show_idle = sel->idle; 459 show_system = sel->system; 460 show_uid = sel->uid != -1; 461 show_command = sel->command != NULL; 462 463 /* count up process states and get pointers to interesting procs */ 464 total_procs = 0; 465 active_procs = 0; 466 memset((char *)process_states, 0, sizeof(process_states)); 467 prefp = pref; 468 for (pp = pbase, i = 0; i < nproc; pp++, i++) 469 { 470 /* 471 * Place pointers to each valid proc structure in pref[]. 472 * Process slots that are actually in use have a non-zero 473 * status field. Processes with SSYS set are system 474 * processes---these get ignored unless show_sysprocs is set. 475 */ 476 if (pp->p_stat != 0 && 477 (show_system || ((pp->p_flag & SSYS) == 0))) 478 { 479 total_procs++; 480 process_states[pp->p_stat]++; 481 /* 482 * idle processes can be selectively ignored: a process is 483 * considered idle when cpticks is zero AND it is not in the run 484 * state. Zombies are always ignored. We also skip over 485 * processes that have been excluded via a uid selection 486 */ 487 if ((pp->p_stat != SZOMB) && 488 (show_idle || (pp->p_cpticks != 0) || (pp->p_stat == SRUN)) && 489 (!show_uid || pp->p_uid == (uid_t)sel->uid)) 490 { 491 *prefp++ = pp; 492 active_procs++; 493 } 494 } 495 } 496 497 /* if requested, sort the "interesting" processes */ 498 if (compare != NULL) 499 { 500 qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compare); 501 } 502 503 /* remember active and total counts */ 504 si->p_total = total_procs; 505 si->p_active = pref_len = active_procs; 506 507 /* pass back a handle */ 508 handle.next_proc = pref; 509 handle.remaining = active_procs; 510 return((caddr_t)&handle); 511} 512 513char fmt[MAX_COLS]; /* static area where result is built */ 514 515char *format_next_process(handle, get_userid) 516 517caddr_t handle; 518char *(*get_userid)(); 519 520{ 521 register struct proc *pp; 522 register long cputime; 523 register double pct; 524 int where; 525 struct user u; 526 struct handle *hp; 527 struct timeval time; 528 struct timezone timezone; 529 530 /* find and remember the next proc structure */ 531 hp = (struct handle *)handle; 532 pp = *(hp->next_proc++); 533 hp->remaining--; 534 535 536 /* get the process's user struct and set cputime */ 537 where = getu(pp, &u); 538 if (where == -1) 539 { 540 (void) strcpy(u.u_comm, "<swapped>"); 541 cputime = 0; 542 } 543 else 544 { 545 546 547 /* set u_comm for system processes */ 548 if (u.u_comm[0] == '\0') 549 { 550 if (pp->p_pid == 0) 551 { 552 (void) strcpy(u.u_comm, "Swapper"); 553 } 554 else if (pp->p_pid == 2) 555 { 556 (void) strcpy(u.u_comm, "Pager"); 557 } 558 } 559 if (where == 1) { 560 /* 561 * Print swapped processes as <pname> 562 */ 563 char buf[sizeof(u.u_comm)]; 564 (void) strncpy(buf, u.u_comm, sizeof(u.u_comm)); 565 u.u_comm[0] = '<'; 566 (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2); 567 u.u_comm[sizeof(u.u_comm) - 2] = '\0'; 568 (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1); 569 u.u_comm[sizeof(u.u_comm) - 1] = '\0'; 570 } 571 572 cputime = __PST2P(pp, pst_cptickstotal) / hz; 573 } 574 575 /* calculate the base for cpu percentages */ 576 pct = pctdouble(p_percentcpu(pp)); 577 578 /* get time used for calculation in weighted_cpu */ 579 gettimeofday(&time, &timezone); 580 581 /* format this entry */ 582 sprintf(fmt, 583 Proc_format, 584 pp->p_pid, 585 (*get_userid)(pp->p_uid), 586 pp->p_pri - PZERO, 587 pp->p_nice - NZERO, 588 format_k(pagetok(PROCSIZE(pp))), 589 format_k(pagetok(P_RSSIZE(pp))), 590 state_abbrev[pp->p_stat], 591 format_time(cputime), 592 100.0 * weighted_cpu(pct, pp), 593 100.0 * pct, 594 printable(u.u_comm)); 595 596 /* return the result */ 597 return(fmt); 598} 599 600/* 601 * getu(p, u) - get the user structure for the process whose proc structure 602 * is pointed to by p. The user structure is put in the buffer pointed 603 * to by u. Return 0 if successful, -1 on failure (such as the process 604 * being swapped out). 605 */ 606 607 608getu(p, u) 609 610register struct proc *p; 611struct user *u; 612 613{ 614 struct pst_status *ps; 615 char *s, *c; 616 int i; 617 618 if ((ps = (struct pst_status *) p->p_upreg) == NULL) 619 return -1; 620 621 memset(u, 0, sizeof(struct user)); 622 c = ps->pst_cmd; 623 ps->pst_cmd[PST_CLEN - 1] = '\0'; /* paranoia */ 624 s = strtok(ps->pst_cmd, "\t \n"); 625 626 if (c = strrchr(s, '/')) 627 c++; 628 else 629 c = s; 630 if (*c == '-') 631 c++; 632 i = 0; 633 for (; i < MAXCOMLEN; i++) { 634 if (*c == '\0' || *c == ' ' || *c == '/') 635 break; 636 u->u_comm[i] = *c++; 637 } 638#ifndef DOSWAP 639 return ((p->p_flag & SLOAD) == 0 ? 1 : 0); 640#endif 641 return(0); 642} 643 644/* 645 * check_nlist(nlst) - checks the nlist to see if any symbols were not 646 * found. For every symbol that was not found, a one-line 647 * message is printed to stderr. The routine returns the 648 * number of symbols NOT found. 649 */ 650 651int check_nlist(nlst) 652 653register struct nlist *nlst; 654 655{ 656 register int i; 657 658 /* check to see if we got ALL the symbols we requested */ 659 /* this will write one line to stderr for every symbol not found */ 660 661 i = 0; 662 while (nlst->n_name != NULL) 663 { 664 if (nlst->n_type == 0) 665 { 666 /* this one wasn't found */ 667 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name); 668 i = 1; 669 } 670 nlst++; 671 } 672 673 return(i); 674} 675 676 677/* 678 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 679 * "offset" is the byte offset into the kernel for the desired value, 680 * "ptr" points to a buffer into which the value is retrieved, 681 * "size" is the size of the buffer (and the object to retrieve), 682 * "refstr" is a reference string used when printing error meessages, 683 * if "refstr" starts with a '!', then a failure on read will not 684 * be fatal (this may seem like a silly way to do things, but I 685 * really didn't want the overhead of another argument). 686 * 687 */ 688 689getkval(offset, ptr, size, refstr) 690 691unsigned long offset; 692int *ptr; 693int size; 694char *refstr; 695 696{ 697 if (lseek(kmem, (long)offset, L_SET) == -1) { 698 if (*refstr == '!') 699 refstr++; 700 (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM, 701 refstr, strerror(errno)); 702 quit(23); 703 } 704 if (read(kmem, (char *) ptr, size) == -1) { 705 if (*refstr == '!') 706 return(0); 707 else { 708 (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM, 709 refstr, strerror(errno)); 710 quit(23); 711 } 712 } 713 return(1); 714} 715 716/* comparison routine for qsort */ 717 718/* 719 * proc_compare - comparison function for "qsort" 720 * Compares the resource consumption of two processes using five 721 * distinct keys. The keys (in descending order of importance) are: 722 * percent cpu, cpu ticks, state, resident set size, total virtual 723 * memory usage. The process states are ordered as follows (from least 724 * to most important): WAIT, zombie, sleep, stop, start, run. The 725 * array declaration below maps a process state index into a number 726 * that reflects this ordering. 727 */ 728 729static unsigned char sorted_state[] = 730{ 731 0, /* not used */ 732 3, /* sleep */ 733 1, /* ABANDONED (WAIT) */ 734 6, /* run */ 735 5, /* start */ 736 2, /* zombie */ 737 4 /* stop */ 738}; 739 740proc_compare(pp1, pp2) 741 742struct proc **pp1; 743struct proc **pp2; 744 745{ 746 register struct proc *p1; 747 register struct proc *p2; 748 register int result; 749 register pctcpu lresult; 750 751 /* remove one level of indirection */ 752 p1 = *pp1; 753 p2 = *pp2; 754 755 /* compare percent cpu (pctcpu) */ 756 if ((lresult = p_percentcpu(p2) - p_percentcpu(p1)) == 0) 757 { 758 /* use cpticks to break the tie */ 759 if ((result = p2->p_cpticks - p1->p_cpticks) == 0) 760 { 761 /* use process state to break the tie */ 762 if ((result = sorted_state[p2->p_stat] - 763 sorted_state[p1->p_stat]) == 0) 764 { 765 /* use priority to break the tie */ 766 if ((result = p2->p_pri - p1->p_pri) == 0) 767 { 768 /* use resident set size (rssize) to break the tie */ 769 if ((result = P_RSSIZE(p2) - P_RSSIZE(p1)) == 0) 770 { 771 /* use total memory to break the tie */ 772 result = PROCSIZE(p2) - PROCSIZE(p1); 773 } 774 } 775 } 776 } 777 } 778 else 779 { 780 result = lresult < 0 ? -1 : 1; 781 } 782 783 return(result); 784} 785 786 787void (*signal(sig, func))() 788 int sig; 789 void (*func)(); 790{ 791 struct sigvec osv, sv; 792 793 /* 794 * XXX: we should block the signal we are playing with, 795 * in case we get interrupted in here. 796 */ 797 if (sigvector(sig, NULL, &osv) == -1) 798 return BADSIG; 799 sv = osv; 800 sv.sv_handler = func; 801#ifdef SV_BSDSIG 802 sv.sv_flags |= SV_BSDSIG; 803#endif 804 if (sigvector(sig, &sv, NULL) == -1) 805 return BADSIG; 806 return osv.sv_handler; 807} 808 809int getpagesize() { return 1 << PGSHIFT; } 810 811int setpriority(a, b, c) { errno = ENOSYS; return -1; } 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 825int pid; 826 827{ 828 register int cnt; 829 register struct proc **prefp; 830 register struct proc *pp; 831 832 prefp = pref; 833 cnt = pref_len; 834 while (--cnt >= 0) 835 { 836 if ((pp = *prefp++)->p_pid == (pid_t)pid) 837 { 838 return((int)pp->p_uid); 839 } 840 } 841 return(-1); 842} 843