xref: /netbsd/external/bsd/top/dist/machine/m_hpux8.c (revision 10dd2532)
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 
94 struct 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 
133 static 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 
151 static 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 
164 char *state_abbrev[] =
165 {
166     "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
167 };
168 
169 
170 static int kmem;
171 
172 /* values that we stash away in _init and use in later routines */
173 
174 static double logcpu;
175 
176 /* these are retrieved from the kernel in _init */
177 
178 static unsigned long proc;
179 static          int  nproc;
180 static          long hz;
181 static load_avg  ccpu;
182 static          int  ncpu = 0;
183 
184 /* these are offsets obtained via nlist and used in the get_ functions */
185 static unsigned long mpid_offset;
186 static unsigned long avenrun_offset;
187 static unsigned long total_offset;
188 static unsigned long cp_time_offset;
189 
190 /* these are for calculating cpu state percentages */
191 
192 static long cp_time[CPUSTATES];
193 static long cp_old[CPUSTATES];
194 static long cp_diff[CPUSTATES];
195 
196 /* these are for detailing the process states */
197 
198 int process_states[7];
199 char *procstatenames[] = {
200     "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
201     " zombie, ", " stopped, ",
202     NULL
203 };
204 
205 /* these are for detailing the cpu states */
206 
207 int cpu_states[9];
208 char *cpustatenames[] = {
209     "usr", "nice", "sys", "idle", "", "", "", "intr", "ker",
210     NULL
211 };
212 
213 /* these are for detailing the memory statistics */
214 
215 long memory_stats[8];
216 char *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 
223 static int bytes;
224 static int pref_len;
225 static struct proc *pbase;
226 static struct proc **pref;
227 static struct pst_status *pst;
228 
229 /* these are for getting the memory statistics */
230 
231 static 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 */
238 extern int errno;
239 extern char *sys_errlist[];
240 
241 long lseek();
242 long time();
243 
244 machine_init(statics)
245 
246 struct 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 
format_header(uname_field)333 char *format_header(uname_field)
334 
335 register 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 
349 void
get_system_info(si)350 get_system_info(si)
351 
352 struct 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 
409 static struct handle handle;
410 
get_process_info(si,sel,i)411 caddr_t get_process_info(si, sel, i)
412 
413 struct system_info *si;
414 struct process_select *sel;
415 int 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 
495 char fmt[MAX_COLS];		/* static area where result is built */
496 
format_next_process(handle,get_userid)497 char *format_next_process(handle, get_userid)
498 
499 caddr_t handle;
500 char *(*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 
getu(p,u)585 getu(p, u)
586 
587 register struct proc *p;
588 struct 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 
check_nlist(nlst)628 int check_nlist(nlst)
629 
630 register 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 
getkval(offset,ptr,size,refstr)666 getkval(offset, ptr, size, refstr)
667 
668 unsigned long offset;
669 int *ptr;
670 int size;
671 char *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 
706 static 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 
717 proc_compare(pp1, pp2)
718 
719 struct proc **pp1;
720 struct 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 
764 void (*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 
getpagesize()786 int getpagesize() { return 1 << PGSHIFT; }
787 
setpriority(a,b,c)788 int 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 
proc_owner(pid)800 int proc_owner(pid)
801 
802 int 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