Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_svr5.c
blob35cc9746f8afc92d90ba839a05bfdfa826cfa76c
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.
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.
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.
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.
33 /*
34 * top - a top users display for Unix
36 * SYNOPSIS: For Intel based System V Release 5 (Unixware7)
38 * DESCRIPTION:
39 * System V release 5 for i[3456]86
40 * Works for:
41 * i586-sco-sysv5uw7 i386 SCO UNIX_SVR5 (UnixWare 7)
43 * LIBS: -lelf -lmas
45 * CFLAGS: -DHAVE_GETOPT -DORDER
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>
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
60 #define _KMEMUSER
61 #define prpsinfo psinfo
62 #include <sys/procfs.h>
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)
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>
90 #include "top.h"
91 #include "machine.h"
92 #include "utils.h"
94 #define UNIX "/stand/unix"
95 #define KMEM "/dev/kmem"
96 #define PROCFS "/proc"
97 #define CPUSTATES 5
99 #ifndef PRIO_MAX
100 #define PRIO_MAX 20
101 #endif
102 #ifndef PRIO_MIN
103 #define PRIO_MIN -20
104 #endif
106 #ifndef FSCALE
107 #define FSHIFT 8 /* bits to right of fixed binary point */
108 #define FSCALE (1<<FSHIFT)
109 #endif
111 #define loaddouble(x) ((double)x/FSCALE)
112 #define pagetok(size) ((size) * pagesz) >> LOG1024
114 /* definitions for the index in the nlist array */
115 #define X_AVENRUN 0
116 #define X_V 1
117 #define X_MPID 2
119 static struct nlist nlst[] =
121 {"avenrun"}, /* 0 */
122 {"v"}, /* 1 */
123 {"nextpid"}, /* 2 */
124 {NULL}
127 static unsigned long avenrun_offset;
128 static unsigned long mpid_offset;
130 static unsigned int pagesz;
132 static void reallocproc(int n);
133 static int maxprocs;
135 /* get_process_info passes back a handle. This is what it looks like: */
137 struct handle
139 struct prpsinfo **next_proc;/* points to next valid proc pointer */
140 int remaining; /* number of pointers remaining */
144 * These definitions control the format of the per-process area
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"
158 char *state_abbrev[] =
159 {"oncpu", "run", "sleep", "stop", "idle", "zombie"};
161 #define sZOMB 5
162 int process_states[8];
163 char *procstatenames[] =
165 " on cpu, ", " running, ", " sleeping, ", " stopped, ",
166 " idling ", " zombie, ",
167 NULL
170 int cpu_states[CPUSTATES];
171 char *cpustatenames[] =
172 {"idle", "user", "kernel", "wait", NULL};
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};
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};
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();
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 };
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;
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 ();
227 /* fwd dcls */
228 static int kmet_init(void );
229 static int get_cpustates(int *new);
233 machine_init (struct statics *statics)
235 static struct var v;
236 int i;
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;
244 /* get the list of symbols we want to access in the kernel */
245 if (nlist (UNIX, nlst))
247 (void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
248 return (-1);
251 /* make sure they were all found */
252 if (check_nlist (nlst) > 0)
253 return (-1);
255 /* open kernel memory */
256 if ((kmem = open (KMEM, O_RDONLY)) == -1)
258 perror (KMEM);
259 return (-1);
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;
269 /* stash away certain offsets for later use */
270 mpid_offset = nlst[X_MPID].n_value;
271 avenrun_offset = nlst[X_AVENRUN].n_value;
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 *));
278 pagesz = sysconf(_SC_PAGESIZE);
281 /* Just in case ... */
282 if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
284 (void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
285 return (-1);
288 if (!(procdir = opendir (PROCFS)))
290 (void) fprintf (stderr, "Unable to open %s\n", PROCFS);
291 return (-1);
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);
301 kmet_init();
303 /* all done! */
304 return (0);
307 char *
308 format_header (char *uname_field)
310 register char *ptr;
312 ptr = header + UNAME_START;
313 while (*uname_field != '\0')
314 *ptr++ = *uname_field++;
316 return (header);
319 void
320 get_system_info (struct system_info *si)
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];
331 get_cpustates(new_states);
333 /* convert cp_time counts to percentages */
334 (void) percentages (CPUSTATES, cpu_states, new_states, cp_old, cp_diff);
337 si->last_pid = -1;
338 /* get mpid -- process id of last process
339 * svr5 is nextpid - next pid to be assigned (already incremented)
341 (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
342 "nextpid");
343 (si->last_pid)--; /* so we shld decrement for display */
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]);
352 mem = sysconf(_SC_TOTAL_MEMORY); /* physical mem */
353 memory_stats[0] = pagetok (mem);
355 mem = kmet_get_freemem(); /* free mem */
356 memory_stats[2] = pagetok (mem);
358 /* mem = sysconf(_SC_GENERAL_MEMORY); */
359 memory_stats[1] = memory_stats[0] - memory_stats[2]; /* active */
361 get_swapinfo(&swap_total, &swap_free);
362 memory_stats[3] = pagetok(swap_total - swap_free);
363 memory_stats[4] = pagetok(swap_free);
366 /* set arrays and strings */
367 si->cpustates = cpu_states;
368 si->memory = memory_stats;
371 static struct handle handle;
373 caddr_t
374 get_process_info (
375 struct system_info *si,
376 struct process_select *sel,
377 int idx)
379 register int i;
380 register int total_procs;
381 register int active_procs;
382 register struct prpsinfo **prefp;
383 register struct prpsinfo *pp;
385 /* these are copied out of sel for speed */
386 int show_idle;
387 int show_system;
388 int show_uid;
390 /* Get current number of processes */
392 /* read all the proc structures */
393 getptable (pbase);
395 /* get a pointer to the states summary array */
396 si->procstates = process_states;
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;
403 nproc = kmet_get_nproc();
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;
411 for (pp = pbase, i = 0; i < nproc; pp++, i++)
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.
419 if ((pp->pr_state >= SONPROC && pp->pr_state <= SIDL) &&
420 (show_system || ((pp->pr_flag & PR_ISSYS) == 0)))
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))
428 *prefp++ = pp;
429 active_procs++;
431 if (ZOMBIE(pp))
432 process_states[sZOMB]++; /* invented */
437 /* if requested, sort the "interesting" processes */
438 qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *),
439 proc_compares[idx]);
441 /* remember active and total counts */
442 si->p_total = total_procs;
443 si->P_ACTIVE = active_procs;
445 /* pass back a handle */
446 handle.next_proc = pref;
447 handle.remaining = active_procs;
448 return ((caddr_t) & handle);
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
456 static double percent_cpu( struct prpsinfo *pp)
458 static time_t tim = 0L;
459 time_t starttime;
460 time_t ctime;
461 time_t etime;
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)
474 /* return (float)(ctime * 100) / (unsigned)etime; */
475 /* this was ocasionally giving vals >100 for some
476 * unknown reason so the below normalises it
479 double pct;
480 pct = (float)(ctime * 100) / (unsigned)etime;
481 return (pct < 100.0) ? pct : 100.00;
483 return 0.00;
487 char fmt[MAX_COLS]; /* static area where result is built */
489 char *
490 format_next_process (
491 caddr_t handle,
492 char *(*get_userid) ())
494 register struct prpsinfo *pp;
495 struct handle *hp;
496 register long cputime;
497 register double pctcpu;
499 /* find and remember the next proc structure */
500 hp = (struct handle *) handle;
501 pp = *(hp->next_proc++);
502 hp->remaining--;
504 /* get the cpu usage and calculate the cpu percentages */
505 cputime = pp->pr_time.tv_sec;
506 pctcpu = percent_cpu(pp);
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));
528 /* return the result */
529 return (fmt);
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.
539 check_nlist (register struct nlist *nlst)
541 register int i;
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 */
546 i = 0;
547 while (nlst->n_name != NULL)
549 if (nlst->n_value == 0)
551 /* this one wasn't found */
552 (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
553 i = 1;
555 nlst++;
557 return (i);
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).
573 getkval (
574 unsigned long offset,
575 int *ptr,
576 int size,
577 char *refstr)
579 if (lseek (kmem, (long) offset, 0) == -1)
581 if (*refstr == '!')
582 refstr++;
583 (void) fprintf (stderr, "%s: lseek to %s: %s\n",
584 myname, refstr, sys_errlist[errno]);
585 quit (22);
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
593 (void) fprintf (stderr, "%s: reading %s: %s\n",
594 myname, refstr, sys_errlist[errno]);
595 quit (23);
597 return (1);
600 /* ----------------- comparison routines for qsort ---------------- */
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.
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)
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)
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)
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)
624 /* states enum {SONPROC, SRUN, SSLEEP, SSTOP, SIDL} */
625 unsigned char sorted_state[] =
627 7, /* onproc */
628 6, /* run */
629 5, /* sleep */
630 4, /* stop */
631 3, /* idle */
632 2, /* zombie */
633 0, /* unused */
634 0 /* unused */
637 #if 0
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.
648 /* default comparison rtn */
650 original_proc_compare (
651 struct prpsinfo **pp1,
652 struct prpsinfo **pp2)
654 register struct prpsinfo *p1;
655 register struct prpsinfo *p2;
656 register long result;
657 double dresult;
659 /* remove one level of indirection */
660 p1 = *pp1;
661 p2 = *pp2;
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)
669 /* use cpticks to break the tie */
670 if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
672 /* use process state to break the tie */
673 if ((result = (long) (sorted_state[p2->pr_state] -
674 sorted_state[p1->pr_state])) == 0)
676 /* use priority to break the tie */
677 if ((result = p2->pr_pri - p1->pr_pri) == 0)
679 /* use resident set size (rssize) to break the tie */
680 if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
682 /* use total memory to break the tie */
683 result = (p2->pr_size - p1->pr_size);
689 return (result);
691 #endif /* original comparison rtn */
693 /* compare_state - comparison function for sorting by state,pri,time,size */
695 proc_compare (
696 struct prpsinfo **pp1,
697 struct prpsinfo **pp2)
699 register struct prpsinfo *p1;
700 register struct prpsinfo *p2;
701 register long result;
702 double dresult;
704 /* remove one level of indirection */
705 p1 = *pp1;
706 p2 = *pp2;
708 ORDERKEY_STATE
709 ORDERKEY_PRIO
710 ORDERKEY_CPTICKS
711 ORDERKEY_RSSIZE
712 ORDERKEY_MEM
713 ORDERKEY_PCTCPU
716 return (result);
720 /* compare_cpu - the comparison function for sorting by cpu % (deflt) */
722 compare_cpu (
723 struct prpsinfo **pp1,
724 struct prpsinfo **pp2)
726 register struct prpsinfo *p1;
727 register struct prpsinfo *p2;
728 register long result;
729 double dresult;
731 /* remove one level of indirection */
732 p1 = *pp1;
733 p2 = *pp2;
735 ORDERKEY_PCTCPU
736 ORDERKEY_CPTICKS
737 ORDERKEY_STATE
738 ORDERKEY_PRIO
739 ORDERKEY_RSSIZE
740 ORDERKEY_MEM
743 return (result);
746 /* compare_size - the comparison function for sorting by total memory usage */
748 compare_size (
749 struct prpsinfo **pp1,
750 struct prpsinfo **pp2)
752 register struct prpsinfo *p1;
753 register struct prpsinfo *p2;
754 register long result;
755 double dresult;
757 /* remove one level of indirection */
758 p1 = *pp1;
759 p2 = *pp2;
761 ORDERKEY_MEM
762 ORDERKEY_RSSIZE
763 ORDERKEY_PCTCPU
764 ORDERKEY_CPTICKS
765 ORDERKEY_STATE
766 ORDERKEY_PRIO
769 return (result);
772 /* compare_res - the comparison function for sorting by resident set size */
774 compare_res (
775 struct prpsinfo **pp1,
776 struct prpsinfo **pp2)
778 register struct prpsinfo *p1;
779 register struct prpsinfo *p2;
780 register long result;
781 double dresult;
783 /* remove one level of indirection */
784 p1 = *pp1;
785 p2 = *pp2;
787 ORDERKEY_RSSIZE
788 ORDERKEY_MEM
789 ORDERKEY_PCTCPU
790 ORDERKEY_CPTICKS
791 ORDERKEY_STATE
792 ORDERKEY_PRIO
795 return (result);
798 /* compare_time - the comparison function for sorting by total cpu time */
800 compare_time (
801 struct prpsinfo **pp1,
802 struct prpsinfo **pp2)
804 register struct prpsinfo *p1;
805 register struct prpsinfo *p2;
806 register long result;
807 double dresult;
809 /* remove one level of indirection */
810 p1 = *pp1;
811 p2 = *pp2;
813 ORDERKEY_CPTICKS
814 ORDERKEY_PCTCPU
815 ORDERKEY_STATE
816 ORDERKEY_PRIO
817 ORDERKEY_MEM
818 ORDERKEY_RSSIZE
821 return (result);
824 /* compare_pid - the comparison function for sorting by pid */
826 compare_pid (
827 struct prpsinfo **pp1,
828 struct prpsinfo **pp2)
830 register struct prpsinfo *p1;
831 register struct prpsinfo *p2;
832 register long result;
833 double dresult;
835 /* remove one level of indirection */
836 p1 = *pp1;
837 p2 = *pp2;
839 ORDERKEY_PID
840 ORDERKEY_CPTICKS
841 ORDERKEY_PCTCPU
842 ORDERKEY_STATE
843 ORDERKEY_PRIO
844 ORDERKEY_MEM
845 ORDERKEY_RSSIZE
848 return (result);
851 /* compare_uid - the comparison function for sorting by user ID */
853 compare_uid (
854 struct prpsinfo **pp1,
855 struct prpsinfo **pp2)
857 register struct prpsinfo *p1;
858 register struct prpsinfo *p2;
859 register long result;
860 double dresult;
862 /* remove one level of indirection */
863 p1 = *pp1;
864 p2 = *pp2;
866 ORDERKEY_UID
867 ORDERKEY_CPTICKS
868 ORDERKEY_PCTCPU
869 ORDERKEY_STATE
870 ORDERKEY_PRIO
871 ORDERKEY_MEM
872 ORDERKEY_RSSIZE
875 return (result);
878 /* compare_rpid - the comparison function for sorting by pid ascending */
880 compare_rpid (
881 struct prpsinfo **pp1,
882 struct prpsinfo **pp2)
884 register struct prpsinfo *p1;
885 register struct prpsinfo *p2;
886 register long result;
887 double dresult;
889 /* remove one level of indirection */
890 p1 = *pp1;
891 p2 = *pp2;
893 ORDERKEY_RPID
894 ORDERKEY_CPTICKS
895 ORDERKEY_PCTCPU
896 ORDERKEY_STATE
897 ORDERKEY_PRIO
898 ORDERKEY_MEM
899 ORDERKEY_RSSIZE
902 return (result);
905 /* compare_uid - the comparison function for sorting by user ID ascending */
907 compare_ruid (
908 struct prpsinfo **pp1,
909 struct prpsinfo **pp2)
911 register struct prpsinfo *p1;
912 register struct prpsinfo *p2;
913 register long result;
914 double dresult;
916 /* remove one level of indirection */
917 p1 = *pp1;
918 p2 = *pp2;
920 ORDERKEY_RUID
921 ORDERKEY_CPTICKS
922 ORDERKEY_PCTCPU
923 ORDERKEY_STATE
924 ORDERKEY_PRIO
925 ORDERKEY_MEM
926 ORDERKEY_RSSIZE
929 return (result);
933 /* ---------------- helper rtns ---------------- */
936 * get process table
938 void
939 getptable (struct prpsinfo *baseptr)
941 struct prpsinfo *currproc; /* pointer to current proc structure */
942 int numprocs = 0;
943 struct dirent *direntp;
945 currproc = baseptr;
946 for (rewinddir (procdir); direntp = readdir (procdir);)
948 int fd;
949 char buf[30];
951 sprintf(buf,"%s/psinfo", direntp->d_name);
953 if ((fd = open (buf, O_RDONLY)) < 0)
954 continue;
956 if (read(fd, currproc, sizeof(psinfo_t)) != sizeof(psinfo_t))
958 (void) close (fd);
959 continue;
962 numprocs++;
963 currproc++;
965 (void) close (fd);
967 /* Atypical place for growth */
968 if (numprocs >= maxprocs)
970 reallocproc(2 * numprocs);
971 currproc = (struct prpsinfo *)
972 ((char *)baseptr + sizeof(psinfo_t) * numprocs);
977 if (nproc != numprocs)
978 nproc = numprocs;
981 /* return the owner of the specified process, for use in commands.c as we're
982 running setuid root */
984 proc_owner (int pid)
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));
992 return (-1);
996 setpriority (int dummy, int who, int niceval)
998 int scale;
999 int prio;
1000 pcinfo_t pcinfo;
1001 pcparms_t pcparms;
1002 tsparms_t *tsparms;
1004 strcpy (pcinfo.pc_clname, "TS");
1005 if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
1006 return (-1);
1008 prio = niceval;
1009 if (prio > PRIO_MAX)
1010 prio = PRIO_MAX;
1011 else if (prio < PRIO_MIN)
1012 prio = PRIO_MIN;
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;
1019 if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
1020 return (-1);
1022 return (0);
1026 get_swapinfo(long *total, long *fr)
1028 register int cnt, i;
1029 register long t, f;
1030 struct swaptable *swt;
1031 struct swapent *ste;
1032 static char path[256];
1034 /* get total number of swap entries */
1035 cnt = swapctl(SC_GETNSWP, 0);
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)
1042 *total = 0;
1043 *fr = 0;
1044 return;
1046 swt->swt_n = cnt;
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)
1054 ste++->ste_path = path;
1057 /* grab all swap info */
1058 swapctl(SC_LIST, swt);
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)
1066 /* dont count slots being deleted */
1067 if (!(ste->ste_flags & ST_INDEL) )
1069 t += ste->ste_pages;
1070 f += ste->ste_free;
1072 ste++;
1075 /* fill in the results */
1076 *total = t;
1077 *fr = f;
1078 free(swt);
1083 * When we reach a proc limit, we need to realloc the stuff.
1085 static void reallocproc(int n)
1087 int bytes;
1088 struct oldproc *op, *endbase;
1090 if (n < maxprocs)
1091 return;
1093 maxprocs = n;
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 *));
1101 /* Just in case ... */
1102 if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
1104 fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
1105 quit(1);
1109 /* ---------------------------------------------------------------- */
1110 /* Access kernel Metrics
1111 * SVR5 uses metreg inteface to Kernel statistics (metrics)
1112 * see /usr/include/mas.h, /usr/include/metreg.h
1115 #include <sys/mman.h>
1116 #include <sys/dl.h>
1117 #include <mas.h>
1118 #include <metreg.h>
1120 static int md; /* metric descriptor handle */
1121 static uint32 ncpu; /* number of processors in system */
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 ) ;
1131 static int get_cpustates(int *new)
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");
1140 /* initialises kernel metrics access and gets #cpus */
1141 static int kmet_init()
1143 uint32 *ncpu_p;
1145 /* open (and map in) the metric access file and assoc data structures */
1146 if( ( md = mas_open( MAS_FILE, MAS_MMAP_ACCESS ) ) < 0 )
1148 (void)fprintf(stderr,"mas_open failed\n");
1149 mas_perror();
1150 quit(10);
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) );
1157 /* get the number of cpu's on the system */
1158 if( (ncpu_p = (uint32 *)mas_get_met( md, NCPU, 0 )) == NULL )
1160 (void)fprintf(stderr,"mas_get_met of ncpu failed\n");
1161 mas_perror();
1162 quit(12);
1164 ncpu = (uint32)(*(short *)ncpu_p);
1166 /* check that MPC_CPU_IDLE is of the form we expect
1167 * ( paranoically we should check the rest as well but ... )
1169 kmet_verify( md, MPC_CPU_IDLE, TIX, PROFILE, sizeof(uint32),
1170 1, ncpu, NCPU, sizeof(short) );
1172 kmet_verify( md, PROCUSE, PROCESSES, COUNT, sizeof(uint32),
1173 1, 1, MAS_SYSTEM, sizeof(uint32) );
1174 nproc = kmet_get_nproc();
1176 return 0;
1179 /* done with kernel metrics access */
1180 static int
1181 kmet_done()
1183 if ( mas_close( md ) < 0 )
1185 (void)fprintf(stderr,"mas_close failed\n");
1186 mas_perror();
1187 quit(14);
1192 static uint32
1193 kmet_get_cpu( int type, char *desc)
1195 int i;
1196 uint32 r=0, rtot=0 ;
1198 for (i=0; i <ncpu; i++)
1200 r=*(uint32 *)mas_get_met( md, (metid_t)type, 0 );
1201 if ( !r)
1203 (void)fprintf(stderr,"mas_get_met of %s failed\n", desc);
1204 mas_perror();
1205 quit(12);
1207 rtot += r; /* sum them for multi cpus */
1209 return rtot /* /ncpu */ ;
1212 static int
1213 kmet_get_freemem()
1215 dl_t *fm_p, fm, fmc, denom;
1216 time_t td1;
1217 static time_t td0;
1218 static dl_t fm_old;
1221 td1 = time(NULL);
1222 if ((fm_p = (dl_t *)mas_get_met( md, FREEMEM, 0 )) == NULL )
1224 (void)fprintf(stderr,"mas_get_met of freemem failed\n");
1225 mas_perror();
1226 quit(12);
1228 fm = *fm_p;
1230 denom.dl_hop = 0;
1231 denom.dl_lop = (long) (td1 - td0);
1232 td0 = td1;
1234 /* calculate the freemem difference divided by the time diff
1235 * giving the freemem in that time sample
1236 * (new - old) / (time_between_samples)
1238 fmc = lsub(fm, fm_old);
1239 fm_old = fm;
1241 fmc = ldivide(fmc, denom);
1242 return fmc.dl_lop;
1246 * return # of processes currently executing on system
1248 static int
1249 kmet_get_nproc()
1251 uint32 *p;
1252 if ((p = (uint32 *)mas_get_met( md, PROCUSE, 0 )) == NULL )
1254 (void)fprintf(stderr,"mas_get_met of procuse failed\n");
1255 mas_perror();
1256 quit(11);
1258 nproc = (int)*p;
1263 * Function: kmet_verify
1264 * renamed from mas_usrtime example verify_met() fm Doug Souders
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.
1270 static void
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 */
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 */
1295 if (!(name = mas_get_met_name( md, id )))
1297 (void)fprintf(stderr,"mas_get_met_name failed\n");
1298 mas_perror();
1299 quit(11);
1302 if (!(status_p = mas_get_met_status( md, id )))
1304 (void)fprintf(stderr,"mas_get_met_status of %s failed\n",
1305 name );
1306 mas_perror();
1307 quit(11);
1309 if ( *status_p != MAS_AVAILABLE )
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);
1316 if (!(units_p = mas_get_met_units( md, id )))
1318 (void)fprintf(stderr,"mas_get_met_units of %s failed\n",
1319 name );
1320 mas_perror();
1321 quit(11);
1323 if (units != *units_p )
1325 (void)fprintf(stderr,"unexpected units for %s\n"
1326 "- expected %u got %u\n",
1327 name, units, *units_p );
1328 quit(11);
1331 if (!(mettype_p = mas_get_met_type( md, id )))
1333 (void)fprintf(stderr,"mas_get_met_type of %s failed\n",
1334 name );
1335 mas_perror();
1336 quit(11);
1338 if (mettype != *mettype_p )
1340 (void)fprintf(stderr,"unexpected metric type for %s\n"
1341 "- expected %u got %u\n",
1342 name, mettype , *mettype_p );
1343 quit(11);
1346 if (!(objsz_p = mas_get_met_objsz( md, id )))
1348 (void)fprintf(stderr,"mas_get_met_objsz of %s failed\n", name );
1349 mas_perror();
1350 quit(11);
1352 if (*objsz_p != metsz )
1354 (void)fprintf(stderr,"unexpected object size for %s\n"
1355 "- expected %u got %u\n",
1356 name, metsz, *objsz_p );
1357 quit(11);
1360 if (!(nobj_p = mas_get_met_nobj( md, id )))
1362 (void)fprintf(stderr,"mas_get_met_nobj of %s failed\n", name );
1363 mas_perror();
1364 quit(11);
1366 if (nobj != *nobj_p )
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);
1374 /* get the number of instances that libmas thinks it knows about */
1375 if (!(nlocs_p = mas_get_met_nlocs( md, id )))
1377 (void)fprintf(stderr,"mas_get_met_nlocs of %s failed\n", name );
1378 mas_perror();
1379 quit(11);
1381 if (nlocs != *nlocs_p )
1383 (void)fprintf(stderr,"unexpected number of instances for %s"
1384 " - expected %u got %u\n",
1385 name, nlocs, *nlocs_p );
1386 quit(11);
1389 /* get the resource list for the metric */
1390 if (!(resource_p = mas_get_met_resources( md, id )))
1392 (void)fprintf(stderr,"mas_get_met_resources of %s failed\n", name );
1393 mas_perror();
1394 quit(11);
1396 if (*resource_p != res_id )
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);
1403 /* get the size of the resource */
1404 if (!(ressz_p = mas_get_met_objsz( md, (metid_t)(*resource_p) )))
1406 (void)fprintf(stderr,"mas_get_met_objsz of resource failed\n");
1407 mas_perror();
1408 quit(11);
1410 if (*ressz_p != ressz )
1412 (void)fprintf(stderr,"unexpected resource size for %s\n"
1413 "- expected %u got %u\n",
1414 name, ressz, *ressz_p );
1415 quit(11);
1418 * get the address of the resource
1420 if (!(resval_p = (uint32 *)mas_get_met( md, *resource_p, 0 )))
1422 (void)fprintf(stderr,"mas_get_met of resource failed\n");
1423 mas_perror();
1424 quit(11);
1426 if (ressz == sizeof( short ) )
1428 if( (uint32)(*(short *)resval_p) != nlocs )
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);
1436 else
1437 { /* assume size of uint32 */
1438 if (*resval_p != nlocs )
1440 (void)fprintf(stderr,"unexpected resource value for %s\n"
1441 "- expected %u got %u\n",
1442 name, nlocs, *resval_p );
1443 quit(11);
1446 return;