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