xref: /netbsd-src/external/bsd/top/dist/machine/m_sco5.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:  SCO UNIX OpenServer5
37  *
38  * DESCRIPTION:
39  * This is the machine-dependent module for SCO OpenServer5.
40  * Originally written for BSD4.3 system by Christos Zoulas.
41  * Modified to m_sco.c (3.2v4.2)  by Gregory Shilin <shilin@onyx.co.il>
42  * Modified to m_sco5.c (3.2v5.*) by Mike Hopkirk <hops@sco.com>
43  * Works for:
44  * SCO UNIX 3.2v5.*
45  *
46  * CFLAGS: -DHAVE_GETOPT -DORDER
47  *
48  * AUTHOR: Mike Hopkirk (hops@sco.com)
49  * hops 10-Jul-98 - added sort fields
50  *      17-Jul-98 - add philiph's chopped cmd string support
51  *                    (define NO_COMMAND_ARGS to enable )
52  *      09-Dec-98 - provide RSS calculation
53  *      15-Mar-2000 - Fix broken lines and cleanup sysinfo access w macros
54  */
55 
56 #include <sys/types.h>
57 #include <sys/param.h>
58 
59 #include <stdio.h>
60 #include <unistd.h>
61 #include <fcntl.h>
62 #include <nlist.h>
63 #include <math.h>
64 #include <signal.h>
65 #include <string.h>
66 
67 #include <sys/dir.h>
68 #include <sys/immu.h>
69 #include <sys/region.h>
70 #include <sys/proc.h>
71 #include <sys/user.h>
72 #include <sys/sysinfo.h>
73 #include <sys/systm.h>
74 #include <sys/sysmacros.h>
75 #include <sys/var.h>
76 #include <sys/sysi86.h>
77 
78 #include "top.h"
79 #include "machine.h"
80 #include "utils.h"
81 #include "loadavg.h"
82 
83 /*
84 typedef unsigned long  ulong;
85 typedef unsigned int   uint;
86 typedef unsigned short ushort;
87 */
88 typedef unsigned char  uchar;
89 
90 #define VMUNIX  "/unix"
91 #define KMEM    "/dev/kmem"
92 #define MEM     "/dev/mem"
93 
94 #define SI_ACTIVE(p)   p->p_active
95 #define SI_TOTAL(p)    p->p_total
96 
97 /* get_process_info passes back a handle. This is what it looks like: */
98 struct handle {
99    struct proc **next_proc; /* points to next valid proc pointer */
100    int           remaining; /* number of pointers remaining */
101 };
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 #define bytetok(bytes) ((bytes) >> 10)
108 
109 /* what we consider to be process size: */
110 #define PROCSIZE(up) bytetok(ctob((up)->u_tsize + (up)->u_dsize+(up)->u_ssize))
111 
112 /* definitions for indices in the nlist array */
113 #define X_V             0  /* System configuration information */
114 #define X_PROC          1  /* process tables */
115 #define X_FREEMEM       2  /* current free memory */
116 #define X_AVAILRMEM     3  /* available resident (not swappable) mem in pages
117 */
118 #define X_AVAILSMEM     4  /* available swappable memory in pages */
119 #define X_MAXMEM        5  /* maximum available free memory in clicks */
120 #define X_PHYSMEM       6  /* physical memory in clicks */
121 #define X_NSWAP         7  /* size of swap space in blocks */
122 #define X_HZ            8  /* ticks/second of the clock */
123 #define X_MPID          9  /* last process id */
124 #define X_SYSINFO       10 /* system information (cpu states) */
125 #define X_CUR_CPU       11
126 
127 static struct nlist nlst[] = {
128    { "v" },             /* 0 */
129    { "proc" },          /* 1 */
130    { "freemem" },       /* 2 */
131    { "availrmem" },     /* 3 */
132    { "availsmem" },     /* 4 */
133    { "maxmem" },        /* 5 */
134    { "physmem" },       /* 6 */
135    { "nswap" },         /* 7 */
136    { "Hz" },            /* 8 */
137    { "mpid" },          /* 9 */
138    { "sysinfo" },       /* 10 */
139    { "cur_cpu" },       /* 11 */
140    { NULL }
141 };
142 
143 /*
144  *  These definitions control the format of the per-process area
145  */
146 
147 static char header[] =
148   "  PID X        PRI NICE   SIZE   RES  STATE   TIME  COMMAND";
149 /* 0123456   -- field to fill in starts at header+6 */
150 #define UNAME_START 6
151 
152 #define Proc_format \
153 	"%5d %-8.8s %3d %4d  %5s %5dK %-5s %6s  %.28s"
154 
155 static int kmem, mem;
156 
157 static double logcpu;
158 
159 /* these are retrieved from the kernel in _init */
160 static int   Hz;
161 static struct var   v;
162 static ulong proca;
163 static load_avg  cur_cpu;
164 
165 /* these are for detailing the process states */
166 int process_states[8];
167 char *procstatenames[] = {
168     "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
169     " created, ", " onproc, ", " xswapped, ",
170     NULL
171 };
172 
173 /* process state names for the "STATE" column of the display */
174 char *state_abbrev[] = {
175    "", "sleep", "run", "zomb", "stop", "create", "onpr", "swap"
176 };
177 
178 /* these are for calculating cpu state percentages */
179 #define CPUSTATES       5    /* definition from struct sysinfo */
180 static time_t cp_time[CPUSTATES];
181 static time_t cp_old[CPUSTATES];
182 static time_t cp_diff[CPUSTATES];
183 
184 /* these are for detailing the cpu states */
185 int cpu_states[CPUSTATES];
186 char *cpustatenames[] = {
187     "idle", "user", "system", "wait", "sxbrk",
188     NULL
189 };
190 
191 /* these are for detailing the memory statistics */
192 unsigned long memory_stats[6];
193 char *memorynames[] = {
194     "K phys, ", "K max, ", "K free, ", "K lck, ", "K unlck, ",
195     "K swap,", NULL
196 };
197 
198 /* these are for keeping track of the proc array */
199 static int bytes;
200 static int pref_len;
201 static struct proc *pbase;
202 static struct proc **pref;
203 
204 /* forward definitions for comparison functions */
205 int proc_compare();
206 int compare_cpu();
207 int compare_size();
208 int compare_time();
209 
210 int (*proc_compares[])() = {
211     proc_compare,   /* state, pri, time, size */
212     compare_cpu,    /* cpu, time, state, pri, size */
213     compare_size,   /* size, cpu, time, state pri  */
214     compare_time,   /* time, cpu, state, pri, size */
215 /* compare_res,     /* res,  cpu, time, state pri  */
216     NULL };
217 
218 /* these are names given to allowed sorting orders -- first is default */
219 char *ordernames[]={"state", "cpu", "size", "time", NULL}; /*hops*/
220 
221 /* useful externals */
222 extern int errno;
223 extern char *sys_errlist[];
224 
225 long time();
226 long percentages();
227 
228 int
machine_init(struct statics * statics)229 machine_init(struct statics *statics)
230 
231 {
232 ulong ptr;
233 
234    if ((kmem = open(KMEM, O_RDONLY)) == -1) {
235       perror(KMEM);
236       return -1;
237    }
238    if ((mem = open(MEM, O_RDONLY)) == -1) {
239       perror(MEM);
240       return -1;
241    }
242 
243    /* get the list of symbols we want to access in the kernel */
244    if (nlist(VMUNIX, nlst) == -1) {
245       fprintf(stderr, "top: nlist failed\n");
246       return -1;
247    }
248    /* make sure they were all found */
249    /*ZZ
250    if (check_nlist(nlst) > 0)
251       return -1;
252    */
253 
254    proca = nlst[X_PROC].n_value;
255 
256    /* get the symbol values out of kmem */
257    (void) getkval(nlst[X_CUR_CPU].n_value, (int *)(&cur_cpu), sizeof(cur_cpu),
258 		  nlst[X_CUR_CPU].n_name);
259    (void) getkval(nlst[X_HZ].n_value,      (int *)(&Hz),      sizeof(Hz),
260 		  nlst[X_HZ].n_name);
261    (void) getkval(nlst[X_V].n_value,       (int *)(&v),       sizeof(v),
262 		  nlst[X_V].n_name);
263 
264    /* this is used in calculating WCPU -- calculate it ahead of time */
265    logcpu = log(fabs(loaddouble(cur_cpu)));
266 
267    /* allocate space for proc structure array and array of pointers */
268    bytes = v.v_proc * sizeof(struct proc);
269    pbase = (struct proc *)malloc(bytes);
270    pref  = (struct proc **)malloc(v.v_proc * sizeof(struct proc *));
271    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL) {
272       fprintf(stderr, "top: cannot allocate sufficient memory\n");
273       return -1;
274    }
275 
276    /* fill in the statics information */
277    statics->procstate_names = procstatenames;
278    statics->cpustate_names = cpustatenames;
279    statics->memory_names = memorynames;
280    statics->order_names = ordernames ;  /* hops */
281 
282    return 0;
283 }
284 
285 char *
format_header(register char * uname_field)286 format_header(register char *uname_field)
287 
288 {
289     register char *ptr;
290 
291     ptr = header + UNAME_START;
292     while (*uname_field != '\0')
293     {
294 	*ptr++ = *uname_field++;
295     }
296 
297     return(header);
298 }
299 
300 
301 /* philiph - get run ave fm /dev/table info */
302 static int
tab_avenrun(double runave[])303 tab_avenrun(double runave[])
304 {
305    FILE *fp = fopen("/dev/table/avenrun", "r");
306    int i;
307 
308    for (i=0; i<3; i++)
309       runave[i] = -1.0;
310 
311    if (fp==NULL)
312       return -1;
313    else
314    {
315       short rawave[3];
316 
317 	if (fread(rawave, sizeof(short), 3, fp) !=3 )
318 	{
319 	    fclose(fp);
320 	    return -1;
321 	}
322 	else
323 	{
324 	    int i;
325 
326 	    for (i=0; i<3; i++)
327 		runave[i] = (double) (rawave[i] / 256.0);
328 
329 	    fclose(fp);
330 	    return 0;
331 	}
332     }
333 }
334 
335 struct pregion *
get_pregion(void * ptr)336 get_pregion(void *ptr)
337 {
338     static struct pregion preg;
339     long addr = (long)ptr;
340 
341    (void) getkval(addr , (struct pregion *)(&preg),
342 		    sizeof(struct pregion), "pregion" );
343     return &preg;
344 }
345 
346 struct region *
get_region(void * ptr)347 get_region(void *ptr)
348 {
349     static struct region reg;
350     long addr = (long)ptr;
351 
352    (void) getkval( addr , (struct region *)(&reg),
353 		    sizeof(struct region), "region" );
354     return &reg;
355 }
356 
357 static unsigned char shareable[RT_VM86 + 1];     /* 1 if shareable */
358 
359 /*
360  * sum private referenced pages,
361  * treat shared pages depending on value of TREAT_SHARABLE_PAGES macro
362  *      undefined : ignore (don't account for - default)
363  *      1:  divide among # of references
364  *      2:  accumulate as if private
365  */
366 /* #define TREAT_SHAREABLE_PAGES 1 */
367 static long
proc_residentsize(struct proc * pp)368 proc_residentsize(struct proc *pp)
369 {
370     struct pregion *prp;
371     struct region *rp;
372     long rtot = 0;
373     long stot = 0;
374     long s1tot = 0;
375 
376     /* init shareable region array */
377     if (shareable[RT_STEXT] == 0 )
378 	shareable[RT_STEXT] = shareable[RT_SHMEM] = shareable[RT_MAPFILE] = 1
379 	;
380 
381     prp = pp->p_region;
382 
383     if ( prp == 0)
384 	return 0;
385 
386     for( ; prp && (prp = get_pregion((void *)(prp))) &&
387 	   prp->p_reg && (rp = get_region((void*)(prp->p_reg)));
388 	   prp = prp->p_next)
389     {
390 	if (shareable[rp->r_type] )     /* account for shared pgs separately
391 	*/
392 	{
393 	    stot  += (rp->r_nvalid / rp->r_refcnt);
394 	    s1tot += rp->r_nvalid;
395 	}
396 	else
397 	    rtot += rp->r_nvalid;
398 
399     }
400 #if defined(TREAT_SHAREABLE_PAGES) && TREAT_SHAREABLE_PAGES == 1
401 	rtot += stot;           /* accumulate and spread over users */
402 #endif
403 
404 #if defined(TREAT_SHAREABLE_PAGES) && TREAT_SHAREABLE_PAGES == 1
405 	rtot += s1tot;          /* accumulate as if private */
406 #endif
407 
408     return rtot * NBPP/1024; ;
409 }
410 
411 void
get_system_info(struct system_info * si)412 get_system_info(struct system_info *si)
413 
414 {
415 long total;
416 
417    /* get process id of the last process */
418    (void) getkval(nlst[X_MPID].n_value,  &(si->last_pid),
419    sizeof(si->last_pid),
420 		  nlst[X_MPID].n_name);
421    /* get the cp_time array */
422    (void) getkval(nlst[X_SYSINFO].n_value, (int *)cp_time, sizeof(cp_time),
423 		  nlst[X_SYSINFO].n_name);
424 
425    /* convert cp_time counts to persentages */
426    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
427 
428    /* sum memory statistics */
429    (void) getkval(nlst[X_PHYSMEM].n_value, &memory_stats[0],
430 		  sizeof(memory_stats[0]), nlst[X_PHYSMEM].n_name);
431    (void) getkval(nlst[X_MAXMEM].n_value, &memory_stats[1],
432 		  sizeof(memory_stats[1]), nlst[X_MAXMEM].n_name);
433    (void) getkval(nlst[X_FREEMEM].n_value, &memory_stats[2],
434 		  sizeof(memory_stats[2]), nlst[X_FREEMEM].n_name);
435    (void) getkval(nlst[X_AVAILRMEM].n_value, &memory_stats[3],
436 		  sizeof(memory_stats[3]), nlst[X_AVAILRMEM].n_name);
437    (void) getkval(nlst[X_AVAILSMEM].n_value, &memory_stats[4],
438 		  sizeof(memory_stats[4]), nlst[X_AVAILSMEM].n_name);
439    (void) getkval(nlst[X_NSWAP].n_value, &memory_stats[5],
440 		  sizeof(memory_stats[5]), nlst[X_NSWAP].n_name);
441    memory_stats[0] = bytetok(ctob(memory_stats[0]));    /* clicks -> bytes
442    */
443    memory_stats[1] = bytetok(ctob(memory_stats[1]));    /* clicks -> bytes
444    */
445    memory_stats[2] = bytetok(ctob(memory_stats[2]));    /* clicks -> bytes
446    */
447    memory_stats[3] = bytetok(memory_stats[3] * NBPP);   /* # bytes per page
448    */
449    memory_stats[4] = bytetok(memory_stats[4] * NBPP);   /* # bytes per page
450    */
451    memory_stats[5] = bytetok(memory_stats[5] * NBPSCTR);/* # bytes per sector
452    */
453 
454    /* set arrays and strings */
455    /* Note: we keep memory_stats as an unsigned long to avoid sign
456       extension problems when shifting in bytetok. But the module
457       interface requires an array of signed longs. So we just cast
458       the pointer here and hope for the best.   --wnl
459    */
460    si->cpustates = cpu_states;
461    si->memory = (long *)memory_stats;
462 
463    tab_avenrun(si->load_avg);   /* philiph */
464 }
465 
466 static struct handle handle;
467 
468 caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int idx)469 get_process_info(struct system_info *si,
470 		 struct process_select *sel,
471 		 int idx)
472 
473 {
474 register int i;
475 register int total_procs;
476 register int active_procs;
477 register struct proc **prefp;
478 register struct proc *pp;
479 
480 /* set up flags of what we are going to select */
481 /* these are copied out of sel for simplicity */
482 int show_idle = sel->idle;
483 int show_system = sel->system;
484 int show_uid = sel->uid != -1;
485 int show_command = sel->command != NULL;
486 
487    /* read all the proc structures in one fell swoop */
488    (void) getkval(proca, (int *)pbase, bytes, "proc array");
489 
490    /* get a pointer to the states summary array */
491    si->procstates = process_states;
492 
493    /* count up process states and get pointers to interesting procs */
494    total_procs = active_procs = 0;
495    memset((char *)process_states, 0, sizeof(process_states));
496    prefp = pref;
497    for (pp = pbase, i = 0; i < v.v_proc; pp++, i++) {
498       /*
499        * Place pointers to each valid proc structure in pref[].
500        * Process slots that are actually in use have a non-zero
501        * status field. Processes with SSYS set are system processes --
502        * these are ignored unless show_system is set.
503        */
504       if (pp->p_stat && (show_system || ((pp->p_flag & SSYS) == 0))) {
505 	 total_procs++;
506 	 process_states[pp->p_stat]++;
507 	 if ((pp->p_stat != SZOMB) &&
508 	     (show_idle || (pp->p_stat == SRUN) || (pp->p_stat == SONPROC)) &&
509 	     (!show_uid || pp->p_uid == (ushort)sel->uid)) {
510 		*prefp++ = pp;
511 		active_procs++;
512 	 }
513       }
514    }
515 
516    /* if requested, sort the "interesting" processes */
517    qsort((char *)pref, active_procs, sizeof(struct proc *), proc_compares[idx]);
518 
519    /* remember active and total counts */
520    SI_TOTAL(si)  = total_procs;
521    SI_ACTIVE(si) = pref_len = active_procs;
522 
523    /* pass back a handle */
524    handle.next_proc = pref;
525    handle.remaining = active_procs;
526    return((caddr_t)&handle);
527 }
528 
529 char fmt[128];          /* static area where result is built */
530 
531 char *
format_next_process(caddr_t handle,char * (* get_userid)())532 format_next_process(caddr_t handle, char *(*get_userid)())
533 
534 {
535 register struct proc *pp;
536 register time_t cputime;
537 register double pct;
538 int where;
539 struct user u;
540 struct handle *hp;
541 char command[29];
542 char * process;
543 char * process2;
544 
545    /* find and remember the next proc structure */
546    hp = (struct handle *)handle;
547    pp = *(hp->next_proc++);
548    hp->remaining--;
549 
550    /* get the process's user struct and set cputime */
551    if ((where = sysi86(RDUBLK, pp->p_pid, &u, sizeof(struct user))) != -1)
552       where = (pp->p_flag & SLOAD) ? 0 : 1;
553    if (where == -1) {
554       strcpy(command, "<swapped>");
555       cputime = 0;
556    } else {
557       /* set u_comm for system processes */
558       if (u.u_comm[0] == '\0') {
559 	 if (pp->p_pid == 0)
560 	    strcpy(command, "Swapper");
561 	 else if (pp->p_pid == 2)
562 	    strcpy(command, "Pager");
563 	 else if (pp->p_pid == 3)
564 	    strcpy(command, "Sync'er");
565       } else if (where == 1) {
566 	 /* print swapped processes as <pname> */
567 	 register char *s1;
568 
569 	 u.u_psargs[28 - 3] = '\0';
570 	 strcpy(command, "<");
571 	 strcat(command, strtok(u.u_psargs, " "));
572 	 strcat(command, ">");
573 	 while (s1 = (char *)strtok(NULL, " "))
574 	    strcat(command, s1);
575       } else {
576 	 sprintf(command, "%s", u.u_psargs);
577       }
578     cputime = u.u_utime + u.u_stime;
579 /*     cputime = pp->p_utime + pp->p_stime;  */
580    }
581    /* calculate the base for cpu percentages */
582    pct = pctdouble(pp->p_cpu);
583 
584    /*
585     * psargs gives the absolute path of the process... strip it to only the
586     * command - [Changes by D. Currie & M. Muldner Aitt NS Canada]
587     */
588     process = printable(command);
589 #if NO_COMMAND_ARGS
590     strtok(process," ");
591 #endif
592     process2 = strrchr(process,'/');
593     if(process2)
594     {
595 	process = process2;
596 	process++;
597     }
598 
599 
600    /* format this entry */
601    sprintf(fmt,
602 	   Proc_format,
603 	   pp->p_pid,
604 	   (*get_userid)(pp->p_uid),
605 	   pp->p_pri - PZERO,
606 	   pp->p_nice - NZERO,
607 	   format_k(PROCSIZE(&u)),  /* same as  pp->p_size * 4 */
608 	   proc_residentsize(pp),
609 	   state_abbrev[pp->p_stat],
610 	   format_time(cputime / Hz),
611 	   printable(process) );
612 
613    return(fmt);
614 }
615 
616 /*
617  * Checks the nlist to see if any symbols were not found.
618  * For every symbol that was not found, a one-line message
619  * is printed to stderr. The routine returns the number of
620  * symbols NOT founded.
621  */
622 
check_nlist(register struct nlist * nlst)623 int check_nlist(register struct nlist *nlst)
624 
625 {
626 register int i = 0;
627 
628    while (nlst->n_name) {
629       if (nlst->n_type == 0) {
630 	 fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
631 	 i++;
632       }
633       nlst++;
634    }
635    return i;
636 }
637 
638 /*
639  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
640  *      "offset" is the byte offset into the kernel for the desired value,
641  *      "ptr" points to a buffer into which the value is retrieved,
642  *      "size" is the size of the buffer (and the object to retrieve),
643  *      "refstr" is a reference string used when printing error meessages,
644  *          if "refstr" starts with a '!', then a failure on read will not
645  *          be fatal (this may seem like a silly way to do things, but I
646  *          really didn't want the overhead of another argument).
647  *
648  */
649 
650 int
getkval(unsigned long offset,int * ptr,int size,char * refstr)651 getkval(unsigned long offset, int *ptr, int size, char *refstr)
652 
653 {
654    if (lseek(kmem, (long)offset, SEEK_SET) == -1) {
655       if (*refstr == '!')
656 	 refstr++;
657       fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
658 	       refstr, errmsg(errno));
659       quit(23);
660    }
661    if (read(kmem, (char *)ptr, size) == -1) {
662       if (*refstr == '!')
663 	 return 0;
664       fprintf(stderr, "%s: reading %s: %s\n", KMEM,
665 	       refstr, errmsg(errno));
666       quit(23);
667    }
668    return(1);
669 }
670 
671 /* comparison routine for qsort */
672 /* NOTE: this is specific to the BSD proc structure, but it should
673    give you a good place to start. */
674 
675 /*
676  *  proc_compare - comparison function for "qsort"
677  *      Compares the resource consumption of two processes using five
678  *      distinct keys.  The keys (in descending order of importance) are:
679  *      percent cpu, cpu ticks, state, resident set size, total virtual
680  *      memory usage.  The process states are ordered as follows (from least
681  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
682  *      array declaration below maps a process state index into a number
683  *      that reflects this ordering.
684  */
685 
686 static unsigned char sorted_state[] =
687 {
688     0,  /* not used             */
689     5,  /* sleep                */
690     6,  /* run                  */
691     2,  /* zombie               */
692     4,  /* stop                 */
693     1,  /* start                */
694     7,  /* onpr                 */
695     3,  /* swap                 */
696 };
697 
698 int
proc_compare(struct proc ** pp1,struct proc ** pp2)699 proc_compare(struct proc **pp1, struct proc **pp2)
700 
701 {
702 register struct proc *p1;
703 register struct proc *p2;
704 register int result;
705 register ulong lresult;
706 
707    /* remove one level of indirection */
708    p1 = *pp1;
709    p2 = *pp2;
710 
711    /* use process state to break the tie */
712    if ((result = sorted_state[p2->p_stat] -
713 		 sorted_state[p1->p_stat])  == 0)
714    {
715       /* use priority to break the tie */
716       if ((result = p2->p_pri - p1->p_pri) == 0)
717       {
718 	 /* use time to break the tie */
719 	 if ((result = (p2->p_utime + p2->p_stime) -
720 		       (p1->p_utime + p1->p_stime)) == 0)
721 	 {
722 	    /* use resident set size (rssize) to break the tie */
723 	    if ((result = p2->p_size - p1->p_size) == 0)
724 	    {
725 	       result = 0;
726 	    }
727 	 }
728       }
729    }
730 
731     return(result);
732 }
733 
734 /* returns uid of owner of process pid */
735 int
proc_owner(int pid)736 proc_owner(int pid)
737 
738 {
739 register int cnt;
740 register struct proc **prefp;
741 register struct proc  *pp;
742 
743    prefp = pref;
744    cnt = pref_len;
745    while (--cnt >= 0) {
746       if ((pp = *prefp++)->p_pid == (short)pid)
747 	 return ((int)pp->p_uid);
748    }
749    return(-1);
750 }
751 
752 #if 0
753 int setpriority(int dummy, int who, int nicewal)
754 {
755    errno = 1;
756    return -1;
757 }
758 #endif
759 
760 /* sigblock is not POSIX conformant */
sigblock(sigset_t mask)761 sigset_t sigblock (sigset_t mask)
762 {
763 sigset_t oset;
764 
765    sigemptyset(&oset);
766    sigprocmask(SIG_BLOCK, &mask, &oset);
767    return oset;
768 }
769 
770 /* sigsetmask is not POSIX conformant */
sigsetmask(sigset_t mask)771 sigsetmask(sigset_t mask)
772 {
773 sigset_t oset;
774 
775    sigemptyset(&oset);
776    sigprocmask(SIG_SETMASK, &mask, &oset);
777    return oset;
778 }
779 
780 
781 /* ---------------- hops - comparison/ordering support ---------------- */
782 
783 #define ORDERKEY_PCTCPU  if (dresult = pctdouble(p2->p_cpu) - pctdouble(p1->p_cpu),\
784 			     (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
785 #define ORDERKEY_MEMSIZE if ((result = (p2->p_size - p1->p_size)) == 0)
786 #define ORDERKEY_CPTIME  if ((result = (long)(p2->p_utime + p2->p_stime) -\
787 				       (long)(p1->p_utime + p1->p_stime)) == 0)
788 
789 #define ORDERKEY_STATE   if ((result = (sorted_state[p2->p_stat] - \
790 			       sorted_state[p1->p_stat])) == 0)
791 #define ORDERKEY_PRIO    if ((result = p2->p_pri - p1->p_pri) == 0)
792 
793 
794 int
compare_cpu(struct proc ** pp1,struct proc ** pp2)795 compare_cpu (   struct proc **pp1, struct proc **pp2)
796 {
797     register struct proc *p1;
798     register struct proc *p2;
799     register int result;
800     double dresult;
801 
802     /* remove one level of indirection */
803     p1 = *pp1;
804     p2 = *pp2;
805 
806     ORDERKEY_PCTCPU
807     ORDERKEY_CPTIME
808     ORDERKEY_STATE
809     ORDERKEY_PRIO
810     ORDERKEY_MEMSIZE
811     ;
812 
813     return (result);
814 }
815 
816 
817 
818 /* compare_size - the comparison function for sorting by process size */
819 int
compare_size(struct proc ** pp1,struct proc ** pp2)820 compare_size ( struct proc **pp1, struct proc **pp2)
821 {
822     register struct proc *p1;
823     register struct proc *p2;
824     register int result;
825     double dresult;
826 
827     /* remove one level of indirection */
828     p1 = *pp1;
829     p2 = *pp2;
830 
831 
832     ORDERKEY_MEMSIZE
833     ORDERKEY_PCTCPU
834     ORDERKEY_CPTIME
835     ORDERKEY_STATE
836     ORDERKEY_PRIO
837     ;
838 
839     return (result);
840 }
841 
842 /* compare_res - the comparison function for sorting by resident set size */
843 /* TODO: add shadow proc struct updating usr + sys times and RSS for use
844  * in comparison rtns, implement compare_res rtn as per compare_size()
845  */
846 
847 /* compare_time - the comparison function for sorting by total cpu time */
848 /* This is giving wrong results since its using the proc structure vals not
849  * the u struct vals we display above
850  * TODO: add shadow proc struct updating usr + sys times and RSS for use
851  * in comparison rtns
852  */
853 int
compare_time(struct proc ** pp1,struct proc ** pp2)854 compare_time ( struct proc **pp1, struct proc **pp2)
855 {
856     register struct proc *p1;
857     register struct proc *p2;
858     register int result;
859     double dresult;
860 
861     /* remove one level of indirection */
862     p1 = *pp1;
863     p2 = *pp2;
864 
865     ORDERKEY_CPTIME
866     ORDERKEY_PCTCPU
867     ORDERKEY_STATE
868     ORDERKEY_PRIO
869     ORDERKEY_MEMSIZE
870     ;
871 
872     return (result);
873 }
874 
875