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