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 79 struct 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 114 static 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 139 static 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 152 char *state_abbrev[] = 153 { 154 "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop" 155 }; 156 157 158 static int kmem, mem; 159 #ifdef DOSWAP 160 static int swap; 161 #endif 162 163 /* values that we stash away in _init and use in later routines */ 164 165 static double logcpu; 166 167 /* these are retrieved from the kernel in _init */ 168 169 static unsigned long proc; 170 static int nproc; 171 static long hz; 172 static load_avg ccpu; 173 static int ncpu = 0; 174 175 /* these are offsets obtained via nlist and used in the get_ functions */ 176 177 #ifndef hp9000s300 178 static unsigned long mpid_offset; 179 #endif 180 #ifdef hp9000s300 181 static struct pte *Usrptmap, *usrpt; 182 #endif 183 #ifdef hp9000s800 184 static int npids; 185 char *ubase; 186 #endif 187 static unsigned long avenrun_offset; 188 static unsigned long total_offset; 189 static unsigned long cp_time_offset; 190 191 /* these are for calculating cpu state percentages */ 192 193 static long cp_time[CPUSTATES]; 194 static long cp_old[CPUSTATES]; 195 static long cp_diff[CPUSTATES]; 196 197 /* these are for detailing the process states */ 198 199 int process_states[7]; 200 char *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 209 int cpu_states[9]; 210 #endif 211 #ifdef hp9000s800 212 int cpu_states[5]; 213 #endif 214 char *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 226 long memory_stats[8]; 227 char *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 234 static int bytes; 235 static int pref_len; 236 static struct proc *pbase; 237 static struct proc **pref; 238 239 /* these are for getting the memory statistics */ 240 241 static 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 */ 248 extern int errno; 249 extern char *sys_errlist[]; 250 251 long lseek(); 252 long time(); 253 254 machine_init(statics) 255 256 struct 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 371 char *format_header(uname_field) 372 373 register 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 387 void 388 get_system_info(si) 389 390 struct 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 451 static struct handle handle; 452 453 caddr_t get_process_info(si, sel, i) 454 455 struct system_info *si; 456 struct process_select *sel; 457 int 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 528 char fmt[MAX_COLS]; /* static area where result is built */ 529 530 char *format_next_process(handle, get_userid) 531 532 caddr_t handle; 533 char *(*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 619 getu(p, u) 620 621 register struct proc *p; 622 struct 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 690 int check_nlist(nlst) 691 692 register 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 728 getkval(offset, ptr, size, refstr) 729 730 unsigned long offset; 731 int *ptr; 732 int size; 733 char *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 768 static 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 779 proc_compare(pp1, pp2) 780 781 struct proc **pp1; 782 struct 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 826 void (*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 848 int getpagesize() { return 1 << PGSHIFT; } 849 850 int 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 862 int proc_owner(pid) 863 864 int 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