xref: /netbsd-src/external/bsd/top/dist/machine/m_hpux9.c (revision 10dd2532a5fc0a73e461275cb9fca28fc3013d32)
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 
107 struct 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 
146 static 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 
164 static 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 
176 char *state_abbrev[] =
177 {
178     "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
179 };
180 
181 
182 static int kmem;
183 
184 /* values that we stash away in _init and use in later routines */
185 
186 static double logcpu;
187 
188 /* these are retrieved from the kernel in _init */
189 
190 static unsigned long proc;
191 static          int  nproc;
192 static          long hz;
193 static load_avg  ccpu;
194 static          int  ncpu = 0;
195 
196 /* these are offsets obtained via nlist and used in the get_ functions */
197 static unsigned long mpid_offset;
198 static unsigned long avenrun_offset;
199 static unsigned long total_offset;
200 static unsigned long cp_time_offset;
201 
202 /* these are for calculating cpu state percentages */
203 
204 static long cp_time[CPUSTATES];
205 static long cp_old[CPUSTATES];
206 static long cp_diff[CPUSTATES];
207 
208 /* these are for detailing the process states */
209 
210 int process_states[7];
211 char *procstatenames[] = {
212     "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
213     " zombie, ", " stopped, ",
214     NULL
215 };
216 
217 /* these are for detailing the cpu states */
218 
219 int cpu_states[9];
220 char *cpustatenames[] = {
221     "usr", "nice", "sys", "idle", "", "", "", "intr", "ker",
222     NULL
223 };
224 
225 /* these are for detailing the memory statistics */
226 
227 long memory_stats[8];
228 char *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 
235 static int bytes;
236 static int pref_len;
237 static struct proc *pbase;
238 static struct proc **pref;
239 static struct pst_status *pst;
240 
241 /* these are for getting the memory statistics */
242 
243 static 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 */
250 extern int errno;
251 extern char *sys_errlist[];
252 
253 long lseek();
254 long time();
255 
256 machine_init(statics)
257 
258 struct 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 
format_header(uname_field)345 char *format_header(uname_field)
346 
347 register 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 
361 void
get_system_info(si)362 get_system_info(si)
363 
364 struct 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 
421 static struct handle handle;
422 
get_process_info(si,sel,i)423 caddr_t get_process_info(si, sel, i)
424 
425 struct system_info *si;
426 struct process_select *sel;
427 int 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 
513 char fmt[MAX_COLS];		/* static area where result is built */
514 
format_next_process(handle,get_userid)515 char *format_next_process(handle, get_userid)
516 
517 caddr_t handle;
518 char *(*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 
getu(p,u)608 getu(p, u)
609 
610 register struct proc *p;
611 struct 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 
check_nlist(nlst)651 int check_nlist(nlst)
652 
653 register 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 
getkval(offset,ptr,size,refstr)689 getkval(offset, ptr, size, refstr)
690 
691 unsigned long offset;
692 int *ptr;
693 int size;
694 char *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 
729 static 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 
740 proc_compare(pp1, pp2)
741 
742 struct proc **pp1;
743 struct 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 
787 void (*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 
getpagesize()809 int getpagesize() { return 1 << PGSHIFT; }
810 
setpriority(a,b,c)811 int 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 
proc_owner(pid)823 int proc_owner(pid)
824 
825 int 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