Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_hpux7.c
blobe6c5a90d90ba43ac22b6fec7c6dfecc6aed7ad3e
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.
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.
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.
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.
34 * top - a top users display for Unix
36 * SYNOPSIS: any hp9000 running hpux version 7 or earlier
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
45 * LIBS:
47 * AUTHOR: Christos Zoulas <christos@ee.cornell.edu>
50 #include "config.h"
51 #include <sys/types.h>
52 #include <sys/signal.h>
53 #include <sys/param.h>
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>
66 #include "top.h"
67 #include "machine.h"
68 #include "utils.h"
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
77 /* get_process_info passes back a handle. This is what it looks like: */
79 struct handle
81 struct proc **next_proc; /* points to next valid proc pointer */
82 int remaining; /* number of pointers remaining */
85 /* declarations for load_avg */
86 #include "loadavg.h"
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))))
92 /* what we consider to be process size: */
93 #define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
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
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 }
136 * These definitions control the format of the per-process area
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
144 #define Proc_format \
145 "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
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 */
152 char *state_abbrev[] =
154 "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
158 static int kmem, mem;
159 #ifdef DOSWAP
160 static int swap;
161 #endif
163 /* values that we stash away in _init and use in later routines */
165 static double logcpu;
167 /* these are retrieved from the kernel in _init */
169 static unsigned long proc;
170 static int nproc;
171 static long hz;
172 static load_avg ccpu;
173 static int ncpu = 0;
175 /* these are offsets obtained via nlist and used in the get_ functions */
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;
191 /* these are for calculating cpu state percentages */
193 static long cp_time[CPUSTATES];
194 static long cp_old[CPUSTATES];
195 static long cp_diff[CPUSTATES];
197 /* these are for detailing the process states */
199 int process_states[7];
200 char *procstatenames[] = {
201 "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
202 " zombie, ", " stopped, ",
203 NULL
206 /* these are for detailing the cpu states */
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
224 /* these are for detailing the memory statistics */
226 long memory_stats[8];
227 char *memorynames[] = {
228 "Real: ", "K active, ", "K total ", "Virtual: ", "K active, ",
229 "K total, ", "K free", NULL
232 /* these are for keeping track of the proc array */
234 static int bytes;
235 static int pref_len;
236 static struct proc *pbase;
237 static struct proc **pref;
239 /* these are for getting the memory statistics */
241 static int pageshift; /* log base 2 of the pagesize */
243 /* define pagetok in terms of pageshift */
245 #define pagetok(size) ((size) << pageshift)
247 /* useful externals */
248 extern int errno;
249 extern char *sys_errlist[];
251 long lseek();
252 long time();
254 machine_init(statics)
256 struct statics *statics;
259 register int i = 0;
260 register int pagesize;
262 if ((kmem = open(KMEM, O_RDONLY)) == -1) {
263 perror(KMEM);
264 return(-1);
266 if ((mem = open(MEM, O_RDONLY)) == -1) {
267 perror(MEM);
268 return(-1);
271 #ifdef DOSWAP
272 if ((swap = open(SWAP, O_RDONLY)) == -1) {
273 perror(SWAP);
274 return(-1);
276 #endif
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
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)
288 fprintf(stderr, "top: nlist failed\n");
289 return(-1);
292 /* make sure they were all found */
293 if (i > 0 && check_nlist(nlst) > 0)
295 return(-1);
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
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;
335 /* this is used in calculating WCPU -- calculate it ahead of time */
336 logcpu = log(loaddouble(ccpu));
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 *));
343 /* Just in case ... */
344 if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
346 fprintf(stderr, "top: can't allocate sufficient memory\n");
347 return(-1);
350 /* get the page size with "getpagesize" and calculate pageshift from it */
351 pagesize = getpagesize();
352 pageshift = 0;
353 while (pagesize > 1)
355 pageshift++;
356 pagesize >>= 1;
359 /* we only need the amount of log(2)1024 for our conversion */
360 pageshift -= LOG1024;
362 /* fill in the statics information */
363 statics->procstate_names = procstatenames;
364 statics->cpustate_names = cpustatenames;
365 statics->memory_names = memorynames;
367 /* all done! */
368 return(0);
371 char *format_header(uname_field)
373 register char *uname_field;
376 register char *ptr;
378 ptr = header + UNAME_START;
379 while (*uname_field != '\0')
381 *ptr++ = *uname_field++;
384 return(header);
387 void
388 get_system_info(si)
390 struct system_info *si;
393 load_avg avenrun[3];
394 long total;
396 /* get the cp_time array */
397 (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
398 "_cp_time");
400 /* get load average array */
401 (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
402 "_avenrun");
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
412 /* convert load averages to doubles */
414 register int i;
415 register double *infoloadp;
416 register load_avg *sysloadp;
418 infoloadp = si->load_avg;
419 sysloadp = avenrun;
420 for (i = 0; i < 3; i++)
422 *infoloadp++ = loaddouble(*sysloadp++);
426 /* convert cp_time counts to percentages */
427 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
429 /* sum memory statistics */
431 struct vmtotal total;
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);
446 /* set arrays and strings */
447 si->cpustates = cpu_states;
448 si->memory = memory_stats;
451 static struct handle handle;
453 caddr_t get_process_info(si, sel, i)
455 struct system_info *si;
456 struct process_select *sel;
457 int i;
460 register int i;
461 register int total_procs;
462 register int active_procs;
463 register struct proc **prefp;
464 register struct proc *pp;
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;
472 /* read all the proc structures in one fell swoop */
473 (void) getkval(proc, (int *)pbase, bytes, "proc array");
475 /* get a pointer to the states summary array */
476 si->procstates = process_states;
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;
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++)
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.
497 if (pp->p_stat != 0 &&
498 (show_system || ((pp->p_flag & SSYS) == 0)))
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))
506 *prefp++ = pp;
507 active_procs++;
512 /* if requested, sort the "interesting" processes */
513 if (compare != NULL)
515 qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compare);
518 /* remember active and total counts */
519 si->p_total = total_procs;
520 si->p_active = pref_len = active_procs;
522 /* pass back a handle */
523 handle.next_proc = pref;
524 handle.remaining = active_procs;
525 return((caddr_t)&handle);
528 char fmt[MAX_COLS]; /* static area where result is built */
530 char *format_next_process(handle, get_userid)
532 caddr_t handle;
533 char *(*get_userid)();
536 register struct proc *pp;
537 register long cputime;
538 register double pct;
539 int where;
540 struct user u;
541 struct handle *hp;
543 /* find and remember the next proc structure */
544 hp = (struct handle *)handle;
545 pp = *(hp->next_proc++);
546 hp->remaining--;
549 /* get the process's user struct and set cputime */
550 where = getu(pp, &u);
551 if (where == -1)
553 (void) strcpy(u.u_comm, "<swapped>");
554 cputime = 0;
556 else
560 /* set u_comm for system processes */
561 if (u.u_comm[0] == '\0')
563 if (pp->p_pid == 0)
565 (void) strcpy(u.u_comm, "Swapper");
567 else if (pp->p_pid == 2)
569 (void) strcpy(u.u_comm, "Pager");
572 if (where == 1) {
574 * Print swapped processes as <pname>
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';
585 cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
588 /* calculate the base for cpu percentages */
589 pct = pctdouble(pp->p_pctcpu);
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));
606 /* return the result */
607 return(fmt);
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).
617 #define USERSIZE sizeof(struct user)
619 getu(p, u)
621 register struct proc *p;
622 struct user *u;
625 struct pte uptes[UPAGES];
626 register caddr_t upage;
627 register struct pte *pte;
628 register nbytes, n;
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.
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);
641 if (read(swap, (char *) u, USERSIZE) != USERSIZE) {
642 perror("read(swap)");
643 return(-1);
645 return (1);
646 #else
647 return(-1);
648 #endif
652 * Process is currently in memory, we hope!
654 if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes),
655 "!p->p_addr"))
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);
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);
678 upage += n;
680 return(0);
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.
690 int check_nlist(nlst)
692 register struct nlist *nlst;
695 register int i;
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 */
700 i = 0;
701 while (nlst->n_name != NULL)
703 if (nlst->n_type == 0)
705 /* this one wasn't found */
706 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
707 i = 1;
709 nlst++;
712 return(i);
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).
728 getkval(offset, ptr, size, refstr)
730 unsigned long offset;
731 int *ptr;
732 int size;
733 char *refstr;
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);
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);
752 return(1);
755 /* comparison routine for qsort */
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.
768 static unsigned char sorted_state[] =
770 0, /* not used */
771 3, /* sleep */
772 1, /* ABANDONED (WAIT) */
773 6, /* run */
774 5, /* start */
775 2, /* zombie */
776 4 /* stop */
779 proc_compare(pp1, pp2)
781 struct proc **pp1;
782 struct proc **pp2;
785 register struct proc *p1;
786 register struct proc *p2;
787 register int result;
788 register pctcpu lresult;
790 /* remove one level of indirection */
791 p1 = *pp1;
792 p2 = *pp2;
794 /* compare percent cpu (pctcpu) */
795 if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
797 /* use cpticks to break the tie */
798 if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
800 /* use process state to break the tie */
801 if ((result = sorted_state[p2->p_stat] -
802 sorted_state[p1->p_stat]) == 0)
804 /* use priority to break the tie */
805 if ((result = p2->p_pri - p1->p_pri) == 0)
807 /* use resident set size (rssize) to break the tie */
808 if ((result = p2->p_rssize - p1->p_rssize) == 0)
810 /* use total memory to break the tie */
811 result = PROCSIZE(p2) - PROCSIZE(p1);
817 else
819 result = lresult < 0 ? -1 : 1;
822 return(result);
826 void (*signal(sig, func))()
827 int sig;
828 void (*func)();
830 struct sigvec osv, sv;
833 * XXX: we should block the signal we are playing with,
834 * in case we get interrupted in here.
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;
848 int getpagesize() { return 1 << PGSHIFT; }
850 int setpriority(a, b, c) { errno = ENOSYS; return -1; }
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.
862 int proc_owner(pid)
864 int pid;
867 register int cnt;
868 register struct proc **prefp;
869 register struct proc *pp;
871 prefp = pref;
872 cnt = pref_len;
873 while (--cnt >= 0)
875 if ((pp = *prefp++)->p_pid == (pid_t)pid)
877 return((int)pp->p_uid);
880 return(-1);