xref: /minix/external/bsd/top/dist/machine/m_svr5.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:  For Intel based System V Release 5 (Unixware7)
37  *
38  * DESCRIPTION:
39  * System V release 5 for i[3456]86
40  * Works for:
41  * i586-sco-sysv5uw7  i386 SCO UNIX_SVR5 (UnixWare 7)
42  *
43  * LIBS:  -lelf -lmas
44  *
45  * CFLAGS: -DHAVE_GETOPT -DORDER
46  *
47  * AUTHORS: Mike Hopkirk       <hops@sco.com>
48  *          David Cutter       <dpc@grail.com>
49  *          Andrew Herbert     <andrew@werple.apana.org.au>
50  *          Robert Boucher     <boucher@sofkin.ca>
51  */
52 
53 /* build config
54  *  SHOW_NICE - process nice fields don't seem to be being updated so changed
55  *     default to display # of threads in use instead.
56  *     define this to display nice fields (values always 0)
57  * #define SHOW_NICE 1
58  */
59 
60 #define _KMEMUSER
61 #define prpsinfo psinfo
62 #include <sys/procfs.h>
63 
64 #define pr_state pr_lwp.pr_state
65 #define pr_nice pr_lwp.pr_nice
66 #define pr_pri pr_lwp.pr_pri
67 #define pr_onpro pr_lwp.pr_onpro
68 #define ZOMBIE(p)	((p)->pr_nlwp == 0)
69 #define SIZE_K(p)	pagetok((p)->pr_size)
70 #define RSS_K(p)	pagetok((p)->pr_rssize)
71 
72 
73 #include <stdio.h>
74 #include <fcntl.h>
75 #include <unistd.h>
76 #include <stdlib.h>
77 #include <errno.h>
78 #include <dirent.h>
79 #include <nlist.h>
80 #include <string.h>
81 #include <sys/types.h>
82 #include <sys/param.h>
83 #include <sys/proc.h>
84 #include <sys/sysmacros.h>
85 #include <vm/anon.h>
86 #include <sys/priocntl.h>
87 #include <sys/tspriocntl.h>
88 #include <sys/var.h>
89 
90 #include "top.h"
91 #include "machine.h"
92 #include "utils.h"
93 
94 #define UNIX "/stand/unix"
95 #define KMEM "/dev/kmem"
96 #define PROCFS "/proc"
97 #define CPUSTATES	5
98 
99 #ifndef PRIO_MAX
100 #define PRIO_MAX	20
101 #endif
102 #ifndef PRIO_MIN
103 #define PRIO_MIN	-20
104 #endif
105 
106 #ifndef FSCALE
107 #define FSHIFT  8		/* bits to right of fixed binary point */
108 #define FSCALE  (1<<FSHIFT)
109 #endif
110 
111 #define loaddouble(x) ((double)x/FSCALE)
112 #define pagetok(size) ((size) * pagesz) >> LOG1024
113 
114 /* definitions for the index in the nlist array */
115 #define X_AVENRUN	0
116 #define X_V		1
117 #define X_MPID		2
118 
119 static struct nlist nlst[] =
120 {
121    {"avenrun"},		        /* 0 */
122    {"v"},			/* 1 */
123    {"nextpid"},                 /* 2 */
124   {NULL}
125 };
126 
127 static unsigned long avenrun_offset;
128 static unsigned long mpid_offset;
129 
130 static unsigned int pagesz;
131 
132 static void reallocproc(int n);
133 static int maxprocs;
134 
135 /* get_process_info passes back a handle.  This is what it looks like: */
136 
137 struct handle
138 {
139     struct prpsinfo **next_proc;/* points to next valid proc pointer */
140     int remaining;		/* number of pointers remaining */
141 };
142 
143 /*
144  *  These definitions control the format of the per-process area
145  */
146 
147 static char header[] =
148 #ifdef SHOW_NICE
149 "  PID X        PRI NICE  SIZE   RES STATE   TIME      CPU  COMMAND";
150 #else
151 "  PID X        PRI  THR  SIZE   RES STATE   TIME      CPU  COMMAND";
152 #endif
153 /* 0123456   -- field to fill in starts at header+6 */
154 #define UNAME_START 6
155 #define Proc_format \
156 	"%5d %-8.8s %3d %4d %5s %5s %-5s %6s %8.4f%% %.16s"
157 
158 char *state_abbrev[] =
159 {"oncpu", "run", "sleep",  "stop", "idle", "zombie"};
160 
161 #define sZOMB 5
162 int process_states[8];
163 char *procstatenames[] =
164 {
165   " on cpu, ", " running, ", " sleeping, ", " stopped, ",
166   " idling ",  " zombie, ",
167   NULL
168 };
169 
170 int cpu_states[CPUSTATES];
171 char *cpustatenames[] =
172 {"idle", "user", "kernel", "wait", NULL};
173 
174 
175 /* these are for detailing the memory statistics */
176 long memory_stats[5];
177 char *memorynames[] =
178 {"K phys, ", "K used, ", "K free, ", "K swapUsed, ", "K swapFree", NULL};
179 
180 /* these are names given to allowed sorting orders -- first is default */
181 char *ordernames[] =
182 {"state", "cpu", "size", "res", "time", "pid", "uid", "rpid", "ruid", NULL};
183 
184 /* forward definitions for comparison functions */
185 int proc_compare();
186 int compare_cpu();
187 int compare_size();
188 int compare_res();
189 int compare_time();
190 int compare_pid();
191 int compare_uid();
192 int compare_rpid();
193 int compare_ruid();
194 
195 int (*proc_compares[])() = {
196     proc_compare,
197     compare_cpu,
198     compare_size,
199     compare_res,
200     compare_time,
201     compare_pid,
202     compare_uid,
203     compare_rpid,
204     compare_ruid,
205     NULL };
206 
207 
208 static int kmem = -1;
209 static int nproc;
210 static int bytes;
211 static struct prpsinfo *pbase;
212 static struct prpsinfo **pref;
213 static DIR *procdir;
214 
215 /* useful externals */
216 extern int errno;
217 extern char *sys_errlist[];
218 extern char *myname;
219 extern long percentages ();
220 extern int check_nlist ();
221 extern int getkval ();
222 extern void perror ();
223 extern void getptable ();
224 extern void quit ();
225 extern int nlist ();
226 
227 /* fwd dcls */
228 static int kmet_init(void );
229 static int get_cpustates(int *new);
230 
231 
232 int
machine_init(struct statics * statics)233 machine_init (struct statics *statics)
234   {
235     static struct var v;
236     int i;
237 
238     /* fill in the statics information */
239     statics->procstate_names = procstatenames;
240     statics->cpustate_names = cpustatenames;
241     statics->memory_names = memorynames;
242     statics->order_names = ordernames;
243 
244     /* get the list of symbols we want to access in the kernel */
245     if (nlist (UNIX, nlst))
246       {
247 	(void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
248 	return (-1);
249       }
250 
251     /* make sure they were all found */
252     if (check_nlist (nlst) > 0)
253       return (-1);
254 
255     /* open kernel memory */
256     if ((kmem = open (KMEM, O_RDONLY)) == -1)
257       {
258 	perror (KMEM);
259 	return (-1);
260       }
261 
262     v.v_proc=200;   /* arbitrary default */
263     /* get the symbol values out of kmem */
264     /* NPROC Tuning parameter for max number of processes */
265     (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
266     nproc = v.v_proc;
267     maxprocs = nproc;
268 
269     /* stash away certain offsets for later use */
270     mpid_offset = nlst[X_MPID].n_value;
271     avenrun_offset = nlst[X_AVENRUN].n_value;
272 
273     /* allocate space for proc structure array and array of pointers */
274     bytes = nproc * sizeof (struct prpsinfo);
275     pbase = (struct prpsinfo *) malloc (bytes);
276     pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
277 
278     pagesz = sysconf(_SC_PAGESIZE);
279 
280 
281     /* Just in case ... */
282     if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
283       {
284 	(void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
285 	return (-1);
286       }
287 
288     if (!(procdir = opendir (PROCFS)))
289       {
290 	(void) fprintf (stderr, "Unable to open %s\n", PROCFS);
291 	return (-1);
292       }
293 
294     if (chdir (PROCFS))
295     {				/* handy for later on when we're reading it */
296 	(void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
297 	return (-1);
298     }
299 
300 
301     kmet_init();
302 
303     /* all done! */
304     return (0);
305   }
306 
307 char *
format_header(char * uname_field)308 format_header (char *uname_field)
309 {
310   register char *ptr;
311 
312   ptr = header + UNAME_START;
313   while (*uname_field != '\0')
314     *ptr++ = *uname_field++;
315 
316   return (header);
317 }
318 
319 void
get_system_info(struct system_info * si)320 get_system_info (struct system_info *si)
321 {
322   long avenrun[3];
323   long mem;
324   static time_t cp_old[CPUSTATES];
325   static time_t cp_diff[CPUSTATES];	/* for cpu state percentages */
326   register int i;
327   static long swap_total;
328   static long swap_free;
329   int new_states[CPUSTATES];
330 
331   get_cpustates(new_states);
332 
333   /* convert cp_time counts to percentages */
334   (void) percentages (CPUSTATES, cpu_states, new_states, cp_old, cp_diff);
335 
336 
337   si->last_pid = -1;
338   /* get mpid -- process id of last process
339    * svr5 is nextpid - next pid to be assigned (already incremented)
340    */
341    (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
342    		  "nextpid");
343    (si->last_pid)--;    /* so we shld decrement for display */
344 
345 
346   /* get load average array */
347   (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
348   /* convert load averages to doubles */
349   for (i = 0; i < 3; i++)
350     si->load_avg[i] = loaddouble(avenrun[i]);
351 
352   mem = sysconf(_SC_TOTAL_MEMORY);      /* physical mem */
353   memory_stats[0] = pagetok (mem);
354 
355   mem = kmet_get_freemem();             /* free mem */
356   memory_stats[2] = pagetok (mem);
357 
358   /* mem = sysconf(_SC_GENERAL_MEMORY);    */
359   memory_stats[1] = memory_stats[0] - memory_stats[2]; /* active */
360 
361   get_swapinfo(&swap_total, &swap_free);
362   memory_stats[3] = pagetok(swap_total - swap_free);
363   memory_stats[4] = pagetok(swap_free);
364 
365 
366   /* set arrays and strings */
367   si->cpustates = cpu_states;
368   si->memory = memory_stats;
369 }
370 
371 static struct handle handle;
372 
373 caddr_t
get_process_info(struct system_info * si,struct process_select * sel,int idx)374 get_process_info (
375 		   struct system_info *si,
376 		   struct process_select *sel,
377 		   int idx)
378 {
379   register int i;
380   register int total_procs;
381   register int active_procs;
382   register struct prpsinfo **prefp;
383   register struct prpsinfo *pp;
384 
385   /* these are copied out of sel for speed */
386   int show_idle;
387   int show_system;
388   int show_uid;
389 
390   /* Get current number of processes */
391 
392   /* read all the proc structures */
393   getptable (pbase);
394 
395   /* get a pointer to the states summary array */
396   si->procstates = process_states;
397 
398   /* set up flags which define what we are going to select */
399   show_idle   = sel->idle;
400   show_system = sel->system;
401   show_uid    = sel->uid != -1;
402 
403   nproc = kmet_get_nproc();
404 
405   /* count up process states and get pointers to interesting procs */
406   total_procs = 0;
407   active_procs = 0;
408   (void) memset (process_states, 0, sizeof (process_states));
409   prefp = pref;
410 
411   for (pp = pbase, i = 0; i < nproc; pp++, i++)
412   {
413       /*
414 	 *  Place pointers to each valid proc structure in pref[].
415 	 *  Process slots that are actually in use have a non-zero
416 	 *  status field.  Processes with PR_ISSYS set are system
417 	 *  processes---these get ignored unless show_sysprocs is set.
418 	 */
419       if ((pp->pr_state >= SONPROC && pp->pr_state <= SIDL)  &&
420 	  (show_system || ((pp->pr_flag & PR_ISSYS) == 0)))
421       {
422 	  total_procs++;
423 	  process_states[pp->pr_state]++;
424 	  if ((!ZOMBIE(pp)) &&
425 	      (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
426 	      (!show_uid || pp->pr_uid == (uid_t) sel->uid))
427 	  {
428 	      *prefp++ = pp;
429 	      active_procs++;
430 	  }
431 	  if (ZOMBIE(pp))
432     	    process_states[sZOMB]++;    /* invented */
433 
434       }
435   }
436 
437   /* if requested, sort the "interesting" processes */
438   qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *),
439 	 proc_compares[idx]);
440 
441   /* remember active and total counts */
442   si->p_total = total_procs;
443   si->P_ACTIVE = active_procs;
444 
445   /* pass back a handle */
446   handle.next_proc = pref;
447   handle.remaining = active_procs;
448   return ((caddr_t) & handle);
449 }
450 
451 /*
452  * cpu percentage calculation is as fm ps.c
453  * seems to be ratio of (sys+user time used)/(elapsed time)
454  * i.e percent of cpu utilised when on cpu
455  */
percent_cpu(struct prpsinfo * pp)456 static double percent_cpu( struct prpsinfo *pp)
457 {
458     static time_t tim = 0L;
459     time_t starttime;
460     time_t ctime;
461     time_t etime;
462 
463     /* if (tim == 0L) */
464         tim = time((time_t *) 0);
465     starttime = pp->pr_start.tv_sec;
466     if (pp->pr_start.tv_nsec > 500000000)
467             starttime++;
468     etime = (tim - starttime);
469     ctime = pp->pr_time.tv_sec;
470     if (pp->pr_time.tv_nsec > 500000000)
471     ctime++;
472     if (etime)
473     {
474         /* return  (float)(ctime * 100) / (unsigned)etime; */
475         /* this was ocasionally giving vals >100 for some
476          * unknown reason so the below normalises it
477          */
478 
479         double pct;
480         pct = (float)(ctime * 100) / (unsigned)etime;
481         return (pct < 100.0) ? pct : 100.00;
482     }
483     return 0.00;
484 }
485 
486 
487 char fmt[MAX_COLS];			/* static area where result is built */
488 
489 char *
format_next_process(caddr_t handle,char * (* get_userid)())490 format_next_process (
491 		      caddr_t handle,
492 		      char *(*get_userid) ())
493 {
494   register struct prpsinfo *pp;
495   struct handle *hp;
496   register long cputime;
497   register double pctcpu;
498 
499   /* find and remember the next proc structure */
500   hp = (struct handle *) handle;
501   pp = *(hp->next_proc++);
502   hp->remaining--;
503 
504   /* get the cpu usage and calculate the cpu percentages */
505   cputime = pp->pr_time.tv_sec;
506   pctcpu = percent_cpu(pp);
507 
508 
509   /* format this entry */
510   (void) sprintf (fmt,
511 		  Proc_format,
512 		  pp->pr_pid,
513 		  (*get_userid) (pp->pr_uid),
514                   pp->pr_pri,
515 #ifdef SHOW_NICE
516 		  pp->pr_nice,
517 #else
518 	          (u_short)pp->pr_nlwp < 999 ? (u_short)pp->pr_nlwp : 999,
519 #endif
520 	          format_k(SIZE_K(pp)),
521                   format_k(RSS_K(pp)),
522 	          (ZOMBIE(pp))  ? state_abbrev[sZOMB]
523                                 : state_abbrev[pp->pr_state],
524 		  format_time(cputime),
525 		  /* 100.0 * */ pctcpu,
526 		  printable(pp->pr_fname));
527 
528   /* return the result */
529   return (fmt);
530 }
531 
532 /*
533  * check_nlist(nlst) - checks the nlist to see if any symbols were not
534  *		found.  For every symbol that was not found, a one-line
535  *		message is printed to stderr.  The routine returns the
536  *		number of symbols NOT found.
537  */
538 int
check_nlist(register struct nlist * nlst)539 check_nlist (register struct nlist *nlst)
540 {
541   register int i;
542 
543   /* check to see if we got ALL the symbols we requested */
544   /* this will write one line to stderr for every symbol not found */
545 
546   i = 0;
547   while (nlst->n_name != NULL)
548     {
549       if (nlst->n_value == 0)
550 	{
551 	  /* this one wasn't found */
552 	  (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
553 	  i = 1;
554 	}
555       nlst++;
556     }
557   return (i);
558 }
559 
560 
561 /*
562  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
563  *	"offset" is the byte offset into the kernel for the desired value,
564  *  	"ptr" points to a buffer into which the value is retrieved,
565  *  	"size" is the size of the buffer (and the object to retrieve),
566  *  	"refstr" is a reference string used when printing error meessages,
567  *	    if "refstr" starts with a '!', then a failure on read will not
568  *  	    be fatal (this may seem like a silly way to do things, but I
569  *  	    really didn't want the overhead of another argument).
570  *
571  */
572 int
getkval(unsigned long offset,int * ptr,int size,char * refstr)573 getkval (
574 	  unsigned long offset,
575 	  int *ptr,
576 	  int size,
577 	  char *refstr)
578 {
579   if (lseek (kmem, (long) offset, 0) == -1)
580     {
581       if (*refstr == '!')
582 	refstr++;
583       (void) fprintf (stderr, "%s: lseek to %s: %s\n",
584 		      myname, refstr, sys_errlist[errno]);
585       quit (22);
586     }
587   if (read (kmem, (char *) ptr, size) == -1)
588     if (*refstr == '!')
589       /* we lost the race with the kernel, process isn't in memory */
590       return (0);
591     else
592       {
593 	(void) fprintf (stderr, "%s: reading %s: %s\n",
594 			myname, refstr, sys_errlist[errno]);
595 	quit (23);
596       }
597   return (1);
598 }
599 
600 /* ----------------- comparison routines for qsort ---------------- */
601 
602 /* First, the possible comparison keys.  These are defined in such a way
603    that they can be merely listed in the source code to define the actual
604    desired ordering.
605  */
606 
607 #define ORDERKEY_PCTCPU  if (dresult = percent_cpu (p2) - percent_cpu (p1),\
608 			     (result = dresult > 0.0 ? 1 : \
609 			     dresult < 0.0 ? -1 : 0) == 0)
610 
611 #define ORDERKEY_CPTICKS if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
612 #define ORDERKEY_STATE   if ((result = (long) (sorted_state[p2->pr_state] - \
613 			       sorted_state[p1->pr_state])) == 0)
614 
615 #define ORDERKEY_PRIO    if ((result = p2->pr_pri    - p1->pr_pri)    == 0)
616 #define ORDERKEY_RSSIZE  if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
617 #define ORDERKEY_MEM     if ((result = (p2->pr_size  - p1->pr_size))  == 0)
618 
619 #define ORDERKEY_PID     if ((result = (p2->pr_pid  - p1->pr_pid))  == 0)
620 #define ORDERKEY_UID     if ((result = (p2->pr_uid  - p1->pr_uid))  == 0)
621 #define ORDERKEY_RPID    if ((result = (p1->pr_pid  - p2->pr_pid))  == 0)
622 #define ORDERKEY_RUID    if ((result = (p1->pr_uid  - p2->pr_uid))  == 0)
623 
624 /* states enum {SONPROC, SRUN, SSLEEP, SSTOP, SIDL}  */
625 unsigned char sorted_state[] =
626 {
627   7,				/* onproc		*/
628   6,				/* run		        */
629   5,				/* sleep		*/
630   4,				/* stop		        */
631   3,				/* idle			*/
632   2,				/* zombie		*/
633   0,				/* unused               */
634   0				/* unused	        */
635 };
636 
637 #if 0
638 /*
639  *  proc_compare - original singleton comparison function for "qsort"
640  *	Compares the resource consumption of two processes using five
641  *  	distinct keys.  The keys (in descending order of importance) are:
642  *  	percent cpu, cpu ticks, state, resident set size, total virtual
643  *  	memory usage.  The process states are ordered as follows (from least
644  *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
645  *  	array declaration below maps a process state index into a number
646  *  	that reflects this ordering.
647  */
648  /* default comparison rtn */
649 int
650 original_proc_compare (
651 	       struct prpsinfo **pp1,
652 	       struct prpsinfo **pp2)
653   {
654     register struct prpsinfo *p1;
655     register struct prpsinfo *p2;
656     register long result;
657     double dresult;
658 
659     /* remove one level of indirection */
660     p1 = *pp1;
661     p2 = *pp2;
662 
663     /* compare percent cpu (pctcpu) */
664     dresult = percent_cpu(p2) - percent_cpu (p1);
665     result = dresult > 0.0 ?  1 :
666              dresult < 0.0 ? -1 : 0;
667     if (result)
668     {
669 	/* use cpticks to break the tie */
670 	if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
671 	  {
672 	    /* use process state to break the tie */
673 	    if ((result = (long) (sorted_state[p2->pr_state] -
674 				  sorted_state[p1->pr_state])) == 0)
675 	      {
676 		/* use priority to break the tie */
677 		if ((result = p2->pr_pri - p1->pr_pri) == 0)
678 		  {
679 		    /* use resident set size (rssize) to break the tie */
680 		    if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
681 		      {
682 			/* use total memory to break the tie */
683 			result = (p2->pr_size - p1->pr_size);
684 		      }
685 		  }
686 	      }
687 	  }
688     }
689     return (result);
690   }
691 #endif  /* original comparison rtn */
692 
693 /* compare_state - comparison function for sorting by state,pri,time,size */
694 int
proc_compare(struct prpsinfo ** pp1,struct prpsinfo ** pp2)695 proc_compare (
696 	       struct prpsinfo **pp1,
697 	       struct prpsinfo **pp2)
698   {
699     register struct prpsinfo *p1;
700     register struct prpsinfo *p2;
701     register long result;
702     double dresult;
703 
704     /* remove one level of indirection */
705     p1 = *pp1;
706     p2 = *pp2;
707 
708     ORDERKEY_STATE
709     ORDERKEY_PRIO
710     ORDERKEY_CPTICKS
711     ORDERKEY_RSSIZE
712     ORDERKEY_MEM
713     ORDERKEY_PCTCPU
714     ;
715 
716     return (result);
717   }
718 
719 
720 /* compare_cpu - the comparison function for sorting by cpu % (deflt) */
721 int
compare_cpu(struct prpsinfo ** pp1,struct prpsinfo ** pp2)722 compare_cpu (
723 	       struct prpsinfo **pp1,
724 	       struct prpsinfo **pp2)
725   {
726     register struct prpsinfo *p1;
727     register struct prpsinfo *p2;
728     register long result;
729     double dresult;
730 
731     /* remove one level of indirection */
732     p1 = *pp1;
733     p2 = *pp2;
734 
735     ORDERKEY_PCTCPU
736     ORDERKEY_CPTICKS
737     ORDERKEY_STATE
738     ORDERKEY_PRIO
739     ORDERKEY_RSSIZE
740     ORDERKEY_MEM
741     ;
742 
743     return (result);
744   }
745 
746 /* compare_size - the comparison function for sorting by total memory usage */
747 int
compare_size(struct prpsinfo ** pp1,struct prpsinfo ** pp2)748 compare_size (
749 	       struct prpsinfo **pp1,
750 	       struct prpsinfo **pp2)
751   {
752     register struct prpsinfo *p1;
753     register struct prpsinfo *p2;
754     register long result;
755     double dresult;
756 
757     /* remove one level of indirection */
758     p1 = *pp1;
759     p2 = *pp2;
760 
761     ORDERKEY_MEM
762     ORDERKEY_RSSIZE
763     ORDERKEY_PCTCPU
764     ORDERKEY_CPTICKS
765     ORDERKEY_STATE
766     ORDERKEY_PRIO
767     ;
768 
769     return (result);
770   }
771 
772 /* compare_res - the comparison function for sorting by resident set size */
773 int
compare_res(struct prpsinfo ** pp1,struct prpsinfo ** pp2)774 compare_res (
775 	       struct prpsinfo **pp1,
776 	       struct prpsinfo **pp2)
777   {
778     register struct prpsinfo *p1;
779     register struct prpsinfo *p2;
780     register long result;
781     double dresult;
782 
783     /* remove one level of indirection */
784     p1 = *pp1;
785     p2 = *pp2;
786 
787     ORDERKEY_RSSIZE
788     ORDERKEY_MEM
789     ORDERKEY_PCTCPU
790     ORDERKEY_CPTICKS
791     ORDERKEY_STATE
792     ORDERKEY_PRIO
793     ;
794 
795     return (result);
796   }
797 
798 /* compare_time - the comparison function for sorting by total cpu time */
799 int
compare_time(struct prpsinfo ** pp1,struct prpsinfo ** pp2)800 compare_time (
801 	       struct prpsinfo **pp1,
802 	       struct prpsinfo **pp2)
803   {
804     register struct prpsinfo *p1;
805     register struct prpsinfo *p2;
806     register long result;
807     double dresult;
808 
809     /* remove one level of indirection */
810     p1 = *pp1;
811     p2 = *pp2;
812 
813     ORDERKEY_CPTICKS
814     ORDERKEY_PCTCPU
815     ORDERKEY_STATE
816     ORDERKEY_PRIO
817     ORDERKEY_MEM
818     ORDERKEY_RSSIZE
819     ;
820 
821     return (result);
822   }
823 
824 /* compare_pid - the comparison function for sorting by pid */
825 int
compare_pid(struct prpsinfo ** pp1,struct prpsinfo ** pp2)826 compare_pid (
827 	       struct prpsinfo **pp1,
828 	       struct prpsinfo **pp2)
829   {
830     register struct prpsinfo *p1;
831     register struct prpsinfo *p2;
832     register long result;
833     double dresult;
834 
835     /* remove one level of indirection */
836     p1 = *pp1;
837     p2 = *pp2;
838 
839     ORDERKEY_PID
840     ORDERKEY_CPTICKS
841     ORDERKEY_PCTCPU
842     ORDERKEY_STATE
843     ORDERKEY_PRIO
844     ORDERKEY_MEM
845     ORDERKEY_RSSIZE
846     ;
847 
848     return (result);
849   }
850 
851 /* compare_uid - the comparison function for sorting by user ID */
852 int
compare_uid(struct prpsinfo ** pp1,struct prpsinfo ** pp2)853 compare_uid (
854 	       struct prpsinfo **pp1,
855 	       struct prpsinfo **pp2)
856   {
857     register struct prpsinfo *p1;
858     register struct prpsinfo *p2;
859     register long result;
860     double dresult;
861 
862     /* remove one level of indirection */
863     p1 = *pp1;
864     p2 = *pp2;
865 
866     ORDERKEY_UID
867     ORDERKEY_CPTICKS
868     ORDERKEY_PCTCPU
869     ORDERKEY_STATE
870     ORDERKEY_PRIO
871     ORDERKEY_MEM
872     ORDERKEY_RSSIZE
873     ;
874 
875     return (result);
876   }
877 
878 /* compare_rpid - the comparison function for sorting by pid ascending */
879 int
compare_rpid(struct prpsinfo ** pp1,struct prpsinfo ** pp2)880 compare_rpid (
881 	       struct prpsinfo **pp1,
882 	       struct prpsinfo **pp2)
883   {
884     register struct prpsinfo *p1;
885     register struct prpsinfo *p2;
886     register long result;
887     double dresult;
888 
889     /* remove one level of indirection */
890     p1 = *pp1;
891     p2 = *pp2;
892 
893     ORDERKEY_RPID
894     ORDERKEY_CPTICKS
895     ORDERKEY_PCTCPU
896     ORDERKEY_STATE
897     ORDERKEY_PRIO
898     ORDERKEY_MEM
899     ORDERKEY_RSSIZE
900     ;
901 
902     return (result);
903   }
904 
905 /* compare_uid - the comparison function for sorting by user ID ascending */
906 int
compare_ruid(struct prpsinfo ** pp1,struct prpsinfo ** pp2)907 compare_ruid (
908 	       struct prpsinfo **pp1,
909 	       struct prpsinfo **pp2)
910   {
911     register struct prpsinfo *p1;
912     register struct prpsinfo *p2;
913     register long result;
914     double dresult;
915 
916     /* remove one level of indirection */
917     p1 = *pp1;
918     p2 = *pp2;
919 
920     ORDERKEY_RUID
921     ORDERKEY_CPTICKS
922     ORDERKEY_PCTCPU
923     ORDERKEY_STATE
924     ORDERKEY_PRIO
925     ORDERKEY_MEM
926     ORDERKEY_RSSIZE
927     ;
928 
929     return (result);
930   }
931 
932 
933 /* ---------------- helper rtns ---------------- */
934 
935 /*
936  * get process table
937  */
938 void
getptable(struct prpsinfo * baseptr)939 getptable (struct prpsinfo *baseptr)
940 {
941   struct prpsinfo *currproc;	/* pointer to current proc structure	*/
942   int numprocs = 0;
943   struct dirent *direntp;
944 
945   currproc = baseptr;
946   for (rewinddir (procdir); direntp = readdir (procdir);)
947     {
948       int fd;
949       char buf[30];
950 
951       sprintf(buf,"%s/psinfo", direntp->d_name);
952 
953       if ((fd = open (buf, O_RDONLY)) < 0)
954 	continue;
955 
956       if (read(fd, currproc, sizeof(psinfo_t)) != sizeof(psinfo_t))
957       {
958 	  (void) close (fd);
959 	  continue;
960       }
961 
962       numprocs++;
963       currproc++;
964 
965       (void) close (fd);
966 
967       /* Atypical place for growth */
968       if (numprocs >= maxprocs)
969       {
970 	    reallocproc(2 * numprocs);
971 	    currproc = (struct prpsinfo *)
972 		    ((char *)baseptr + sizeof(psinfo_t) * numprocs);
973       }
974 
975     }
976 
977   if (nproc != numprocs)
978     nproc = numprocs;
979 }
980 
981 /* return the owner of the specified process, for use in commands.c as we're
982    running setuid root */
983 int
proc_owner(int pid)984 proc_owner (int pid)
985 {
986   register struct prpsinfo *p;
987   int i;
988   for (i = 0, p = pbase; i < nproc; i++, p++)
989     if (p->pr_pid == (pid_t)pid)
990       return ((int)(p->pr_uid));
991 
992   return (-1);
993 }
994 
995 int
setpriority(int dummy,int who,int niceval)996 setpriority (int dummy, int who, int niceval)
997 {
998   int scale;
999   int prio;
1000   pcinfo_t pcinfo;
1001   pcparms_t pcparms;
1002   tsparms_t *tsparms;
1003 
1004   strcpy (pcinfo.pc_clname, "TS");
1005   if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
1006     return (-1);
1007 
1008   prio = niceval;
1009   if (prio > PRIO_MAX)
1010     prio = PRIO_MAX;
1011   else if (prio < PRIO_MIN)
1012     prio = PRIO_MIN;
1013 
1014   tsparms = (tsparms_t *) pcparms.pc_clparms;
1015   scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
1016   tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
1017   pcparms.pc_cid = pcinfo.pc_cid;
1018 
1019   if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
1020     return (-1);
1021 
1022   return (0);
1023 }
1024 
1025 
get_swapinfo(long * total,long * fr)1026 get_swapinfo(long *total, long *fr)
1027 {
1028     register int cnt, i;
1029     register long t, f;
1030     struct swaptable *swt;
1031     struct swapent *ste;
1032     static char path[256];
1033 
1034     /* get total number of swap entries */
1035     cnt = swapctl(SC_GETNSWP, 0);
1036 
1037     /* allocate enough space to hold count + n swapents */
1038     swt = (struct swaptable *)malloc(sizeof(int) +
1039 				     cnt * sizeof(struct swapent));
1040     if (swt == NULL)
1041     {
1042 	*total = 0;
1043 	*fr = 0;
1044 	return;
1045     }
1046     swt->swt_n = cnt;
1047 
1048     /* fill in ste_path pointers: we don't care about the paths, so we point
1049        them all to the same buffer */
1050     ste = &(swt->swt_ent[0]);
1051     i = cnt;
1052     while (--i >= 0)
1053     {
1054 	ste++->ste_path = path;
1055     }
1056 
1057     /* grab all swap info */
1058     swapctl(SC_LIST, swt);
1059 
1060     /* walk thru the structs and sum up the fields */
1061     t = f = 0;
1062     ste = &(swt->swt_ent[0]);
1063     i = cnt;
1064     while (--i >= 0)
1065     {
1066 	/* dont count slots being deleted */
1067 	if (!(ste->ste_flags & ST_INDEL) )
1068 	{
1069 	    t += ste->ste_pages;
1070 	    f += ste->ste_free;
1071 	}
1072 	ste++;
1073     }
1074 
1075     /* fill in the results */
1076     *total = t;
1077     *fr = f;
1078     free(swt);
1079 }
1080 
1081 
1082 /*
1083  * When we reach a proc limit, we need to realloc the stuff.
1084  */
reallocproc(int n)1085 static void reallocproc(int n)
1086 {
1087     int bytes;
1088     struct oldproc *op, *endbase;
1089 
1090     if (n < maxprocs)
1091 	return;
1092 
1093     maxprocs = n;
1094 
1095     /* allocate space for proc structure array and array of pointers */
1096     bytes = maxprocs * sizeof(psinfo_t) ;
1097     pbase = (struct prpsinfo *) realloc(pbase, bytes);
1098     pref = (struct prpsinfo **) realloc(pref,
1099 			maxprocs * sizeof(struct prpsinfo *));
1100 
1101     /* Just in case ... */
1102     if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
1103     {
1104 	fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
1105 	quit(1);
1106     }
1107 }
1108 
1109 /* ---------------------------------------------------------------- */
1110 /* Access kernel Metrics
1111  * SVR5 uses metreg inteface to Kernel statistics (metrics)
1112  *  see /usr/include/mas.h, /usr/include/metreg.h
1113  */
1114 
1115 #include <sys/mman.h>
1116 #include <sys/dl.h>
1117 #include <mas.h>
1118 #include <metreg.h>
1119 
1120 static int md;         /* metric descriptor handle */
1121 static  uint32 ncpu;   /* number of processors in system */
1122 
1123 /* fwd dcls */
1124 static uint32 kmet_get_cpu( int type, char *desc);
1125 static void kmet_verify(
1126     uint32 md,    metid_t id,  units_t units, type_t mettype,
1127     uint32 metsz, uint32 nobj, uint32 nlocs,  resource_t res_id,
1128     uint32 ressz ) ;
1129 
1130 
get_cpustates(int * new)1131 static int get_cpustates(int *new)
1132 {
1133     new[0] = (int)kmet_get_cpu( MPC_CPU_IDLE, "idle");
1134     new[1] = (int)kmet_get_cpu( MPC_CPU_USR,  "usr");
1135     new[2] = (int)kmet_get_cpu( MPC_CPU_SYS,  "sys");
1136     new[3] = (int)kmet_get_cpu( MPC_CPU_WIO,  "wio");
1137 }
1138 
1139 
1140 /* initialises kernel metrics access and gets #cpus */
kmet_init()1141 static int kmet_init()
1142 {
1143     uint32 *ncpu_p;
1144 
1145     /*  open (and map in) the metric access file and assoc data structures */
1146     if( ( md = mas_open( MAS_FILE, MAS_MMAP_ACCESS ) ) < 0 )
1147     {
1148         (void)fprintf(stderr,"mas_open failed\n");
1149         mas_perror();
1150         quit(10);
1151     }
1152 
1153     /* verify the NCPU metric is everything we expect */
1154     kmet_verify(md, NCPU, CPUS, CONFIGURABLE, sizeof(short),
1155                    1, 1, MAS_SYSTEM, sizeof(uint32) );
1156 
1157     /* get the number of cpu's on the system */
1158     if( (ncpu_p = (uint32 *)mas_get_met( md, NCPU, 0 )) == NULL )
1159     {
1160         (void)fprintf(stderr,"mas_get_met of ncpu failed\n");
1161         mas_perror();
1162         quit(12);
1163     }
1164     ncpu = (uint32)(*(short *)ncpu_p);
1165 
1166     /* check that MPC_CPU_IDLE is of the form we expect
1167      *      ( paranoically we should check the rest as well but ... )
1168      */
1169     kmet_verify( md, MPC_CPU_IDLE, TIX, PROFILE, sizeof(uint32),
1170                     1,  ncpu, NCPU, sizeof(short) );
1171 
1172     kmet_verify( md, PROCUSE, PROCESSES, COUNT, sizeof(uint32),
1173                     1,  1, MAS_SYSTEM, sizeof(uint32) );
1174     nproc = kmet_get_nproc();
1175 
1176     return 0;
1177 }
1178 
1179 /* done with kernel metrics access */
1180 static int
kmet_done()1181 kmet_done()
1182 {
1183     if ( mas_close( md ) < 0 )
1184     {
1185         (void)fprintf(stderr,"mas_close failed\n");
1186         mas_perror();
1187         quit(14);
1188     }
1189 }
1190 
1191 
1192 static uint32
kmet_get_cpu(int type,char * desc)1193 kmet_get_cpu( int type, char *desc)
1194 {
1195     int i;
1196     uint32 r=0, rtot=0 ;
1197 
1198     for (i=0; i <ncpu; i++)
1199     {
1200         r=*(uint32 *)mas_get_met( md, (metid_t)type, 0 );
1201         if ( !r)
1202         {
1203             (void)fprintf(stderr,"mas_get_met of %s failed\n", desc);
1204             mas_perror();
1205             quit(12);
1206         }
1207         rtot += r;      /* sum them for multi cpus */
1208     }
1209     return rtot /* /ncpu */ ;
1210 }
1211 
1212 static int
kmet_get_freemem()1213 kmet_get_freemem()
1214 {
1215     dl_t            *fm_p, fm, fmc, denom;
1216     time_t          td1;
1217     static time_t   td0;
1218     static dl_t     fm_old;
1219 
1220 
1221     td1 = time(NULL);
1222     if ((fm_p = (dl_t *)mas_get_met( md, FREEMEM, 0 )) == NULL )
1223     {
1224         (void)fprintf(stderr,"mas_get_met of freemem failed\n");
1225         mas_perror();
1226         quit(12);
1227     }
1228     fm = *fm_p;
1229 
1230     denom.dl_hop = 0;
1231     denom.dl_lop = (long) (td1 - td0);
1232     td0 = td1;
1233 
1234     /* calculate the freemem difference divided by the time diff
1235      * giving the freemem in that time sample
1236      *  (new - old) / (time_between_samples)
1237      */
1238     fmc = lsub(fm, fm_old);
1239     fm_old = fm;
1240 
1241     fmc = ldivide(fmc, denom);
1242     return  fmc.dl_lop;
1243 }
1244 
1245 /*
1246  * return # of processes currently executing on system
1247  */
1248 static int
kmet_get_nproc()1249 kmet_get_nproc()
1250 {
1251     uint32 *p;
1252     if ((p = (uint32 *)mas_get_met( md, PROCUSE, 0 )) == NULL )
1253     {
1254         (void)fprintf(stderr,"mas_get_met of procuse failed\n");
1255         mas_perror();
1256         quit(11);
1257     }
1258     nproc = (int)*p;
1259 }
1260 
1261 
1262 /*
1263  * Function: 	kmet_verify
1264  * renamed from mas_usrtime example verify_met() fm Doug Souders
1265  *
1266  * Description:	Verify the registration data associated with this metric
1267  *		match what are expected.  Cautious consumer applications
1268  *		should do this sort of verification before using metrics.
1269  */
1270 static void
kmet_verify(uint32 md,metid_t id,units_t units,type_t mettype,uint32 metsz,uint32 nobj,uint32 nlocs,resource_t res_id,uint32 ressz)1271 kmet_verify(
1272      uint32     md,         /* metric descriptor                */
1273      metid_t    id,         /* metric id number                 */
1274      units_t    units,      /* expected units of metric         */
1275      type_t     mettype,    /* expected type of metric          */
1276      uint32     metsz,      /* expected object size of metric   */
1277      uint32     nobj,       /* expected number of array elements */
1278      uint32     nlocs,      /* expected number of instances     */
1279      resource_t res_id,     /* expected resource id number      */
1280      uint32     ressz       /* expected resource object size    */
1281      )
1282 {
1283 
1284     char		*name;		/* the name of the metric 	*/
1285     units_t		*units_p;	/* the units of the metric	*/
1286     type_t		*mettype_p;	/* type field of the metric	*/
1287     uint32 		*objsz_p;	/* size of each element in met 	*/
1288     uint32 		*nobj_p;	/* num of elements >1 then array*/
1289     uint32 		*nlocs_p;	/* total number of instances	*/
1290     uint32 		*status_p;	/* status word (update|avail)	*/
1291     resource_t	        *resource_p;	/* the resource list of the met	*/
1292     uint32		*resval_p;	/* pointer to resource		*/
1293     uint32 		*ressz_p;	/* size of the resource met	*/
1294 
1295     if (!(name = mas_get_met_name( md, id )))
1296     {
1297             (void)fprintf(stderr,"mas_get_met_name failed\n");
1298             mas_perror();
1299             quit(11);
1300     }
1301 
1302     if (!(status_p = mas_get_met_status( md, id )))
1303     {
1304             (void)fprintf(stderr,"mas_get_met_status of %s failed\n",
1305                 name );
1306             mas_perror();
1307             quit(11);
1308     }
1309     if ( *status_p != MAS_AVAILABLE )
1310     {
1311         (void)fprintf(stderr,"unexpected status word for %s\n"
1312                                 "- expected %u got %u\n",
1313                 name, MAS_AVAILABLE, *status_p );
1314         quit(11);
1315     }
1316     if (!(units_p = mas_get_met_units( md, id )))
1317     {
1318             (void)fprintf(stderr,"mas_get_met_units of %s failed\n",
1319                 name );
1320             mas_perror();
1321             quit(11);
1322     }
1323     if (units != *units_p )
1324     {
1325             (void)fprintf(stderr,"unexpected units for %s\n"
1326                                     "- expected %u got %u\n",
1327                 name, units, *units_p );
1328             quit(11);
1329     }
1330 
1331     if (!(mettype_p = mas_get_met_type( md, id )))
1332     {
1333             (void)fprintf(stderr,"mas_get_met_type of %s failed\n",
1334                 name );
1335             mas_perror();
1336             quit(11);
1337     }
1338     if (mettype != *mettype_p )
1339     {
1340             (void)fprintf(stderr,"unexpected metric type for %s\n"
1341                                     "- expected %u got %u\n",
1342                 name, mettype , *mettype_p );
1343             quit(11);
1344     }
1345 
1346     if (!(objsz_p = mas_get_met_objsz( md, id )))
1347     {
1348             (void)fprintf(stderr,"mas_get_met_objsz of %s failed\n", name );
1349             mas_perror();
1350             quit(11);
1351     }
1352     if (*objsz_p != metsz )
1353     {
1354             (void)fprintf(stderr,"unexpected object size for %s\n"
1355                                     "- expected %u got %u\n",
1356                 name, metsz, *objsz_p );
1357             quit(11);
1358     }
1359 
1360     if (!(nobj_p = mas_get_met_nobj( md, id )))
1361     {
1362             (void)fprintf(stderr,"mas_get_met_nobj of %s failed\n", name );
1363             mas_perror();
1364             quit(11);
1365     }
1366     if (nobj != *nobj_p )
1367     {
1368         (void)fprintf(stderr,"unexpected number of objects for %s\n"
1369                                     "- expected %u got %u\n",
1370                 name, nobj, *nobj_p );
1371          quit(11);
1372     }
1373 
1374     /* get the number of instances that libmas thinks it knows about  */
1375     if (!(nlocs_p = mas_get_met_nlocs( md, id )))
1376     {
1377         (void)fprintf(stderr,"mas_get_met_nlocs of %s failed\n",  name );
1378         mas_perror();
1379         quit(11);
1380     }
1381     if (nlocs != *nlocs_p )
1382     {
1383         (void)fprintf(stderr,"unexpected number of instances for %s"
1384                         " - expected %u got %u\n",
1385                 name, nlocs, *nlocs_p );
1386         quit(11);
1387 
1388     }
1389     /*	get the resource list for the metric */
1390     if (!(resource_p = mas_get_met_resources( md, id )))
1391     {
1392         (void)fprintf(stderr,"mas_get_met_resources of %s failed\n", name );
1393         mas_perror();
1394         quit(11);
1395     }
1396     if (*resource_p != res_id )
1397     {
1398         (void)fprintf(stderr,"unexpected resource id for %s\n"
1399                                     "- expected %u got %u\n",
1400                 name, res_id, *resource_p);
1401         quit(11);
1402     }
1403     /*	get the size of the resource  */
1404     if (!(ressz_p = mas_get_met_objsz( md, (metid_t)(*resource_p) )))
1405     {
1406         (void)fprintf(stderr,"mas_get_met_objsz of resource failed\n");
1407         mas_perror();
1408         quit(11);
1409     }
1410     if (*ressz_p != ressz )
1411     {
1412         (void)fprintf(stderr,"unexpected resource size for %s\n"
1413                                     "- expected %u got %u\n",
1414                 name, ressz, *ressz_p );
1415         quit(11);
1416     }
1417 /*
1418  *	get the address of the resource
1419  */
1420     if (!(resval_p = (uint32 *)mas_get_met( md, *resource_p, 0 )))
1421     {
1422             (void)fprintf(stderr,"mas_get_met of resource failed\n");
1423             mas_perror();
1424             quit(11);
1425     }
1426     if (ressz == sizeof( short ) )
1427     {
1428         if( (uint32)(*(short *)resval_p) != nlocs )
1429         {
1430             (void)fprintf(stderr,"unexpected resource value for %s\n"
1431                                     "- expected %u got %u\n",
1432                         name, nlocs, (uint32)(*(short *)resval_p) );
1433             quit(11);
1434         }
1435     }
1436     else
1437     { /* assume size of uint32 */
1438         if (*resval_p != nlocs )
1439         {
1440             (void)fprintf(stderr,"unexpected resource value for %s\n"
1441                                     "- expected %u got %u\n",
1442                         name, nlocs, *resval_p );
1443             quit(11);
1444         }
1445     }
1446     return;
1447 }
1448 
1449