xref: /minix/external/bsd/top/dist/machine/m_hpux7.c (revision b89261ba)
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 7 or earlier
37  *
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
44  *
45  * LIBS:
46  *
47  * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
48  */
49 
50 #include "config.h"
51 #include <sys/types.h>
52 #include <sys/signal.h>
53 #include <sys/param.h>
54 
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>
65 
66 #include "top.h"
67 #include "machine.h"
68 #include "utils.h"
69 
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
76 
77 /* get_process_info passes back a handle.  This is what it looks like: */
78 
79 struct handle
80 {
81     struct proc **next_proc;	/* points to next valid proc pointer */
82     int remaining;		/* number of pointers remaining */
83 };
84 
85 /* declarations for load_avg */
86 #include "loadavg.h"
87 
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))))
91 
92 /* what we consider to be process size: */
93 #define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
94 
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
113 
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 }
133 };
134 
135 /*
136  *  These definitions control the format of the per-process area
137  */
138 
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
143 
144 #define Proc_format \
145 	"%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
146 
147 
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 */
151 
152 char *state_abbrev[] =
153 {
154     "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
155 };
156 
157 
158 static int kmem, mem;
159 #ifdef DOSWAP
160 static int swap;
161 #endif
162 
163 /* values that we stash away in _init and use in later routines */
164 
165 static double logcpu;
166 
167 /* these are retrieved from the kernel in _init */
168 
169 static unsigned long proc;
170 static          int  nproc;
171 static          long hz;
172 static load_avg  ccpu;
173 static          int  ncpu = 0;
174 
175 /* these are offsets obtained via nlist and used in the get_ functions */
176 
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;
190 
191 /* these are for calculating cpu state percentages */
192 
193 static long cp_time[CPUSTATES];
194 static long cp_old[CPUSTATES];
195 static long cp_diff[CPUSTATES];
196 
197 /* these are for detailing the process states */
198 
199 int process_states[7];
200 char *procstatenames[] = {
201     "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
202     " zombie, ", " stopped, ",
203     NULL
204 };
205 
206 /* these are for detailing the cpu states */
207 
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
222 };
223 
224 /* these are for detailing the memory statistics */
225 
226 long memory_stats[8];
227 char *memorynames[] = {
228     "Real: ", "K active, ", "K total  ", "Virtual: ", "K active, ",
229     "K total, ", "K free", NULL
230 };
231 
232 /* these are for keeping track of the proc array */
233 
234 static int bytes;
235 static int pref_len;
236 static struct proc *pbase;
237 static struct proc **pref;
238 
239 /* these are for getting the memory statistics */
240 
241 static int pageshift;		/* log base 2 of the pagesize */
242 
243 /* define pagetok in terms of pageshift */
244 
245 #define pagetok(size) ((size) << pageshift)
246 
247 /* useful externals */
248 extern int errno;
249 extern char *sys_errlist[];
250 
251 long lseek();
252 long time();
253 
254 machine_init(statics)
255 
256 struct statics *statics;
257 
258 {
259     register int i = 0;
260     register int pagesize;
261 
262     if ((kmem = open(KMEM, O_RDONLY)) == -1) {
263 	perror(KMEM);
264 	return(-1);
265     }
266     if ((mem = open(MEM, O_RDONLY)) == -1) {
267 	perror(MEM);
268 	return(-1);
269     }
270 
271 #ifdef DOSWAP
272     if ((swap = open(SWAP, O_RDONLY)) == -1) {
273 	perror(SWAP);
274 	return(-1);
275     }
276 #endif
277 
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
283 
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)
287     {
288 	fprintf(stderr, "top: nlist failed\n");
289 	return(-1);
290     }
291 
292     /* make sure they were all found */
293     if (i > 0 && check_nlist(nlst) > 0)
294     {
295 	return(-1);
296     }
297 
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
315 
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;
334 
335     /* this is used in calculating WCPU -- calculate it ahead of time */
336     logcpu = log(loaddouble(ccpu));
337 
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 *));
342 
343     /* Just in case ... */
344     if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
345     {
346 	fprintf(stderr, "top: can't allocate sufficient memory\n");
347 	return(-1);
348     }
349 
350     /* get the page size with "getpagesize" and calculate pageshift from it */
351     pagesize = getpagesize();
352     pageshift = 0;
353     while (pagesize > 1)
354     {
355 	pageshift++;
356 	pagesize >>= 1;
357     }
358 
359     /* we only need the amount of log(2)1024 for our conversion */
360     pageshift -= LOG1024;
361 
362     /* fill in the statics information */
363     statics->procstate_names = procstatenames;
364     statics->cpustate_names = cpustatenames;
365     statics->memory_names = memorynames;
366 
367     /* all done! */
368     return(0);
369 }
370 
format_header(uname_field)371 char *format_header(uname_field)
372 
373 register char *uname_field;
374 
375 {
376     register char *ptr;
377 
378     ptr = header + UNAME_START;
379     while (*uname_field != '\0')
380     {
381 	*ptr++ = *uname_field++;
382     }
383 
384     return(header);
385 }
386 
387 void
get_system_info(si)388 get_system_info(si)
389 
390 struct system_info *si;
391 
392 {
393     load_avg avenrun[3];
394     long total;
395 
396     /* get the cp_time array */
397     (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
398 		   "_cp_time");
399 
400     /* get load average array */
401     (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
402 		   "_avenrun");
403 
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
411 
412     /* convert load averages to doubles */
413     {
414 	register int i;
415 	register double *infoloadp;
416 	register load_avg *sysloadp;
417 
418 	infoloadp = si->load_avg;
419 	sysloadp = avenrun;
420 	for (i = 0; i < 3; i++)
421 	{
422 	    *infoloadp++ = loaddouble(*sysloadp++);
423 	}
424     }
425 
426     /* convert cp_time counts to percentages */
427     total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
428 
429     /* sum memory statistics */
430     {
431 	struct vmtotal total;
432 
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);
444     }
445 
446     /* set arrays and strings */
447     si->cpustates = cpu_states;
448     si->memory = memory_stats;
449 }
450 
451 static struct handle handle;
452 
get_process_info(si,sel,i)453 caddr_t get_process_info(si, sel, i)
454 
455 struct system_info *si;
456 struct process_select *sel;
457 int i;
458 
459 {
460     register int i;
461     register int total_procs;
462     register int active_procs;
463     register struct proc **prefp;
464     register struct proc *pp;
465 
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;
471 
472     /* read all the proc structures in one fell swoop */
473     (void) getkval(proc, (int *)pbase, bytes, "proc array");
474 
475     /* get a pointer to the states summary array */
476     si->procstates = process_states;
477 
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;
483 
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++)
490     {
491 	/*
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.
496 	 */
497 	if (pp->p_stat != 0 &&
498 	    (show_system || ((pp->p_flag & SSYS) == 0)))
499 	{
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))
505 	    {
506 		*prefp++ = pp;
507 		active_procs++;
508 	    }
509 	}
510     }
511 
512     /* if requested, sort the "interesting" processes */
513     if (compare != NULL)
514     {
515 	qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compare);
516     }
517 
518     /* remember active and total counts */
519     si->p_total = total_procs;
520     si->p_active = pref_len = active_procs;
521 
522     /* pass back a handle */
523     handle.next_proc = pref;
524     handle.remaining = active_procs;
525     return((caddr_t)&handle);
526 }
527 
528 char fmt[MAX_COLS];		/* static area where result is built */
529 
format_next_process(handle,get_userid)530 char *format_next_process(handle, get_userid)
531 
532 caddr_t handle;
533 char *(*get_userid)();
534 
535 {
536     register struct proc *pp;
537     register long cputime;
538     register double pct;
539     int where;
540     struct user u;
541     struct handle *hp;
542 
543     /* find and remember the next proc structure */
544     hp = (struct handle *)handle;
545     pp = *(hp->next_proc++);
546     hp->remaining--;
547 
548 
549     /* get the process's user struct and set cputime */
550     where = getu(pp, &u);
551     if (where == -1)
552     {
553 	(void) strcpy(u.u_comm, "<swapped>");
554 	cputime = 0;
555     }
556     else
557     {
558 
559 
560 	/* set u_comm for system processes */
561 	if (u.u_comm[0] == '\0')
562 	{
563 	    if (pp->p_pid == 0)
564 	    {
565 		(void) strcpy(u.u_comm, "Swapper");
566 	    }
567 	    else if (pp->p_pid == 2)
568 	    {
569 		(void) strcpy(u.u_comm, "Pager");
570 	    }
571 	}
572 	if (where == 1) {
573 	    /*
574 	     * Print swapped processes as <pname>
575 	     */
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';
583 	}
584 
585 	cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
586     }
587 
588     /* calculate the base for cpu percentages */
589     pct = pctdouble(pp->p_pctcpu);
590 
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));
605 
606     /* return the result */
607     return(fmt);
608 }
609 
610 /*
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).
615  */
616 
617 #define USERSIZE sizeof(struct user)
618 
getu(p,u)619 getu(p, u)
620 
621 register struct proc *p;
622 struct user *u;
623 
624 {
625     struct pte uptes[UPAGES];
626     register caddr_t upage;
627     register struct pte *pte;
628     register nbytes, n;
629 
630     /*
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.
634      */
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);
640 	}
641 	if (read(swap, (char *) u, USERSIZE) != USERSIZE)  {
642 	    perror("read(swap)");
643 	    return(-1);
644 	}
645 	return (1);
646 #else
647 	return(-1);
648 #endif
649     }
650 
651     /*
652      *  Process is currently in memory, we hope!
653      */
654     if (!getkval((unsigned long)p->p_addr, (int *)uptes, sizeof(uptes),
655                 "!p->p_addr"))
656     {
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);
662     }
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);
677 	}
678 	upage += n;
679     }
680     return(0);
681 }
682 
683 /*
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.
688  */
689 
check_nlist(nlst)690 int check_nlist(nlst)
691 
692 register struct nlist *nlst;
693 
694 {
695     register int i;
696 
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 */
699 
700     i = 0;
701     while (nlst->n_name != NULL)
702     {
703 	if (nlst->n_type == 0)
704 	{
705 	    /* this one wasn't found */
706 	    fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
707 	    i = 1;
708 	}
709 	nlst++;
710     }
711 
712     return(i);
713 }
714 
715 
716 /*
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).
725  *
726  */
727 
getkval(offset,ptr,size,refstr)728 getkval(offset, ptr, size, refstr)
729 
730 unsigned long offset;
731 int *ptr;
732 int size;
733 char *refstr;
734 
735 {
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);
742     }
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);
750         }
751     }
752     return(1);
753 }
754 
755 /* comparison routine for qsort */
756 
757 /*
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.
766  */
767 
768 static unsigned char sorted_state[] =
769 {
770     0,	/* not used		*/
771     3,	/* sleep		*/
772     1,	/* ABANDONED (WAIT)	*/
773     6,	/* run			*/
774     5,	/* start		*/
775     2,	/* zombie		*/
776     4	/* stop			*/
777 };
778 
779 proc_compare(pp1, pp2)
780 
781 struct proc **pp1;
782 struct proc **pp2;
783 
784 {
785     register struct proc *p1;
786     register struct proc *p2;
787     register int result;
788     register pctcpu lresult;
789 
790     /* remove one level of indirection */
791     p1 = *pp1;
792     p2 = *pp2;
793 
794     /* compare percent cpu (pctcpu) */
795     if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
796     {
797 	/* use cpticks to break the tie */
798 	if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
799 	{
800 	    /* use process state to break the tie */
801 	    if ((result = sorted_state[p2->p_stat] -
802 			  sorted_state[p1->p_stat])  == 0)
803 	    {
804 		/* use priority to break the tie */
805 		if ((result = p2->p_pri - p1->p_pri) == 0)
806 		{
807 		    /* use resident set size (rssize) to break the tie */
808 		    if ((result = p2->p_rssize - p1->p_rssize) == 0)
809 		    {
810 			/* use total memory to break the tie */
811 			result = PROCSIZE(p2) - PROCSIZE(p1);
812 		    }
813 		}
814 	    }
815 	}
816     }
817     else
818     {
819 	result = lresult < 0 ? -1 : 1;
820     }
821 
822     return(result);
823 }
824 
825 
826 void (*signal(sig, func))()
827     int sig;
828     void (*func)();
829 {
830     struct sigvec osv, sv;
831 
832     /*
833      * XXX: we should block the signal we are playing with,
834      *	    in case we get interrupted in here.
835      */
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;
846 }
847 
getpagesize()848 int getpagesize() { return 1 << PGSHIFT; }
849 
setpriority(a,b,c)850 int setpriority(a, b, c) { errno = ENOSYS; return -1; }
851 
852 /*
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.
860  */
861 
proc_owner(pid)862 int proc_owner(pid)
863 
864 int pid;
865 
866 {
867     register int cnt;
868     register struct proc **prefp;
869     register struct proc *pp;
870 
871     prefp = pref;
872     cnt = pref_len;
873     while (--cnt >= 0)
874     {
875 	if ((pp = *prefp++)->p_pid == (pid_t)pid)
876 	{
877 	    return((int)pp->p_uid);
878 	}
879     }
880     return(-1);
881 }
882