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 7 or earlier 37 * 38 * DESCRIPTION: 39 * This is the machine-dependent module for Hpux 6.5 and 7.0. 40 * This makes top work on the following systems: 41 * hp9000s300 42 * hp9000s700 43 * hp9000s800 44 * 45 * LIBS: 46 * 47 * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> 48 */ 49 50#include "config.h" 51#include <sys/types.h> 52#include <sys/signal.h> 53#include <sys/param.h> 54 55#include <stdio.h> 56#include <nlist.h> 57#include <math.h> 58#include <sys/dir.h> 59#include <sys/user.h> 60#include <sys/proc.h> 61#include <sys/dk.h> 62#include <sys/vm.h> 63#include <sys/file.h> 64#include <sys/time.h> 65 66#include "top.h" 67#include "machine.h" 68#include "utils.h" 69 70#define VMUNIX "/hp-ux" 71#define KMEM "/dev/kmem" 72#define MEM "/dev/mem" 73#ifdef DOSWAP 74#define SWAP "/dev/swap" 75#endif 76 77/* get_process_info passes back a handle. This is what it looks like: */ 78 79struct handle 80{ 81 struct proc **next_proc; /* points to next valid proc pointer */ 82 int remaining; /* number of pointers remaining */ 83}; 84 85/* declarations for load_avg */ 86#include "loadavg.h" 87 88/* define what weighted cpu is. */ 89#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \ 90 ((pct) / (1.0 - exp((pp)->p_time * logcpu)))) 91 92/* what we consider to be process size: */ 93#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize) 94 95/* definitions for indices in the nlist array */ 96#define X_AVENRUN 0 97#define X_CCPU 1 98#define X_NPROC 2 99#define X_PROC 3 100#define X_TOTAL 4 101#define X_CP_TIME 5 102#ifdef hp9000s300 103# define X_USRPTMAP 6 104# define X_USRPT 7 105#else 106# define X_MPID 6 107# define X_HZ 7 108#endif 109#ifdef hp9000s800 110# define X_NPIDS 8 111# define X_UBASE 9 112#endif 113 114static struct nlist nlst[] = { 115 { "_avenrun" }, /* 0 */ 116 { "_ccpu" }, /* 1 */ 117 { "_nproc" }, /* 2 */ 118 { "_proc" }, /* 3 */ 119 { "_total" }, /* 4 */ 120 { "_cp_time" }, /* 5 */ 121#ifdef hp9000s300 122 { "_Usrptmap" }, /* 6 */ 123 { "_usrpt" }, /* 7 */ 124#else 125 { "_mpid" }, /* 6 */ 126 { "_hz" }, /* 7 */ 127#endif 128#ifdef hp9000s800 129 { "_npids" }, /* 8 */ 130 { "_ubase" }, /* 9 */ 131#endif 132 { 0 } 133}; 134 135/* 136 * These definitions control the format of the per-process area 137 */ 138 139static char header[] = 140 " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 141/* 0123456 -- field to fill in starts at header+6 */ 142#define UNAME_START 6 143 144#define Proc_format \ 145 "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s" 146 147 148/* process state names for the "STATE" column of the display */ 149/* the extra nulls in the string "run" are for adding a slash and 150 the processor number when needed */ 151 152char *state_abbrev[] = 153{ 154 "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop" 155}; 156 157 158static int kmem, mem; 159#ifdef DOSWAP 160static int swap; 161#endif 162 163/* values that we stash away in _init and use in later routines */ 164 165static double logcpu; 166 167/* these are retrieved from the kernel in _init */ 168 169static unsigned long proc; 170static int nproc; 171static long hz; 172static load_avg ccpu; 173static int ncpu = 0; 174 175/* these are offsets obtained via nlist and used in the get_ functions */ 176 177#ifndef hp9000s300 178static unsigned long mpid_offset; 179#endif 180#ifdef hp9000s300 181static struct pte *Usrptmap, *usrpt; 182#endif 183#ifdef hp9000s800 184static int npids; 185char *ubase; 186#endif 187static unsigned long avenrun_offset; 188static unsigned long total_offset; 189static unsigned long cp_time_offset; 190 191/* these are for calculating cpu state percentages */ 192 193static long cp_time[CPUSTATES]; 194static long cp_old[CPUSTATES]; 195static long cp_diff[CPUSTATES]; 196 197/* these are for detailing the process states */ 198 199int process_states[7]; 200char *procstatenames[] = { 201 "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ", 202 " zombie, ", " stopped, ", 203 NULL 204}; 205 206/* these are for detailing the cpu states */ 207 208#ifdef hp9000s300 209int cpu_states[9]; 210#endif 211#ifdef hp9000s800 212int cpu_states[5]; 213#endif 214char *cpustatenames[] = { 215#ifdef hp9000s300 216 "usr", "nice", "sys", "idle", "", "", "", "intr", "ker", 217#endif 218#ifdef hp9000s800 219 "user", "nice", "system", "idle", "wait", 220#endif 221 NULL 222}; 223 224/* these are for detailing the memory statistics */ 225 226long memory_stats[8]; 227char *memorynames[] = { 228 "Real: ", "K active, ", "K total ", "Virtual: ", "K active, ", 229 "K total, ", "K free", NULL 230}; 231 232/* these are for keeping track of the proc array */ 233 234static int bytes; 235static int pref_len; 236static struct proc *pbase; 237static struct proc **pref; 238 239/* these are for getting the memory statistics */ 240 241static int pageshift; /* log base 2 of the pagesize */ 242 243/* define pagetok in terms of pageshift */ 244 245#define pagetok(size) ((size) << pageshift) 246 247/* useful externals */ 248extern int errno; 249extern char *sys_errlist[]; 250 251long lseek(); 252long time(); 253 254machine_init(statics) 255 256struct statics *statics; 257 258{ 259 register int i = 0; 260 register int pagesize; 261 262 if ((kmem = open(KMEM, O_RDONLY)) == -1) { 263 perror(KMEM); 264 return(-1); 265 } 266 if ((mem = open(MEM, O_RDONLY)) == -1) { 267 perror(MEM); 268 return(-1); 269 } 270 271#ifdef DOSWAP 272 if ((swap = open(SWAP, O_RDONLY)) == -1) { 273 perror(SWAP); 274 return(-1); 275 } 276#endif 277 278#ifdef hp9000s800 279 /* 800 names don't have leading underscores */ 280 for (i = 0; nlst[i].n_name; nlst[i++].n_name++) 281 continue; 282#endif 283 284 /* get the list of symbols we want to access in the kernel */ 285 (void) nlist(VMUNIX, nlst); 286 if (nlst[0].n_type == 0) 287 { 288 fprintf(stderr, "top: nlist failed\n"); 289 return(-1); 290 } 291 292 /* make sure they were all found */ 293 if (i > 0 && check_nlist(nlst) > 0) 294 { 295 return(-1); 296 } 297 298 /* get the symbol values out of kmem */ 299 (void) getkval(nlst[X_PROC].n_value, (int *)(&proc), sizeof(proc), 300 nlst[X_PROC].n_name); 301 (void) getkval(nlst[X_NPROC].n_value, &nproc, sizeof(nproc), 302 nlst[X_NPROC].n_name); 303#ifndef hp9000s300 304 (void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz), 305 nlst[X_HZ].n_name); 306#else 307 hz = HZ; 308#endif 309 (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu), 310 nlst[X_CCPU].n_name); 311#ifdef hp9000s800 312 (void) getkval(nlst[X_NPIDS].n_value, (int *)(&npids), sizeof(npids), 313 nlst[X_NPIDS].n_name); 314#endif 315 316 /* stash away certain offsets for later use */ 317#ifdef hp9000s800 318# ifndef UAREA 319 ubase = nlst[X_UBASE].n_value; 320# else 321 ubase = UAREA; 322# endif 323#endif 324#ifdef hp9000s300 325 Usrptmap = (struct pte *) nlst[X_USRPTMAP].n_value; 326 usrpt = (struct pte *) nlst[X_USRPT].n_value; 327#endif 328#ifndef hp9000s300 329 mpid_offset = nlst[X_MPID].n_value; 330#endif 331 avenrun_offset = nlst[X_AVENRUN].n_value; 332 total_offset = nlst[X_TOTAL].n_value; 333 cp_time_offset = nlst[X_CP_TIME].n_value; 334 335 /* this is used in calculating WCPU -- calculate it ahead of time */ 336 logcpu = log(loaddouble(ccpu)); 337 338 /* allocate space for proc structure array and array of pointers */ 339 bytes = nproc * sizeof(struct proc); 340 pbase = (struct proc *)malloc(bytes); 341 pref = (struct proc **)malloc(nproc * sizeof(struct proc *)); 342 343 /* Just in case ... */ 344 if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL) 345 { 346 fprintf(stderr, "top: can't allocate sufficient memory\n"); 347 return(-1); 348 } 349 350 /* get the page size with "getpagesize" and calculate pageshift from it */ 351 pagesize = getpagesize(); 352 pageshift = 0; 353 while (pagesize > 1) 354 { 355 pageshift++; 356 pagesize >>= 1; 357 } 358 359 /* we only need the amount of log(2)1024 for our conversion */ 360 pageshift -= LOG1024; 361 362 /* fill in the statics information */ 363 statics->procstate_names = procstatenames; 364 statics->cpustate_names = cpustatenames; 365 statics->memory_names = memorynames; 366 367 /* all done! */ 368 return(0); 369} 370 371char *format_header(uname_field) 372 373register char *uname_field; 374 375{ 376 register char *ptr; 377 378 ptr = header + UNAME_START; 379 while (*uname_field != '\0') 380 { 381 *ptr++ = *uname_field++; 382 } 383 384 return(header); 385} 386 387void 388get_system_info(si) 389 390struct system_info *si; 391 392{ 393 load_avg avenrun[3]; 394 long total; 395 396 /* get the cp_time array */ 397 (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time), 398 "_cp_time"); 399 400 /* get load average array */ 401 (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), 402 "_avenrun"); 403 404#ifndef hp9000s300 405 /* get mpid -- process id of last process */ 406 (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid), 407 "_mpid"); 408#else 409 si->last_pid = -1; 410#endif 411 412 /* convert load averages to doubles */ 413 { 414 register int i; 415 register double *infoloadp; 416 register load_avg *sysloadp; 417 418 infoloadp = si->load_avg; 419 sysloadp = avenrun; 420 for (i = 0; i < 3; i++) 421 { 422 *infoloadp++ = loaddouble(*sysloadp++); 423 } 424 } 425 426 /* convert cp_time counts to percentages */ 427 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 428 429 /* sum memory statistics */ 430 { 431 struct vmtotal total; 432 433 /* get total -- systemwide main memory usage structure */ 434 (void) getkval(total_offset, (int *)(&total), sizeof(total), 435 "_total"); 436 /* convert memory stats to Kbytes */ 437 memory_stats[0] = -1; 438 memory_stats[1] = pagetok(total.t_arm); 439 memory_stats[2] = pagetok(total.t_rm); 440 memory_stats[3] = -1; 441 memory_stats[4] = pagetok(total.t_avm); 442 memory_stats[5] = pagetok(total.t_vm); 443 memory_stats[6] = pagetok(total.t_free); 444 } 445 446 /* set arrays and strings */ 447 si->cpustates = cpu_states; 448 si->memory = memory_stats; 449} 450 451static struct handle handle; 452 453caddr_t get_process_info(si, sel, i) 454 455struct system_info *si; 456struct process_select *sel; 457int i; 458 459{ 460 register int i; 461 register int total_procs; 462 register int active_procs; 463 register struct proc **prefp; 464 register struct proc *pp; 465 466 /* these are copied out of sel for speed */ 467 int show_idle; 468 int show_system; 469 int show_uid; 470 int show_command; 471 472 /* read all the proc structures in one fell swoop */ 473 (void) getkval(proc, (int *)pbase, bytes, "proc array"); 474 475 /* get a pointer to the states summary array */ 476 si->procstates = process_states; 477 478 /* set up flags which define what we are going to select */ 479 show_idle = sel->idle; 480 show_system = sel->system; 481 show_uid = sel->uid != -1; 482 show_command = sel->command != NULL; 483 484 /* count up process states and get pointers to interesting procs */ 485 total_procs = 0; 486 active_procs = 0; 487 memset((char *)process_states, 0, sizeof(process_states)); 488 prefp = pref; 489 for (pp = pbase, i = 0; i < nproc; pp++, i++) 490 { 491 /* 492 * Place pointers to each valid proc structure in pref[]. 493 * Process slots that are actually in use have a non-zero 494 * status field. Processes with SSYS set are system 495 * processes---these get ignored unless show_sysprocs is set. 496 */ 497 if (pp->p_stat != 0 && 498 (show_system || ((pp->p_flag & SSYS) == 0))) 499 { 500 total_procs++; 501 process_states[pp->p_stat]++; 502 if ((pp->p_stat != SZOMB) && 503 (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) && 504 (!show_uid || pp->p_uid == (uid_t)sel->uid)) 505 { 506 *prefp++ = pp; 507 active_procs++; 508 } 509 } 510 } 511 512 /* if requested, sort the "interesting" processes */ 513 if (compare != NULL) 514 { 515 qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compare); 516 } 517 518 /* remember active and total counts */ 519 si->p_total = total_procs; 520 si->p_active = pref_len = active_procs; 521 522 /* pass back a handle */ 523 handle.next_proc = pref; 524 handle.remaining = active_procs; 525 return((caddr_t)&handle); 526} 527 528char fmt[MAX_COLS]; /* static area where result is built */ 529 530char *format_next_process(handle, get_userid) 531 532caddr_t handle; 533char *(*get_userid)(); 534 535{ 536 register struct proc *pp; 537 register long cputime; 538 register double pct; 539 int where; 540 struct user u; 541 struct handle *hp; 542 543 /* find and remember the next proc structure */ 544 hp = (struct handle *)handle; 545 pp = *(hp->next_proc++); 546 hp->remaining--; 547 548 549 /* get the process's user struct and set cputime */ 550 where = getu(pp, &u); 551 if (where == -1) 552 { 553 (void) strcpy(u.u_comm, "<swapped>"); 554 cputime = 0; 555 } 556 else 557 { 558 559 560 /* set u_comm for system processes */ 561 if (u.u_comm[0] == '\0') 562 { 563 if (pp->p_pid == 0) 564 { 565 (void) strcpy(u.u_comm, "Swapper"); 566 } 567 else if (pp->p_pid == 2) 568 { 569 (void) strcpy(u.u_comm, "Pager"); 570 } 571 } 572 if (where == 1) { 573 /* 574 * Print swapped processes as <pname> 575 */ 576 char buf[sizeof(u.u_comm)]; 577 (void) strncpy(buf, u.u_comm, sizeof(u.u_comm)); 578 u.u_comm[0] = '<'; 579 (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2); 580 u.u_comm[sizeof(u.u_comm) - 2] = '\0'; 581 (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1); 582 u.u_comm[sizeof(u.u_comm) - 1] = '\0'; 583 } 584 585 cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec; 586 } 587 588 /* calculate the base for cpu percentages */ 589 pct = pctdouble(pp->p_pctcpu); 590 591 /* format this entry */ 592 sprintf(fmt, 593 Proc_format, 594 pp->p_pid, 595 (*get_userid)(pp->p_uid), 596 pp->p_pri - PZERO, 597 pp->p_nice - NZERO, 598 format_k(pagetok(PROCSIZE(pp))), 599 format_k(pagetok(pp->p_rssize)), 600 state_abbrev[pp->p_stat], 601 format_time(cputime), 602 100.0 * weighted_cpu(pct, pp), 603 100.0 * pct, 604 printable(u.u_comm)); 605 606 /* return the result */ 607 return(fmt); 608} 609 610/* 611 * getu(p, u) - get the user structure for the process whose proc structure 612 * is pointed to by p. The user structure is put in the buffer pointed 613 * to by u. Return 0 if successful, -1 on failure (such as the process 614 * being swapped out). 615 */ 616 617#define USERSIZE sizeof(struct user) 618 619getu(p, u) 620 621register struct proc *p; 622struct user *u; 623 624{ 625 struct pte uptes[UPAGES]; 626 register caddr_t upage; 627 register struct pte *pte; 628 register nbytes, n; 629 630 /* 631 * Check if the process is currently loaded or swapped out. The way we 632 * get the u area is totally different for the two cases. For this 633 * application, we just don't bother if the process is swapped out. 634 */ 635 if ((p->p_flag & SLOAD) == 0) { 636#ifdef DOSWAP 637 if (lseek(swap, (long)dtob(p->p_swaddr), 0) == -1) { 638 perror("lseek(swap)"); 639 return(-1); 640 } 641 if (read(swap, (char *) u, USERSIZE) != USERSIZE) { 642 perror("read(swap)"); 643 return(-1); 644 } 645 return (1); 646#else 647 return(-1); 648#endif 649 } 650 651 /* 652 * Process is currently in memory, we hope! 653 */ 654 if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes), 655 "!p->p_addr")) 656 { 657#ifdef DEBUG 658 perror("getkval(uptes)"); 659#endif 660 /* we can't seem to get to it, so pretend it's swapped out */ 661 return(-1); 662 } 663 upage = (caddr_t) u; 664 pte = uptes; 665 for (nbytes = USERSIZE; nbytes > 0; nbytes -= NBPG) { 666 (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0); 667#ifdef DEBUG 668 perror("lseek(mem)"); 669#endif 670 n = MIN(nbytes, NBPG); 671 if (read(mem, upage, n) != n) { 672#ifdef DEBUG 673 perror("read(mem)"); 674#endif 675 /* we can't seem to get to it, so pretend it's swapped out */ 676 return(-1); 677 } 678 upage += n; 679 } 680 return(0); 681} 682 683/* 684 * check_nlist(nlst) - checks the nlist to see if any symbols were not 685 * found. For every symbol that was not found, a one-line 686 * message is printed to stderr. The routine returns the 687 * number of symbols NOT found. 688 */ 689 690int check_nlist(nlst) 691 692register struct nlist *nlst; 693 694{ 695 register int i; 696 697 /* check to see if we got ALL the symbols we requested */ 698 /* this will write one line to stderr for every symbol not found */ 699 700 i = 0; 701 while (nlst->n_name != NULL) 702 { 703 if (nlst->n_type == 0) 704 { 705 /* this one wasn't found */ 706 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name); 707 i = 1; 708 } 709 nlst++; 710 } 711 712 return(i); 713} 714 715 716/* 717 * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 718 * "offset" is the byte offset into the kernel for the desired value, 719 * "ptr" points to a buffer into which the value is retrieved, 720 * "size" is the size of the buffer (and the object to retrieve), 721 * "refstr" is a reference string used when printing error meessages, 722 * if "refstr" starts with a '!', then a failure on read will not 723 * be fatal (this may seem like a silly way to do things, but I 724 * really didn't want the overhead of another argument). 725 * 726 */ 727 728getkval(offset, ptr, size, refstr) 729 730unsigned long offset; 731int *ptr; 732int size; 733char *refstr; 734 735{ 736 if (lseek(kmem, (long)offset, L_SET) == -1) { 737 if (*refstr == '!') 738 refstr++; 739 (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM, 740 refstr, strerror(errno)); 741 quit(23); 742 } 743 if (read(kmem, (char *) ptr, size) == -1) { 744 if (*refstr == '!') 745 return(0); 746 else { 747 (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM, 748 refstr, strerror(errno)); 749 quit(23); 750 } 751 } 752 return(1); 753} 754 755/* comparison routine for qsort */ 756 757/* 758 * proc_compare - comparison function for "qsort" 759 * Compares the resource consumption of two processes using five 760 * distinct keys. The keys (in descending order of importance) are: 761 * percent cpu, cpu ticks, state, resident set size, total virtual 762 * memory usage. The process states are ordered as follows (from least 763 * to most important): WAIT, zombie, sleep, stop, start, run. The 764 * array declaration below maps a process state index into a number 765 * that reflects this ordering. 766 */ 767 768static unsigned char sorted_state[] = 769{ 770 0, /* not used */ 771 3, /* sleep */ 772 1, /* ABANDONED (WAIT) */ 773 6, /* run */ 774 5, /* start */ 775 2, /* zombie */ 776 4 /* stop */ 777}; 778 779proc_compare(pp1, pp2) 780 781struct proc **pp1; 782struct proc **pp2; 783 784{ 785 register struct proc *p1; 786 register struct proc *p2; 787 register int result; 788 register pctcpu lresult; 789 790 /* remove one level of indirection */ 791 p1 = *pp1; 792 p2 = *pp2; 793 794 /* compare percent cpu (pctcpu) */ 795 if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0) 796 { 797 /* use cpticks to break the tie */ 798 if ((result = p2->p_cpticks - p1->p_cpticks) == 0) 799 { 800 /* use process state to break the tie */ 801 if ((result = sorted_state[p2->p_stat] - 802 sorted_state[p1->p_stat]) == 0) 803 { 804 /* use priority to break the tie */ 805 if ((result = p2->p_pri - p1->p_pri) == 0) 806 { 807 /* use resident set size (rssize) to break the tie */ 808 if ((result = p2->p_rssize - p1->p_rssize) == 0) 809 { 810 /* use total memory to break the tie */ 811 result = PROCSIZE(p2) - PROCSIZE(p1); 812 } 813 } 814 } 815 } 816 } 817 else 818 { 819 result = lresult < 0 ? -1 : 1; 820 } 821 822 return(result); 823} 824 825 826void (*signal(sig, func))() 827 int sig; 828 void (*func)(); 829{ 830 struct sigvec osv, sv; 831 832 /* 833 * XXX: we should block the signal we are playing with, 834 * in case we get interrupted in here. 835 */ 836 if (sigvector(sig, NULL, &osv) == -1) 837 return BADSIG; 838 sv = osv; 839 sv.sv_handler = func; 840#ifdef SV_BSDSIG 841 sv.sv_flags |= SV_BSDSIG; 842#endif 843 if (sigvector(sig, &sv, NULL) == -1) 844 return BADSIG; 845 return osv.sv_handler; 846} 847 848int getpagesize() { return 1 << PGSHIFT; } 849 850int setpriority(a, b, c) { errno = ENOSYS; return -1; } 851 852/* 853 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 854 * the process does not exist. 855 * It is EXTREMLY IMPORTANT that this function work correctly. 856 * If top runs setuid root (as in SVR4), then this function 857 * is the only thing that stands in the way of a serious 858 * security problem. It validates requests for the "kill" 859 * and "renice" commands. 860 */ 861 862int proc_owner(pid) 863 864int pid; 865 866{ 867 register int cnt; 868 register struct proc **prefp; 869 register struct proc *pp; 870 871 prefp = pref; 872 cnt = pref_len; 873 while (--cnt >= 0) 874 { 875 if ((pp = *prefp++)->p_pid == (pid_t)pid) 876 { 877 return((int)pp->p_uid); 878 } 879 } 880 return(-1); 881} 882