Home | History | Annotate | Line # | Download | only in machine
      1 /*
      2  * top - a top users display for Unix
      3  *
      4  * SYNOPSIS:  Any Sun running SunOS 5.x (Solaris 2.x)
      5  *
      6  * DESCRIPTION:
      7  * This is the machine-dependent module for SunOS 5.x (Solaris 2).
      8  * There is some support for MP architectures.
      9  * This makes top work on all revisions of SunOS 5 from 5.0
     10  * through 5.9 (otherwise known as Solaris 9).  It has not been
     11  * tested on SunOS 5.10.
     12  *
     13  * AUTHORS:      Torsten Kasch 		<torsten (at) techfak.uni-bielefeld.de>
     14  *               Robert Boucher		<boucher (at) sofkin.ca>
     15  * CONTRIBUTORS: Marc Cohen 		<marc (at) aai.com>
     16  *               Charles Hedrick 	<hedrick (at) geneva.rutgers.edu>
     17  *	         William L. Jones 	<jones@chpc>
     18  *               Petri Kutvonen         <kutvonen (at) cs.helsinki.fi>
     19  *	         Casper Dik             <casper.dik (at) sun.com>
     20  *               Tim Pugh               <tpugh (at) oce.orst.edu>
     21  */
     22 
     23 #define _KMEMUSER
     24 
     25 #include "os.h"
     26 #include "utils.h"
     27 #include "username.h"
     28 #include "display.h"
     29 
     30 #if (OSREV == 551)
     31 #undef OSREV
     32 #define OSREV 55
     33 #endif
     34 
     35 /*
     36  * Starting with SunOS 5.6 the data in /proc changed along with the
     37  * means by which it is accessed.  In this case we define USE_NEW_PROC.
     38  * Note that with USE_NEW_PROC defined the structure named "prpsinfo"
     39  * is redefined to be "psinfo".  This will be confusing as you read
     40  * the code.
     41  */
     42 
     43 #if OSREV >= 56
     44 #define USE_NEW_PROC
     45 #endif
     46 
     47 #if defined(USE_NEW_PROC)
     48 #define _STRUCTURED_PROC 1
     49 #define prpsinfo psinfo
     50 #include <sys/procfs.h>
     51 #define pr_fill pr_nlwp
     52 /* the "px" macros are used where the actual member could be in a substructure */
     53 #define px_state pr_lwp.pr_state
     54 #define px_nice pr_lwp.pr_nice
     55 #define px_pri pr_lwp.pr_pri
     56 #define px_onpro pr_lwp.pr_onpro
     57 #define ZOMBIE(p)	((p)->pr_nlwp == 0)
     58 #define SIZE_K(p)	(long)((p)->pr_size)
     59 #define RSS_K(p)	(long)((p)->pr_rssize)
     60 #else
     61 #define px_state pr_state
     62 #define px_oldpri pr_oldpri
     63 #define px_nice pr_nice
     64 #define px_pri pr_pri
     65 #define px_onpro pr_filler[5]
     66 #define ZOMBIE(p)	((p)->pr_zomb)
     67 #define SIZE_K(p)	(long)((p)->pr_bysize/1024)
     68 #define RSS_K(p)	(long)((p)->pr_byrssize/1024)
     69 #endif
     70 
     71 #include "top.h"
     72 #include "machine.h"
     73 #include <limits.h>
     74 #include <stdio.h>
     75 #include <fcntl.h>
     76 #include <unistd.h>
     77 #include <stdlib.h>
     78 #include <errno.h>
     79 #include <dirent.h>
     80 #include <nlist.h>
     81 #include <string.h>
     82 #include <kvm.h>
     83 #include <signal.h>
     84 #include <sys/types.h>
     85 #include <sys/param.h>
     86 #include <sys/signal.h>
     87 #include <sys/fault.h>
     88 #include <sys/sysinfo.h>
     89 #include <sys/sysmacros.h>
     90 #include <sys/syscall.h>
     91 #include <sys/user.h>
     92 #include <sys/proc.h>
     93 #include <sys/procfs.h>
     94 #include <sys/vm.h>
     95 #include <sys/var.h>
     96 #include <sys/cpuvar.h>
     97 #include <sys/file.h>
     98 #include <sys/time.h>
     99 #include <sys/priocntl.h>
    100 #include <sys/tspriocntl.h>
    101 #include <sys/processor.h>
    102 #include <sys/resource.h>
    103 #include <sys/swap.h>
    104 #include <sys/stat.h>
    105 #include <vm/anon.h>
    106 #include <math.h>
    107 #include <utmpx.h>
    108 #include "utils.h"
    109 #include "hash.h"
    110 
    111 #if OSREV >= 53
    112 #define USE_KSTAT
    113 #endif
    114 #ifdef USE_KSTAT
    115 #include <kstat.h>
    116 /*
    117  * Some kstats are fixed at 32 bits, these will be specified as ui32; some
    118  * are "natural" size (32 bit on 32 bit Solaris, 64 on 64 bit Solaris
    119  * we'll make those unsigned long)
    120  * Older Solaris doesn't define KSTAT_DATA_UINT32, those are always 32 bit.
    121  */
    122 # ifndef KSTAT_DATA_UINT32
    123 #  define ui32 ul
    124 # endif
    125 #endif
    126 
    127 #define UNIX "/dev/ksyms"
    128 #define KMEM "/dev/kmem"
    129 #define PROCFS "/proc"
    130 #define CPUSTATES     5
    131 #ifndef PRIO_MIN
    132 #define PRIO_MIN	-20
    133 #endif
    134 #ifndef PRIO_MAX
    135 #define PRIO_MAX	20
    136 #endif
    137 
    138 #ifndef FSCALE
    139 #define FSHIFT  8		/* bits to right of fixed binary point */
    140 #define FSCALE  (1<<FSHIFT)
    141 #endif /* FSCALE */
    142 
    143 #define loaddouble(la) ((double)(la) / FSCALE)
    144 #define dbl_align(x)	(((unsigned long)(x)+(sizeof(double)-1)) & \
    145 						~(sizeof(double)-1))
    146 
    147 /*
    148  * SunOS 5.4 and above track pctcpu in the proc structure as pr_pctcpu.
    149  * These values are weighted over one minute whereas top output prefers
    150  * a near-instantaneous measure of cpu utilization.  So we choose to
    151  * ignore pr_pctcpu: we calculate our own cpu percentage and store it in
    152  * one of the spare slots in the prinfo structure.
    153  */
    154 
    155 #define percent_cpu(pp) (*(double *)dbl_align(&pp->pr_filler[0]))
    156 
    157 /* definitions for indices in the nlist array */
    158 #define X_V			 0
    159 #define X_MPID			 1
    160 #define X_ANONINFO		 2
    161 #define X_MAXMEM		 3
    162 #define X_FREEMEM		 4
    163 #define X_AVENRUN		 5
    164 #define X_CPU			 6
    165 #define X_NPROC			 7
    166 #define X_NCPUS		   	 8
    167 
    168 static struct nlist nlst[] =
    169 {
    170   {"v"},			/* 0 */	/* replaced by dynamic allocation */
    171   {"mpid"},			/* 1 */
    172 #if OSREV >= 56
    173   /* this structure really has some extra fields, but the first three match */
    174   {"k_anoninfo"},		/* 2 */
    175 #else
    176   {"anoninfo"},			/* 2 */
    177 #endif
    178   {"maxmem"},			/* 3 */ /* use sysconf */
    179   {"freemem"},			/* 4 */	/* available from kstat >= 2.5 */
    180   {"avenrun"},			/* 5 */ /* available from kstat */
    181   {"cpu"},			/* 6 */ /* available from kstat */
    182   {"nproc"},			/* 7 */ /* available from kstat */
    183   {"ncpus"},			/* 8 */ /* available from kstat */
    184   {0}
    185 };
    186 
    187 static unsigned long avenrun_offset;
    188 static unsigned long mpid_offset;
    189 #ifdef USE_KSTAT
    190 static kstat_ctl_t *kc = NULL;
    191 static kid_t kcid = 0;
    192 #else
    193 static unsigned long *cpu_offset;
    194 #endif
    195 static unsigned long nproc_offset;
    196 static unsigned long freemem_offset;
    197 static unsigned long maxmem_offset;
    198 static unsigned long anoninfo_offset;
    199 static int maxfiles = 256;
    200 #define MAXFILES 2048
    201 static int *display_fields;
    202 static int show_threads = 0;
    203 static int show_fullcmd;
    204 
    205 /* get_process_info passes back a handle.  This is what it looks like: */
    206 struct handle
    207 {
    208     struct prpsinfo **next_proc;/* points to next valid proc pointer */
    209     int remaining;		/* number of pointers remaining */
    210 };
    211 
    212 /*
    213  * Structure for keeping track processes between updates.
    214  * We keep these things in a hash table, which is updated at every cycle.
    215  */
    216 struct oldproc
    217 {
    218     pid_t pid;
    219     id_t lwpid;
    220     double oldtime;
    221     double oldpct;
    222     uid_t  owner_uid;
    223     int fd_psinfo;
    224     int fd_lpsinfo;
    225     int seen;
    226 };
    227 
    228 #define TIMESPEC_TO_DOUBLE(ts) ((ts).tv_sec * 1.0e9 + (ts).tv_nsec)
    229 
    230 hash_table *prochash;
    231 hash_table *threadhash;
    232 
    233 /*
    234  * Structure for tracking per-cpu information
    235  */
    236 struct cpustats
    237 {
    238     unsigned int states[CPUSTATES];
    239     uint_t pswitch;
    240     uint_t trap;
    241     uint_t intr;
    242     uint_t syscall;
    243     uint_t sysfork;
    244     uint_t sysvfork;
    245     uint_t pfault;
    246     uint_t pgin;
    247     uint_t pgout;
    248 };
    249 
    250 /*
    251  * GCC assumes that all doubles are aligned.  Unfortunately it
    252  * doesn't round up the structure size to be a multiple of 8.
    253  * Thus we'll get a coredump when going through array.  The
    254  * following is a size rounded up to 8.
    255  */
    256 #define PRPSINFOSIZE dbl_align(sizeof(struct prpsinfo))
    257 
    258 /* this defines one field (or column) in the process display */
    259 
    260 struct proc_field {
    261     char *name;
    262     int width;
    263     int rjust;
    264     int min_screenwidth;
    265     int (*format)(char *, int, struct prpsinfo *);
    266 };
    267 
    268 #define PROCSTATES 8
    269 /* process state names for the "STATE" column of the display */
    270 char *state_abbrev[] =
    271 {"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
    272 
    273 int process_states[PROCSTATES];
    274 char *procstatenames[] =
    275 {
    276   "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
    277   " starting, ", " on cpu, ", " swapped, ",
    278   NULL
    279 };
    280 
    281 int cpu_states[CPUSTATES];
    282 char *cpustatenames[] =
    283 {"idle", "user", "kernel", "iowait", "swap", NULL};
    284 #define CPUSTATE_IOWAIT 3
    285 #define CPUSTATE_SWAP   4
    286 
    287 
    288 /* these are for detailing the memory statistics */
    289 long memory_stats[5];
    290 char *memorynames[] =
    291 {"K phys mem, ", "K free mem, ", "K total swap, ", "K free swap", NULL};
    292 #define MEMORY_TOTALMEM  0
    293 #define MEMORY_FREEMEM   1
    294 #define MEMORY_TOTALSWAP 2
    295 #define MEMORY_FREESWAP  3
    296 
    297 /* these are for detailing kernel statistics */
    298 int kernel_stats[8];
    299 char *kernelnames[] =
    300 {" ctxsw, ", " trap, ", " intr, ", " syscall, ", " fork, ",
    301  " flt, ", " pgin, ", " pgout, ", NULL};
    302 #define KERNEL_CSWITCH 0
    303 #define KERNEL_TRAP 1
    304 #define KERNEL_INTR 2
    305 #define KERNEL_SYSCALL 3
    306 #define KERNEL_FORK 4
    307 #define KERNEL_PFAULT 5
    308 #define KERNEL_PGIN 6
    309 #define KERNEL_PGOUT 7
    310 
    311 /* these are names given to allowed sorting orders -- first is default */
    312 char *ordernames[] =
    313 {"cpu", "size", "res", "time", "pid", NULL};
    314 
    315 /* forward definitions for comparison functions */
    316 int compare_cpu();
    317 int compare_size();
    318 int compare_res();
    319 int compare_time();
    320 int compare_pid();
    321 
    322 int (*proc_compares[])() = {
    323     compare_cpu,
    324     compare_size,
    325     compare_res,
    326     compare_time,
    327     compare_pid,
    328     NULL };
    329 
    330 kvm_t *kd;
    331 static DIR *procdir;
    332 
    333 /* "cpucount" is used to store the value for the kernel variable "ncpus".
    334    But since <sys/cpuvar.h> actually defines a variable "ncpus" we need
    335    to use a different name here.   --wnl */
    336 static int cpucount;
    337 
    338 /* pagetok function is really a pointer to an appropriate function */
    339 static int pageshift;
    340 static long (*p_pagetok) ();
    341 #define pagetok(size) ((*p_pagetok)(size))
    342 
    343 /* useful externals */
    344 extern char *myname;
    345 extern void perror ();
    346 extern int getptable ();
    347 extern void quit ();
    348 
    349 /* process formatting functions and data */
    350 
    351 int
    352 fmt_pid(char *buf, int sz, struct prpsinfo *pp)
    353 
    354 {
    355     return snprintf(buf, sz, "%6d", (int)pp->pr_pid);
    356 }
    357 
    358 int
    359 fmt_username(char *buf, int sz, struct prpsinfo *pp)
    360 
    361 {
    362     return snprintf(buf, sz, "%-8.8s", username(pp->pr_uid));
    363 }
    364 
    365 int
    366 fmt_uid(char *buf, int sz, struct prpsinfo *pp)
    367 
    368 {
    369     return snprintf(buf, sz, "%6d", (int)pp->pr_uid);
    370 }
    371 
    372 int
    373 fmt_nlwp(char *buf, int sz, struct prpsinfo *pp)
    374 
    375 {
    376     return snprintf(buf, sz, "%4d", pp->pr_fill < 999 ? pp->pr_fill: 999);
    377 }
    378 
    379 int
    380 fmt_pri(char *buf, int sz, struct prpsinfo *pp)
    381 
    382 {
    383     return snprintf(buf, sz, "%3d", pp->px_pri);
    384 }
    385 
    386 int
    387 fmt_nice(char *buf, int sz, struct prpsinfo *pp)
    388 
    389 {
    390     return snprintf(buf, sz, "%4d", pp->px_nice - NZERO);
    391 }
    392 
    393 int
    394 fmt_size(char *buf, int sz, struct prpsinfo *pp)
    395 
    396 {
    397     return snprintf(buf, sz, "%5s", format_k(SIZE_K(pp)));
    398 }
    399 
    400 int
    401 fmt_res(char *buf, int sz, struct prpsinfo *pp)
    402 
    403 {
    404     return snprintf(buf, sz, "%5s", format_k(RSS_K(pp)));
    405 }
    406 
    407 int
    408 fmt_state(char *buf, int sz, struct prpsinfo *pp)
    409 
    410 {
    411     if (pp->px_state == SONPROC && cpucount > 1)
    412     {
    413 	/* large #s may overflow colums */
    414 	if (pp->px_onpro < 100)
    415 	{
    416 	    return snprintf(buf, sz, "cpu/%-2d", pp->px_onpro);
    417 	}
    418 	return snprintf(buf, sz, "cpu/**");
    419     }
    420 
    421     return snprintf(buf, sz, "%-6s", state_abbrev[(int)pp->px_state]);
    422 }
    423 
    424 int
    425 fmt_time(char *buf, int sz, struct prpsinfo *pp)
    426 
    427 {
    428     return snprintf(buf, sz, "%6s", format_time(pp->pr_time.tv_sec));
    429 }
    430 
    431 int
    432 fmt_cpu(char *buf, int sz, struct prpsinfo *pp)
    433 
    434 {
    435     return snprintf(buf, sz, "%5s%%",
    436 		    format_percent(percent_cpu(pp) / cpucount));
    437 }
    438 
    439 int
    440 fmt_command(char *buf, int sz, struct prpsinfo *pp)
    441 
    442 {
    443     return snprintf(buf, sz, "%s",
    444 		    printable(show_fullcmd ? pp->pr_psargs : pp->pr_fname));
    445 }
    446 
    447 int
    448 fmt_lwp(char *buf, int sz, struct prpsinfo *pp)
    449 
    450 {
    451     return snprintf(buf, sz, "%4d", ((int)pp->pr_lwp.pr_lwpid < 10000 ?
    452 		(int)pp->pr_lwp.pr_lwpid : 9999));
    453 }
    454 
    455 struct proc_field proc_field[] = {
    456     { "PID", 6, 1, 0, fmt_pid },
    457     { "USERNAME", 8, 0, 0, fmt_username },
    458 #define FIELD_USERNAME 1
    459     { "UID", 6, 1, 0, fmt_uid },
    460 #define FIELD_UID 2
    461     { "NLWP", 4, 1, 0, fmt_nlwp },
    462     { "PRI", 3, 1, 0, fmt_pri },
    463     { "NICE", 4, 1, 0, fmt_nice },
    464     { "SIZE", 5, 1, 0, fmt_size },
    465     { "RES", 5, 1, 0, fmt_res },
    466     { "STATE", 6, 0, 0, fmt_state },
    467     { "TIME", 6, 1, 0, fmt_time },
    468     { "CPU", 6, 1, 0, fmt_cpu },
    469     { "COMMAND", 7, 0, 0, fmt_command },
    470     { "LWP", 4, 1, 0, fmt_lwp },
    471 };
    472 #define MAX_FIELDS 13
    473 
    474 static int proc_display[MAX_FIELDS];
    475 static int thr_display[MAX_FIELDS];
    476 
    477 int
    478 field_index(char *col)
    479 
    480 {
    481     struct proc_field *fp;
    482     int i = 0;
    483 
    484     fp = proc_field;
    485     while (fp->name != NULL)
    486     {
    487 	if (strcmp(col, fp->name) == 0)
    488 	{
    489 	    return i;
    490 	}
    491 	fp++;
    492 	i++;
    493     }
    494 
    495     return -1;
    496 }
    497 
    498 void
    499 field_subst(int *fp, int old, int new)
    500 
    501 {
    502     while (*fp != -1)
    503     {
    504 	if (*fp == old)
    505 	{
    506 	    *fp = new;
    507 	}
    508 	fp++;
    509     }
    510 }
    511 
    512 /* p_pagetok points to one of the following, depending on which
    513    direction data has to be shifted: */
    514 
    515 long pagetok_none(long size)
    516 
    517 {
    518     return(size);
    519 }
    520 
    521 long pagetok_left(long size)
    522 
    523 {
    524     return(size << pageshift);
    525 }
    526 
    527 long pagetok_right(long size)
    528 
    529 {
    530     return(size >> pageshift);
    531 }
    532 
    533 /*
    534  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
    535  *	"offset" is the byte offset into the kernel for the desired value,
    536  *  	"ptr" points to a buffer into which the value is retrieved,
    537  *  	"size" is the size of the buffer (and the object to retrieve),
    538  *  	"refstr" is a reference string used when printing error meessages,
    539  *	    if "refstr" starts with a '!', then a failure on read will not
    540  *  	    be fatal (this may seem like a silly way to do things, but I
    541  *  	    really didn't want the overhead of another argument).
    542  *
    543  */
    544 int
    545 getkval (unsigned long offset,
    546 	 int *ptr,
    547 	 int size,
    548 	 char *refstr)
    549 {
    550     dprintf("getkval(%08x, %08x, %d, %s)\n", offset, ptr, size, refstr);
    551 
    552     if (kvm_read (kd, offset, (char *) ptr, size) != size)
    553     {
    554 	dprintf("getkval: read failed\n");
    555 	if (*refstr == '!')
    556 	{
    557 	    return (0);
    558 	}
    559 	else
    560 	{
    561 	    fprintf (stderr, "top: kvm_read for %s: %s\n", refstr, strerror(errno));
    562 	    quit (23);
    563 	}
    564     }
    565 
    566     dprintf("getkval read %d (%08x)\n", *ptr);
    567 
    568     return (1);
    569 
    570 }
    571 
    572 /* procs structure memory management */
    573 
    574 static struct prpsinfo **allprocs = NULL;
    575 static struct prpsinfo **nextproc = NULL;
    576 static int maxprocs = 0;
    577 static int idxprocs = 0;
    578 
    579 /*
    580  * void procs_prealloc(int cnt)
    581  *
    582  * Preallocate "cnt" procs structures.  If "cnt" is less than or equal
    583  * to procs_max() then this function has no effect.
    584  */
    585 
    586 void
    587 procs_prealloc(int max)
    588 
    589 {
    590     int cnt;
    591     struct prpsinfo *new;
    592     struct prpsinfo **pp;
    593 
    594     cnt = max - maxprocs;
    595     if (cnt > 0)
    596     {
    597 	dprintf("procs_prealloc: need %d, deficit %d\n", max, cnt);
    598 	allprocs = (struct prpsinfo **)
    599 	    realloc((void *)allprocs, max * sizeof(struct prpsinfo *));
    600 	pp = nextproc = allprocs + idxprocs;
    601 	new = (struct prpsinfo *)malloc(cnt * PRPSINFOSIZE);
    602 	dprintf("procs_prealloc: idxprocs %d, allprocs %08x, nextproc %08x, new %08x\n",
    603 		idxprocs, allprocs, nextproc, new);
    604 	while (--cnt >= 0)
    605 	{
    606 	    *pp++ = new;
    607 	    new = (struct prpsinfo *) ((char *)new + PRPSINFOSIZE);
    608 	}
    609 	dprintf("procs_prealloc: done filling at %08x\n", new);
    610 	maxprocs = max;
    611     }
    612 }
    613 
    614 /*
    615  * struct prpsinfo *procs_next()
    616  *
    617  * Return the next available procs structure, allocating a new one
    618  * if needed.
    619  */
    620 
    621 struct prpsinfo *
    622 procs_next()
    623 
    624 {
    625     if (idxprocs >= maxprocs)
    626     {
    627 	/* allocate some more */
    628 	procs_prealloc(maxprocs + 128);
    629     }
    630     idxprocs++;
    631     return *nextproc++;
    632 }
    633 
    634 struct prpsinfo *
    635 procs_dup(struct prpsinfo *p)
    636 
    637 {
    638     struct prpsinfo *n;
    639 
    640     n = procs_next();
    641     memcpy(n, p, PRPSINFOSIZE);
    642     return n;
    643 }
    644 
    645 /*
    646  * struct prpsinfo *procs_start()
    647  *
    648  * Return the first procs structure.
    649  */
    650 
    651 struct prpsinfo *
    652 procs_start()
    653 
    654 {
    655     idxprocs = 0;
    656     nextproc = allprocs;
    657     return procs_next();
    658 }
    659 
    660 /*
    661  * int procs_max()
    662  *
    663  * Return the maximum number of procs structures currently allocated.
    664  */
    665 
    666 int
    667 procs_max()
    668 
    669 {
    670     return maxprocs;
    671 }
    672 
    673 /*
    674  * check_nlist(nlst) - checks the nlist to see if any symbols were not
    675  *		found.  For every symbol that was not found, a one-line
    676  *		message is printed to stderr.  The routine returns the
    677  *		number of symbols NOT found.
    678  */
    679 int
    680 check_nlist (register struct nlist *nlst)
    681 {
    682     register int i;
    683 
    684     /* check to see if we got ALL the symbols we requested */
    685     /* this will write one line to stderr for every symbol not found */
    686 
    687     i = 0;
    688     while (nlst->n_name != NULL)
    689     {
    690 	if (nlst->n_type == 0)
    691 	{
    692 	    /* this one wasn't found */
    693 	    fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
    694 	    i = 1;
    695 	}
    696 	nlst++;
    697     }
    698     return (i);
    699 }
    700 
    701 
    702 char *
    703 format_header (register char *uname_field)
    704 {
    705   return ("");
    706 }
    707 
    708 #ifdef USE_KSTAT
    709 
    710 long
    711 kstat_data_value_l(kstat_named_t *kn)
    712 
    713 {
    714 #ifdef KSTAT_DATA_UINT32
    715     switch(kn->data_type)
    716     {
    717     case KSTAT_DATA_INT32:
    718 	return ((long)(kn->value.i32));
    719     case KSTAT_DATA_UINT32:
    720 	return ((long)(kn->value.ui32));
    721     case KSTAT_DATA_INT64:
    722 	return ((long)(kn->value.i64));
    723     case KSTAT_DATA_UINT64:
    724 	return ((long)(kn->value.ui64));
    725     }
    726     return 0;
    727 #else
    728     return ((long)(kn->value.ui32));
    729 #endif
    730 }
    731 
    732 int
    733 kstat_safe_retrieve(kstat_t **ksp,
    734 		    char *module, int instance, char *name, void *buf)
    735 
    736 {
    737     kstat_t *ks;
    738     kid_t new_kcid;
    739     int changed;
    740 
    741     dprintf("kstat_safe_retrieve(%08x -> %08x, %s, %d, %s, %08x)\n",
    742 	    ksp, *ksp, module, instance, name, buf);
    743 
    744     ks = *ksp;
    745     do {
    746 	changed = 0;
    747 	/* if we dont already have the kstat, retrieve it */
    748 	if (ks == NULL)
    749 	{
    750 	    if ((ks = kstat_lookup(kc, module, instance, name)) == NULL)
    751 	    {
    752 		return (-1);
    753 	    }
    754 	    *ksp = ks;
    755 	}
    756 
    757 	/* attempt to read it */
    758 	new_kcid = kstat_read(kc, ks, buf);
    759 	/* chance for an infinite loop here if kstat_read keeps
    760 	   returning -1 */
    761 
    762 	/* if the chain changed, update it */
    763 	if (new_kcid != kcid)
    764 	{
    765 	    dprintf("kstat_safe_retrieve: chain changed to %d...updating\n",
    766 		    new_kcid);
    767 	    changed = 1;
    768 	    kcid = kstat_chain_update(kc);
    769 	}
    770     } while (changed);
    771 
    772     return (0);
    773 }
    774 
    775 /*
    776  * int kstat_safe_namematch(int num, kstat_t *ksp, char *name, void *buf)
    777  *
    778  * Safe scan of kstat chain for names starting with "name".  Matches
    779  * are copied in to "ksp", and kstat_read is called on each match using
    780  * "buf" as a buffer of length "size".  The actual number of records
    781  * found is returned.  Up to "num" kstats are copied in to "ksp", but
    782  * no more.  If any kstat_read indicates that the chain has changed, then
    783  * the whole process is restarted.
    784  */
    785 
    786 int
    787 kstat_safe_namematch(int num, kstat_t **ksparg, char *name, void *buf, int size)
    788 
    789 {
    790     kstat_t *ks;
    791     kstat_t **ksp;
    792     kid_t new_kcid;
    793     int namelen;
    794     int count;
    795     int changed;
    796     char *cbuf;
    797 
    798     dprintf("kstat_safe_namematch(%d, %08x, %s, %08x, %d)\n",
    799 	    num, ksparg, name, buf, size);
    800 
    801     namelen = strlen(name);
    802 
    803     do {
    804 	/* initialize before the scan */
    805 	cbuf = (char *)buf;
    806 	ksp = ksparg;
    807 	count = 0;
    808 	changed = 0;
    809 
    810 	/* scan the chain for matching kstats */
    811 	for (ks = kc->kc_chain; ks != NULL; ks = ks->ks_next)
    812 	{
    813 	    if (strncmp(ks->ks_name, name, namelen) == 0)
    814 	    {
    815 		/* this kstat matches: save it if there is room */
    816 		if (count++ < num)
    817 		{
    818 		    /* read the kstat */
    819 		    new_kcid = kstat_read(kc, ks, cbuf);
    820 
    821 		    /* if the chain changed, update it */
    822 		    if (new_kcid != kcid)
    823 		    {
    824 			dprintf("kstat_safe_namematch: chain changed to %d...updating\n",
    825 				new_kcid);
    826 			changed = 1;
    827 			kcid = kstat_chain_update(kc);
    828 
    829 			/* there's no sense in continuing the scan */
    830 			/* so break out of the for loop */
    831 			break;
    832 		    }
    833 
    834 		    /* move to the next buffers */
    835 		    cbuf += size;
    836 		    *ksp++ = ks;
    837 		}
    838 	    }
    839 	}
    840     } while(changed);
    841 
    842     dprintf("kstat_safe_namematch returns %d\n", count);
    843 
    844     return count;
    845 }
    846 
    847 static kstat_t *ks_system_misc = NULL;
    848 
    849 #endif /* USE_KSTAT */
    850 
    851 
    852 int
    853 get_avenrun(int avenrun[3])
    854 
    855 {
    856 #ifdef USE_KSTAT
    857     int status;
    858     kstat_named_t *kn;
    859 
    860     dprintf("get_avenrun(%08x)\n", avenrun);
    861 
    862     if ((status = kstat_safe_retrieve(&ks_system_misc,
    863 				      "unix", 0, "system_misc", NULL)) == 0)
    864     {
    865 	if ((kn = kstat_data_lookup(ks_system_misc, "avenrun_1min")) != NULL)
    866 	{
    867 	    avenrun[0] = kn->value.ui32;
    868 	}
    869 	if ((kn = kstat_data_lookup(ks_system_misc, "avenrun_5min")) != NULL)
    870 	{
    871 	    avenrun[1] = kn->value.ui32;
    872 	}
    873 	if ((kn = kstat_data_lookup(ks_system_misc, "avenrun_15min")) != NULL)
    874 	{
    875 	    avenrun[2] = kn->value.ui32;
    876 	}
    877     }
    878     dprintf("get_avenrun returns %d\n", status);
    879     return (status);
    880 
    881 #else /* !USE_KSTAT */
    882 
    883     (void) getkval (avenrun_offset, (int *) avenrun, sizeof (int [3]), "avenrun");
    884 
    885     return 0;
    886 
    887 #endif /* USE_KSTAT */
    888 }
    889 
    890 int
    891 get_ncpus()
    892 
    893 {
    894 #ifdef USE_KSTAT
    895     kstat_named_t *kn;
    896     int ret = -1;
    897 
    898     if ((kn = kstat_data_lookup(ks_system_misc, "ncpus")) != NULL)
    899     {
    900 	ret = (int)(kn->value.ui32);
    901     }
    902 
    903     return ret;
    904 #else
    905     int ret;
    906 
    907     (void) getkval(nlst[X_NCPUS].n_value, (int *)(&ret), sizeof(ret), "ncpus");
    908     return ret;
    909 #endif
    910 }
    911 
    912 int
    913 get_nproc()
    914 
    915 {
    916 #ifdef USE_KSTAT
    917     kstat_named_t *kn;
    918     int ret = -1;
    919 
    920     if ((kn = kstat_data_lookup(ks_system_misc, "nproc")) != NULL)
    921     {
    922 	ret = (int)(kn->value.ui32);
    923     }
    924 #else
    925     int ret;
    926 
    927     (void) getkval (nproc_offset, (int *) (&ret), sizeof (ret), "nproc");
    928 #endif
    929 
    930     dprintf("get_nproc returns %d\n", ret);
    931     return ret;
    932 }
    933 
    934 struct cpustats *
    935 get_cpustats(int *cnt, struct cpustats *cpustats)
    936 
    937 {
    938 #ifdef USE_KSTAT
    939     static kstat_t **cpu_ks = NULL;
    940     static cpu_stat_t *cpu_stat = NULL;
    941     static unsigned int nelems = 0;
    942     cpu_stat_t *cpu_stat_p;
    943     int i, cpu_num;
    944     struct cpustats *cpustats_p;
    945 
    946     dprintf("get_cpustats(%d -> %d, %08x)\n", cnt, *cnt, cpustats);
    947 
    948     while (nelems > 0 ?
    949 	   (cpu_num = kstat_safe_namematch(nelems,
    950 					   cpu_ks,
    951 					   "cpu_stat",
    952 					   cpu_stat,
    953 					   sizeof(cpu_stat_t))) > nelems :
    954 	   (cpu_num = get_ncpus()) > 0)
    955     {
    956 	/* reallocate the arrays */
    957 	dprintf("realloc from %d to %d\n", nelems, cpu_num);
    958 	nelems = cpu_num;
    959 	if (cpu_ks != NULL)
    960 	{
    961 	    free(cpu_ks);
    962 	}
    963 	cpu_ks = (kstat_t **)calloc(nelems, sizeof(kstat_t *));
    964 	if (cpu_stat != NULL)
    965 	{
    966 	    free(cpu_stat);
    967 	}
    968 	cpu_stat = (cpu_stat_t *)malloc(nelems * sizeof(cpu_stat_t));
    969     }
    970 
    971     /* do we have more cpus than our caller? */
    972     if (cpu_num > *cnt)
    973     {
    974 	/* yes, so realloc their array, too */
    975 	dprintf("realloc array from %d to %d\n", *cnt, cpu_num);
    976 	*cnt = cpu_num;
    977 	cpustats = (struct cpustats *)realloc(cpustats,
    978 					      cpu_num * sizeof(struct cpustats));
    979     }
    980 
    981     cpu_stat_p = cpu_stat;
    982     cpustats_p = cpustats;
    983     for (i = 0; i < cpu_num; i++)
    984     {
    985 	dprintf("cpu %d %08x: idle %u, user %u, syscall %u\n", i, cpu_stat_p,
    986 		cpu_stat_p->cpu_sysinfo.cpu[0],
    987 		cpu_stat_p->cpu_sysinfo.cpu[1],
    988 		cpu_stat_p->cpu_sysinfo.syscall);
    989 
    990 	cpustats_p->states[CPU_IDLE] = cpu_stat_p->cpu_sysinfo.cpu[CPU_IDLE];
    991 	cpustats_p->states[CPU_USER] = cpu_stat_p->cpu_sysinfo.cpu[CPU_USER];
    992 	cpustats_p->states[CPU_KERNEL] = cpu_stat_p->cpu_sysinfo.cpu[CPU_KERNEL];
    993 	cpustats_p->states[CPUSTATE_IOWAIT] = cpu_stat_p->cpu_sysinfo.wait[W_IO] +
    994 	    cpu_stat_p->cpu_sysinfo.wait[W_PIO];
    995 	cpustats_p->states[CPUSTATE_SWAP] = cpu_stat_p->cpu_sysinfo.wait[W_SWAP];
    996 	cpustats_p->pswitch = cpu_stat_p->cpu_sysinfo.pswitch;
    997 	cpustats_p->trap = cpu_stat_p->cpu_sysinfo.trap;
    998 	cpustats_p->intr = cpu_stat_p->cpu_sysinfo.intr;
    999 	cpustats_p->syscall = cpu_stat_p->cpu_sysinfo.syscall;
   1000 	cpustats_p->sysfork = cpu_stat_p->cpu_sysinfo.sysfork;
   1001 	cpustats_p->sysvfork = cpu_stat_p->cpu_sysinfo.sysvfork;
   1002 	cpustats_p->pfault = cpu_stat_p->cpu_vminfo.hat_fault +
   1003 	    cpu_stat_p->cpu_vminfo.as_fault;
   1004 	cpustats_p->pgin = cpu_stat_p->cpu_vminfo.pgin;
   1005 	cpustats_p->pgout = cpu_stat_p->cpu_vminfo.pgout;
   1006 	cpustats_p++;
   1007 	cpu_stat_p++;
   1008     }
   1009 
   1010     cpucount = cpu_num;
   1011 
   1012     dprintf("get_cpustats sees %d cpus and returns %08x\n", cpucount, cpustats);
   1013 
   1014     return (cpustats);
   1015 #else /* !USE_KSTAT */
   1016     int i;
   1017     struct cpu cpu;
   1018     unsigned int (*cp_stats_p)[CPUSTATES];
   1019 
   1020     /* do we have more cpus than our caller? */
   1021     if (cpucount > *cnt)
   1022     {
   1023 	/* yes, so realloc their array, too */
   1024 	dprintf("realloc array from %d to %d\n", *cnt, cpucount);
   1025 	*cnt = cpucount;
   1026 	cp_stats = (unsigned int (*)[CPUSTATES])realloc(cp_stats,
   1027 			 cpucount * sizeof(unsigned int) * CPUSTATES);
   1028     }
   1029 
   1030     cp_stats_p = cp_stats;
   1031     for (i = 0; i < cpucount; i++)
   1032     {
   1033 	if (cpu_offset[i] != 0)
   1034 	{
   1035 	    /* get struct cpu for this processor */
   1036 	    (void) getkval (cpu_offset[i], (int *)(&cpu), sizeof (struct cpu), "cpu");
   1037 
   1038 	    (*cp_stats_p)[CPU_IDLE] = cpu.cpu_stat.cpu_sysinfo.cpu[CPU_IDLE];
   1039 	    (*cp_stats_p)[CPU_USER] = cpu.cpu_stat.cpu_sysinfo.cpu[CPU_USER];
   1040 	    (*cp_stats_p)[CPU_KERNEL] = cpu.cpu_stat.cpu_sysinfo.cpu[CPU_KERNEL];
   1041 	    (*cp_stats_p)[CPUSTATE_IOWAIT] = cpu.cpu_stat.cpu_sysinfo.wait[W_IO] +
   1042 		cpu.cpu_stat.cpu_sysinfo.wait[W_PIO];
   1043 	    (*cp_stats_p)[CPUSTATE_SWAP] = cpu.cpu_stat.cpu_sysinfo.wait[W_SWAP];
   1044 	    cp_stats_p++;
   1045 	}
   1046     }
   1047 
   1048     return (cp_stats);
   1049 #endif /* USE_KSTAT */
   1050 }
   1051 
   1052 /*
   1053  * void get_meminfo(long *total, long *fr)
   1054  *
   1055  * Get information about the system's physical memory.  Pass back values
   1056  * for total available and amount of memory that is free (in kilobytes).
   1057  * It returns 0 on success and -1 on any kind of failure.
   1058  */
   1059 
   1060 int
   1061 get_meminfo(long *total, long *fr)
   1062 
   1063 {
   1064     long freemem;
   1065     static kstat_t *ks = NULL;
   1066     kstat_named_t *kn;
   1067 
   1068     /* total comes from sysconf */
   1069     *total = pagetok(sysconf(_SC_PHYS_PAGES));
   1070 
   1071     /* free comes from the kernel's freemem or from kstat */
   1072     /* prefer kmem for this because kstat unix:0:system_pages
   1073        can be slow on systems with lots of memory */
   1074     if (kd)
   1075     {
   1076 	(void) getkval(freemem_offset, (int *)(&freemem), sizeof(freemem),
   1077 		       "freemem");
   1078     }
   1079     else
   1080     {
   1081 #ifdef USE_KSTAT
   1082 	/* only need to grab kstat chain once */
   1083 	if (ks == NULL)
   1084 	{
   1085 	    ks = kstat_lookup(kc, "unix", 0, "system_pages");
   1086 	}
   1087 
   1088 	if (ks != NULL &&
   1089 	    kstat_read(kc, ks, 0) != -1 &&
   1090 	    (kn = kstat_data_lookup(ks, "freemem")) != NULL)
   1091 	{
   1092 	    freemem = kstat_data_value_l(kn);
   1093 	}
   1094 	else
   1095 	{
   1096 	    freemem = -1;
   1097 	}
   1098 #else
   1099 	freemem = -1;
   1100 #endif
   1101     }
   1102 
   1103     *fr = freemem == -1 ? -1 : pagetok(freemem);
   1104 
   1105     return (0);
   1106 }
   1107 
   1108 /*
   1109  * void get_swapinfo(long *total, long *fr)
   1110  *
   1111  * Get information about the system's swap.  Pass back values for
   1112  * total swap available and amount of swap that is free (in kilobytes).
   1113  * It returns 0 on success and -1 on any kind of failure.
   1114  */
   1115 
   1116 int
   1117 get_swapinfo(long *total, long *fr)
   1118 
   1119 {
   1120     register int cnt, i;
   1121     register long t, f;
   1122     struct swaptable *swt;
   1123     struct swapent *ste;
   1124     static char path[256];
   1125 
   1126     /* preset values to 0 just in case we have to return early */
   1127     *total = 0;
   1128     *fr = 0;
   1129 
   1130     /* get total number of swap entries */
   1131     if ((cnt = swapctl(SC_GETNSWP, 0)) == -1)
   1132     {
   1133 	return (-1);
   1134     }
   1135 
   1136     /* allocate enough space to hold count + n swapents */
   1137     swt = (struct swaptable *)malloc(sizeof(int) +
   1138 				     cnt * sizeof(struct swapent));
   1139     if (swt == NULL)
   1140     {
   1141 	return (-1);
   1142     }
   1143     swt->swt_n = cnt;
   1144 
   1145     /* fill in ste_path pointers: we don't care about the paths, so we point
   1146        them all to the same buffer */
   1147     ste = &(swt->swt_ent[0]);
   1148     i = cnt;
   1149     while (--i >= 0)
   1150     {
   1151 	ste++->ste_path = path;
   1152     }
   1153 
   1154     /* grab all swap info */
   1155     if (swapctl(SC_LIST, swt) == -1)
   1156     {
   1157 	return (-1);
   1158     }
   1159 
   1160     /* walk thru the structs and sum up the fields */
   1161     t = f = 0;
   1162     ste = &(swt->swt_ent[0]);
   1163     i = cnt;
   1164     while (--i >= 0)
   1165     {
   1166 	/* dont count slots being deleted */
   1167 	if (!(ste->ste_flags & ST_INDEL) &&
   1168 	    !(ste->ste_flags & ST_DOINGDEL))
   1169 	{
   1170 	    t += ste->ste_pages;
   1171 	    f += ste->ste_free;
   1172 	}
   1173 	ste++;
   1174     }
   1175 
   1176     /* fill in the results */
   1177     *total = pagetok(t);
   1178     *fr = pagetok(f);
   1179     free(swt);
   1180 
   1181     /* good to go */
   1182     return (0);
   1183 }
   1184 
   1185 int
   1186 machine_init (struct statics *statics)
   1187 {
   1188     struct utmpx ut;
   1189     struct utmpx *up;
   1190     struct rlimit rlim;
   1191     int i;
   1192     char *p;
   1193     int *ip;
   1194     int nproc;
   1195 #ifndef USE_KSTAT
   1196     int offset;
   1197 #endif
   1198 
   1199     /* There's a buffer overflow bug in curses that can be exploited when
   1200        we run as root.  By making sure that TERMINFO is set to something
   1201        this bug is avoided.  This code thanks to Casper */
   1202     if ((p = getenv("TERMINFO")) == NULL || *p == '\0')
   1203     {
   1204         putenv("TERMINFO=/usr/share/lib/terminfo/");
   1205     }
   1206 
   1207     /* perform the kvm_open - suppress error here */
   1208     if ((kd = kvm_open (NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
   1209     {
   1210 	/* save the error message: we may need it later */
   1211 	p = strerror(errno);
   1212     }
   1213     dprintf("kvm_open: fd %d\n", kd);
   1214 
   1215     /*
   1216      * turn off super group/user privs - but beware; we might
   1217      * want the privs back later and we still have a fd to
   1218      * /dev/kmem open so we can't use setgid()/setuid() as that
   1219      * would allow a debugger to attach to this process. CD
   1220      */
   1221     setegid(getgid());
   1222     seteuid(getuid()); /* super user not needed for NEW_PROC */
   1223 
   1224 #ifdef USE_KSTAT
   1225     /* open kstat */
   1226     if ((kc = kstat_open()) == NULL)
   1227     {
   1228 	fprintf(stderr, "Unable to open kstat.\n");
   1229 	return(-1);
   1230     }
   1231     kcid = kc->kc_chain_id;
   1232     dprintf("kstat_open: chain %d\n", kcid);
   1233 #endif
   1234 
   1235     /* fill in the statics information */
   1236     statics->procstate_names = procstatenames;
   1237     statics->cpustate_names = cpustatenames;
   1238     statics->memory_names = memorynames;
   1239     statics->kernel_names = kernelnames;
   1240     statics->order_names = ordernames;
   1241     statics->flags.fullcmds = 1;
   1242     statics->flags.warmup = 1;
   1243     statics->flags.threads = 1;
   1244 
   1245     /* get boot time */
   1246     ut.ut_type = BOOT_TIME;
   1247     if ((up = getutxid(&ut)) != NULL)
   1248     {
   1249 	statics->boottime = up->ut_tv.tv_sec;
   1250     }
   1251     endutxent();
   1252 
   1253     /* if the kvm_open succeeded, get the nlist */
   1254     if (kd)
   1255     {
   1256 	if (kvm_nlist (kd, nlst) < 0)
   1257         {
   1258 	    perror ("kvm_nlist");
   1259 	    return (-1);
   1260         }
   1261 	if (check_nlist (nlst) != 0)
   1262 	    return (-1);
   1263     }
   1264 #ifndef USE_KSTAT
   1265     /* if KSTAT is not available to us and we can't open /dev/kmem,
   1266        this is a serious problem.
   1267     */
   1268     else
   1269     {
   1270 	/* Print the error message here */
   1271 	(void) fprintf(stderr, "kvm_open: %s\n", p);
   1272 	return (-1);
   1273     }
   1274 #endif
   1275 
   1276     /* stash away certain offsets for later use */
   1277     mpid_offset = nlst[X_MPID].n_value;
   1278     nproc_offset = nlst[X_NPROC].n_value;
   1279     avenrun_offset = nlst[X_AVENRUN].n_value;
   1280     anoninfo_offset = nlst[X_ANONINFO].n_value;
   1281     freemem_offset = nlst[X_FREEMEM].n_value;
   1282     maxmem_offset = nlst[X_MAXMEM].n_value;
   1283 
   1284 #ifndef USE_KSTAT
   1285     (void) getkval (nlst[X_NCPUS].n_value, (int *) (&cpucount),
   1286 		    sizeof (cpucount), "ncpus");
   1287 
   1288     cpu_offset = (unsigned long *) malloc (cpucount * sizeof (unsigned long));
   1289     for (i = offset = 0; i < cpucount; offset += sizeof(unsigned long)) {
   1290         (void) getkval (nlst[X_CPU].n_value + offset,
   1291                         (int *)(&cpu_offset[i]), sizeof (unsigned long),
   1292                         nlst[X_CPU].n_name );
   1293         if (cpu_offset[i] != 0)
   1294             i++;
   1295     }
   1296 #endif
   1297 
   1298     /* we need to get the current nproc */
   1299 #ifdef USE_KSTAT
   1300     /* get_nproc assumes that the chain has already been retrieved,
   1301        so we need to do that here */
   1302     kstat_safe_retrieve(&ks_system_misc, "unix", 0, "system_misc", NULL);
   1303 #endif
   1304     nproc = get_nproc();
   1305     dprintf("machine_init: nproc=%d\n", nproc);
   1306 
   1307     /* hash table for procs and threads sized based on current nproc*/
   1308     prochash = hash_create(nproc > 100 ? nproc * 2 + 1 : 521);
   1309     threadhash = hash_create(nproc > 100 ? nproc * 4 + 1 : 2053);
   1310 
   1311     /* calculate pageshift value */
   1312     i = sysconf(_SC_PAGESIZE);
   1313     pageshift = 0;
   1314     while ((i >>= 1) > 0)
   1315     {
   1316 	pageshift++;
   1317     }
   1318 
   1319     /* calculate an amount to shift to K values */
   1320     /* remember that log base 2 of 1024 is 10 (i.e.: 2^10 = 1024) */
   1321     pageshift -= 10;
   1322 
   1323     /* now determine which pageshift function is appropriate for the
   1324        result (have to because x << y is undefined for y < 0) */
   1325     if (pageshift > 0)
   1326     {
   1327 	/* this is the most likely */
   1328 	p_pagetok = pagetok_left;
   1329     }
   1330     else if (pageshift == 0)
   1331     {
   1332 	p_pagetok = pagetok_none;
   1333     }
   1334     else
   1335     {
   1336 	p_pagetok = pagetok_right;
   1337 	pageshift = -pageshift;
   1338     }
   1339 
   1340     /* we cache open files to improve performance, so we need to up
   1341        the NOFILE limit */
   1342     if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
   1343     {
   1344 	/* set a new soft limit */
   1345 	maxfiles = (int)(rlim.rlim_max < MAXFILES ? rlim.rlim_max : MAXFILES);
   1346 	rlim.rlim_cur = (rlim_t)maxfiles;
   1347 	(void)setrlimit(RLIMIT_NOFILE, &rlim);
   1348 
   1349 	/* now leave some wiggle room above the maximum */
   1350 	maxfiles -= 20;
   1351     }
   1352 
   1353     /* set up the display indices */
   1354     ip = proc_display;
   1355     *ip++ = field_index("PID");
   1356     *ip++ = field_index("USERNAME");
   1357     *ip++ = field_index("NLWP");
   1358     *ip++ = field_index("PRI");
   1359     *ip++ = field_index("NICE");
   1360     *ip++ = field_index("SIZE");
   1361     *ip++ = field_index("RES");
   1362     *ip++ = field_index("STATE");
   1363     *ip++ = field_index("TIME");
   1364     *ip++ = field_index("CPU");
   1365     *ip++ = field_index("COMMAND");
   1366     *ip = -1;
   1367     ip = thr_display;
   1368     *ip++ = field_index("PID");
   1369     *ip++ = field_index("LWP");
   1370     *ip++ = field_index("USERNAME");
   1371     *ip++ = field_index("PRI");
   1372     *ip++ = field_index("NICE");
   1373     *ip++ = field_index("SIZE");
   1374     *ip++ = field_index("RES");
   1375     *ip++ = field_index("STATE");
   1376     *ip++ = field_index("TIME");
   1377     *ip++ = field_index("CPU");
   1378     *ip++ = field_index("COMMAND");
   1379     *ip = -1;
   1380 
   1381     if (!(procdir = opendir (PROCFS)))
   1382     {
   1383 	(void) fprintf (stderr, "Unable to open %s\n", PROCFS);
   1384 	return (-1);
   1385     }
   1386 
   1387     if (chdir (PROCFS))
   1388     {				/* handy for later on when we're reading it */
   1389 	(void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
   1390 	return (-1);
   1391     }
   1392 
   1393     /* all done! */
   1394     return (0);
   1395 }
   1396 
   1397 void
   1398 get_system_info (struct system_info *si)
   1399 {
   1400     int avenrun[3];
   1401 
   1402     static long cp_time[CPUSTATES];
   1403     static long cp_old[CPUSTATES];
   1404     static long cp_diff[CPUSTATES];
   1405     static struct cpustats *cpustats = NULL;
   1406     static struct cpustats sum_current;
   1407     static struct cpustats sum_old;
   1408     static int cpus = 0;
   1409     register int j, i;
   1410 
   1411     /* remember the old values and zero out the current */
   1412     memcpy(&sum_old, &sum_current, sizeof(sum_current));
   1413     memset(&sum_current, 0, sizeof(sum_current));
   1414 
   1415     /* get important information */
   1416     get_avenrun(avenrun);
   1417 
   1418     /* get the cpu statistics arrays */
   1419     cpustats = get_cpustats(&cpus, cpustats);
   1420 
   1421     /* zero the cp_time array */
   1422     memset(cp_time, 0, sizeof(cp_time));
   1423 
   1424     /* sum stats in to a single array and a single structure */
   1425     for (i = 0; i < cpus; i++)
   1426     {
   1427 	for (j = 0; j < CPUSTATES; j++)
   1428 	{
   1429 	    cp_time[j] += cpustats[i].states[j];
   1430 	}
   1431 	sum_current.pswitch += cpustats[i].pswitch;
   1432 	sum_current.trap += cpustats[i].trap;
   1433 	sum_current.intr += cpustats[i].intr;
   1434 	sum_current.syscall += cpustats[i].syscall;
   1435 	sum_current.sysfork += cpustats[i].sysfork;
   1436 	sum_current.sysvfork += cpustats[i].sysvfork;
   1437 	sum_current.pfault += cpustats[i].pfault;
   1438 	sum_current.pgin += cpustats[i].pgin;
   1439 	sum_current.pgout += cpustats[i].pgout;
   1440     }
   1441 
   1442     /* convert cp_time counts to percentages */
   1443     (void) percentages (CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
   1444 
   1445     /* get mpid -- process id of last process */
   1446     if (kd)
   1447 	(void) getkval(mpid_offset, &(si->last_pid), sizeof (si->last_pid), "mpid");
   1448     else
   1449 	si->last_pid = -1;
   1450 
   1451     /* convert load averages to doubles */
   1452     for (i = 0; i < 3; i++)
   1453 	si->load_avg[i] = loaddouble (avenrun[i]);
   1454 
   1455     /* get physical memory data */
   1456     if (get_meminfo(&(memory_stats[MEMORY_TOTALMEM]),
   1457 		    &(memory_stats[MEMORY_FREEMEM])) == -1)
   1458     {
   1459 	memory_stats[MEMORY_TOTALMEM] = memory_stats[MEMORY_FREEMEM] = -1;
   1460     }
   1461 
   1462     /* get swap data */
   1463     if (get_swapinfo(&(memory_stats[MEMORY_TOTALSWAP]),
   1464 		     &(memory_stats[MEMORY_FREESWAP])) == -1)
   1465     {
   1466 	memory_stats[MEMORY_TOTALSWAP] = memory_stats[MEMORY_FREESWAP] = -1;
   1467     }
   1468 
   1469     /* get kernel data */
   1470     kernel_stats[KERNEL_CSWITCH] = diff_per_second(sum_current.pswitch, sum_old.pswitch);
   1471     kernel_stats[KERNEL_TRAP] = diff_per_second(sum_current.trap, sum_old.trap);
   1472     kernel_stats[KERNEL_INTR] = diff_per_second(sum_current.intr, sum_old.intr);
   1473     kernel_stats[KERNEL_SYSCALL] = diff_per_second(sum_current.syscall, sum_old.syscall);
   1474     kernel_stats[KERNEL_FORK] = diff_per_second(sum_current.sysfork + sum_current.sysvfork,
   1475 						sum_old.sysfork + sum_old.sysvfork);
   1476     kernel_stats[KERNEL_PFAULT] = diff_per_second(sum_current.pfault, sum_old.pfault);
   1477     kernel_stats[KERNEL_PGIN] = pagetok(diff_per_second(sum_current.pgin, sum_old.pgin));
   1478     kernel_stats[KERNEL_PGOUT] = pagetok(diff_per_second(sum_current.pgout, sum_old.pgout));
   1479 
   1480 
   1481     /* set arrays and strings */
   1482     si->cpustates = cpu_states;
   1483     si->memory = memory_stats;
   1484     si->kernel = kernel_stats;
   1485 
   1486     dprintf("get_system_info returns\n");
   1487 }
   1488 
   1489 static struct handle handle;
   1490 
   1491 caddr_t
   1492 get_process_info (
   1493 		   struct system_info *si,
   1494 		   struct process_select *sel,
   1495 		   int compare_index)
   1496 {
   1497     register int i;
   1498     register int total_procs;
   1499     register int active_procs;
   1500     register struct prpsinfo **prefp;
   1501     register struct prpsinfo *pp;
   1502     int nproc;
   1503     int state;
   1504 
   1505     /* these are copied out of sel for speed */
   1506     int show_idle;
   1507     int show_system;
   1508     int show_uid;
   1509     char *show_command;
   1510 
   1511     /* these persist across calls */
   1512     static struct prpsinfo **pref = NULL;
   1513     static int pref_size = 0;
   1514 
   1515     /* set up flags which define what we are going to select */
   1516     show_idle = sel->idle;
   1517     show_system = sel->system;
   1518     show_uid = sel->uid != -1;
   1519     show_fullcmd = sel->fullcmd;
   1520     show_command = sel->command;
   1521     show_threads = sel->threads;
   1522 
   1523     /* allocate enough space for twice our current needs */
   1524     nproc = get_nproc();
   1525     if (nproc > procs_max())
   1526     {
   1527 	procs_prealloc(2 * nproc);
   1528     }
   1529 
   1530     /* read all the proc structures */
   1531     nproc = getptable();
   1532 
   1533     /* allocate pref[] */
   1534     if (pref_size < nproc)
   1535     {
   1536 	if (pref != NULL)
   1537 	{
   1538 	    free(pref);
   1539 	}
   1540 	pref = (struct prpsinfo **)malloc(nproc * sizeof(struct prpsinfo *));
   1541 	dprintf("get_process_info: allocated %d prinfo pointers at %08x\n",
   1542 		nproc, pref);
   1543 	pref_size = nproc;
   1544     }
   1545 
   1546     /* get a pointer to the states summary array */
   1547     si->procstates = process_states;
   1548 
   1549     /* count up process states and get pointers to interesting procs */
   1550     total_procs = 0;
   1551     active_procs = 0;
   1552     (void) memset (process_states, 0, sizeof (process_states));
   1553     prefp = pref;
   1554 
   1555     for (pp = procs_start(), i = 0; i < nproc;
   1556 	 i++, pp = procs_next())
   1557     {
   1558 	dprintf("looking at #%d: %d.%d\n", i,
   1559 		pp->pr_pid, pp->pr_lwp.pr_lwpid);
   1560 	/*
   1561 	 *  Place pointers to each valid proc structure in pref[].
   1562 	 *  Process slots that are actually in use have a non-zero
   1563 	 *  status field.  Processes with SSYS set are system
   1564 	 *  processes---these get ignored unless show_sysprocs is set.
   1565 	 */
   1566 	if (pp->px_state != 0 &&
   1567 	    (show_system || ((pp->pr_flag & SSYS) == 0)))
   1568 	{
   1569 	    total_procs++;
   1570 	    state = (int)pp->px_state;
   1571 	    if (state > 0 && state < PROCSTATES)
   1572 	    {
   1573 		process_states[state]++;
   1574 	    }
   1575 	    else
   1576 	    {
   1577 		dprintf("process %d.%d: state out of bounds %d\n",
   1578 			pp->pr_pid, pp->pr_lwp.pr_lwpid, state);
   1579 	    }
   1580 
   1581 	    if ((!ZOMBIE(pp)) &&
   1582 		(show_idle || percent_cpu (pp) || (pp->px_state == SRUN) || (pp->px_state == SONPROC)) &&
   1583 		(!show_uid || pp->pr_uid == (uid_t) sel->uid) &&
   1584 		(show_command == NULL ||
   1585 		 strstr(pp->pr_fname, show_command) != NULL))
   1586 	    {
   1587 		*prefp++ = pp;
   1588 		active_procs++;
   1589 	    }
   1590 	}
   1591     }
   1592 
   1593     dprintf("total_procs %d, active_procs %d\n", total_procs, active_procs);
   1594 
   1595     /* if requested, sort the "interesting" processes */
   1596     qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *),
   1597 	   proc_compares[compare_index]);
   1598 
   1599     /* remember active and total counts */
   1600     si->p_total = total_procs;
   1601     si->p_active = active_procs;
   1602 
   1603     /* pass back a handle */
   1604     handle.next_proc = pref;
   1605     handle.remaining = active_procs;
   1606     return ((caddr_t) & handle);
   1607 }
   1608 
   1609 static char p_header[MAX_COLS];
   1610 
   1611 char *
   1612 format_process_header(struct process_select *sel, caddr_t handle, int count)
   1613 
   1614 {
   1615     int cols;
   1616     char *p;
   1617     int *fi;
   1618     struct proc_field *fp;
   1619 
   1620     /* check for null handle */
   1621     if (handle == NULL)
   1622     {
   1623 	return("");
   1624     }
   1625 
   1626     /* remember how many columns there are on the display */
   1627     cols = display_columns();
   1628 
   1629     /* mode & threads dictate format */
   1630     fi = display_fields = sel->threads ? thr_display : proc_display;
   1631 
   1632     /* set username field correctly */
   1633     if (!sel->usernames)
   1634     {
   1635 	/* display uids */
   1636 	field_subst(fi, FIELD_USERNAME, FIELD_UID);
   1637     }
   1638     else
   1639     {
   1640 	/* display usernames */
   1641 	field_subst(fi, FIELD_UID, FIELD_USERNAME);
   1642     }
   1643 
   1644     /* walk thru fields and construct header */
   1645     /* are we worried about overflow??? */
   1646     p = p_header;
   1647     while (*fi != -1)
   1648     {
   1649 	fp = &(proc_field[*fi++]);
   1650 	if (fp->min_screenwidth <= cols)
   1651 	{
   1652 	    p += sprintf(p, fp->rjust ? "%*s" : "%-*s", fp->width, fp->name);
   1653 	    *p++ = ' ';
   1654 	}
   1655     }
   1656     *--p = '\0';
   1657 
   1658     return p_header;
   1659 }
   1660 
   1661 static char fmt[MAX_COLS];		/* static area where result is built */
   1662 
   1663 char *
   1664 format_next_process(caddr_t handle, char *(*get_userid)(int))
   1665 
   1666 {
   1667     struct prpsinfo *pp;
   1668     struct handle *hp;
   1669     struct proc_field *fp;
   1670     int *fi;
   1671     int i;
   1672     int cols;
   1673     char *p;
   1674     int len;
   1675     int x;
   1676 
   1677     /* find and remember the next proc structure */
   1678     hp = (struct handle *)handle;
   1679     pp = *(hp->next_proc++);
   1680     hp->remaining--;
   1681 
   1682     /* grab format descriptor */
   1683     fi = display_fields;
   1684 
   1685     /* screen width is a consideration, too */
   1686     cols = display_columns();
   1687 
   1688     /* build output by field */
   1689     p = fmt;
   1690     len = MAX_COLS;
   1691     while ((i = *fi++) != -1)
   1692     {
   1693 	fp = &(proc_field[i]);
   1694 	if (len > 0 && fp->min_screenwidth <= cols)
   1695 	{
   1696 	    x = (*(fp->format))(p, len, pp);
   1697 	    if (x >= len)
   1698 	    {
   1699 		dprintf("format_next_process: formatter overflow: x %d, len %d, p %08x => %08x, fmt %08x - %08x\n",
   1700 			x, len, p, p + len, fmt, fmt + sizeof(fmt));
   1701 		p += len;
   1702 		len = 0;
   1703 	    }
   1704 	    else
   1705 	    {
   1706 		p += x;
   1707 		*p++ = ' ';
   1708 		len -= x + 1;
   1709 	    }
   1710 	}
   1711     }
   1712     *--p = '\0';
   1713 
   1714     /* return the result */
   1715     return(fmt);
   1716 }
   1717 
   1718 /* comparison routines for qsort */
   1719 
   1720 /*
   1721  * There are currently four possible comparison routines.  main selects
   1722  * one of these by indexing in to the array proc_compares.
   1723  *
   1724  * Possible keys are defined as macros below.  Currently these keys are
   1725  * defined:  percent cpu, cpu ticks, process state, resident set size,
   1726  * total virtual memory usage.  The process states are ordered as follows
   1727  * (from least to most important):  WAIT, zombie, sleep, stop, start, run.
   1728  * The array declaration below maps a process state index into a number
   1729  * that reflects this ordering.
   1730  */
   1731 
   1732 /* First, the possible comparison keys.  These are defined in such a way
   1733    that they can be merely listed in the source code to define the actual
   1734    desired ordering.
   1735  */
   1736 
   1737 #define ORDERKEY_PCTCPU  if (dresult = percent_cpu (p2) - percent_cpu (p1),\
   1738 			     (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0)
   1739 #define ORDERKEY_CPTICKS if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
   1740 #define ORDERKEY_STATE   if ((result = (long) (sorted_state[(int)p2->px_state] - \
   1741 			       sorted_state[(int)p1->px_state])) == 0)
   1742 #define ORDERKEY_PRIO    if ((result = p2->px_pri - p1->px_pri) == 0)
   1743 #define ORDERKEY_RSSIZE  if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
   1744 #define ORDERKEY_MEM     if ((result = (p2->pr_size - p1->pr_size)) == 0)
   1745 #define ORDERKEY_LWP     if ((result = (p1->pr_lwp.pr_lwpid - p2->pr_lwp.pr_lwpid)) == 0)
   1746 #define ORDERKEY_PID     if ((result = (p1->pr_pid - p2->pr_pid)) == 0)
   1747 
   1748 /* Now the array that maps process state to a weight */
   1749 
   1750 unsigned char sorted_state[] =
   1751 {
   1752   0,				/* not used		*/
   1753   3,				/* sleep		*/
   1754   6,				/* run			*/
   1755   2,				/* zombie		*/
   1756   4,				/* stop			*/
   1757   5,				/* start		*/
   1758   7,				/* run on a processor   */
   1759   1				/* being swapped (WAIT)	*/
   1760 };
   1761 
   1762 
   1763 /* compare_cpu - the comparison function for sorting by cpu percentage */
   1764 
   1765 int
   1766 compare_cpu (struct prpsinfo **pp1, struct prpsinfo **pp2)
   1767 
   1768 {
   1769     register struct prpsinfo *p1;
   1770     register struct prpsinfo *p2;
   1771     register long result;
   1772     double dresult;
   1773 
   1774     /* remove one level of indirection */
   1775     p1 = *pp1;
   1776     p2 = *pp2;
   1777 
   1778     ORDERKEY_PCTCPU
   1779     ORDERKEY_CPTICKS
   1780     ORDERKEY_STATE
   1781     ORDERKEY_PRIO
   1782     ORDERKEY_RSSIZE
   1783     ORDERKEY_MEM
   1784     ORDERKEY_PID
   1785     ORDERKEY_LWP
   1786     ;
   1787 
   1788     return (result);
   1789 }
   1790 
   1791 /* compare_size - the comparison function for sorting by total memory usage */
   1792 
   1793 int
   1794 compare_size (struct prpsinfo **pp1, struct prpsinfo **pp2)
   1795 
   1796 {
   1797     register struct prpsinfo *p1;
   1798     register struct prpsinfo *p2;
   1799     register long result;
   1800     double dresult;
   1801 
   1802     /* remove one level of indirection */
   1803     p1 = *pp1;
   1804     p2 = *pp2;
   1805 
   1806     ORDERKEY_MEM
   1807     ORDERKEY_RSSIZE
   1808     ORDERKEY_PCTCPU
   1809     ORDERKEY_CPTICKS
   1810     ORDERKEY_STATE
   1811     ORDERKEY_PRIO
   1812     ORDERKEY_PID
   1813     ORDERKEY_LWP
   1814     ;
   1815 
   1816     return (result);
   1817 }
   1818 
   1819 /* compare_res - the comparison function for sorting by resident set size */
   1820 
   1821 int
   1822 compare_res (struct prpsinfo **pp1, struct prpsinfo **pp2)
   1823 
   1824 {
   1825     register struct prpsinfo *p1;
   1826     register struct prpsinfo *p2;
   1827     register long result;
   1828     double dresult;
   1829 
   1830     /* remove one level of indirection */
   1831     p1 = *pp1;
   1832     p2 = *pp2;
   1833 
   1834     ORDERKEY_RSSIZE
   1835     ORDERKEY_MEM
   1836     ORDERKEY_PCTCPU
   1837     ORDERKEY_CPTICKS
   1838     ORDERKEY_STATE
   1839     ORDERKEY_PRIO
   1840     ORDERKEY_PID
   1841     ORDERKEY_LWP
   1842     ;
   1843 
   1844     return (result);
   1845 }
   1846 
   1847 /* compare_time - the comparison function for sorting by total cpu time */
   1848 
   1849 int
   1850 compare_time (struct prpsinfo **pp1, struct prpsinfo **pp2)
   1851 
   1852 {
   1853     register struct prpsinfo *p1;
   1854     register struct prpsinfo *p2;
   1855     register long result;
   1856     double dresult;
   1857 
   1858     /* remove one level of indirection */
   1859     p1 = *pp1;
   1860     p2 = *pp2;
   1861 
   1862     ORDERKEY_CPTICKS
   1863     ORDERKEY_PCTCPU
   1864     ORDERKEY_STATE
   1865     ORDERKEY_PRIO
   1866     ORDERKEY_MEM
   1867     ORDERKEY_RSSIZE
   1868     ORDERKEY_PID
   1869     ORDERKEY_LWP
   1870     ;
   1871 
   1872     return (result);
   1873 }
   1874 
   1875 /* compare_pid - the comparison function for sorting by process id */
   1876 
   1877 int
   1878 compare_pid (struct prpsinfo **pp1, struct prpsinfo **pp2)
   1879 
   1880 {
   1881     register struct prpsinfo *p1;
   1882     register struct prpsinfo *p2;
   1883     register long result;
   1884 
   1885     /* remove one level of indirection */
   1886     p1 = *pp1;
   1887     p2 = *pp2;
   1888 
   1889     ORDERKEY_PID
   1890     ORDERKEY_LWP
   1891     ;
   1892 
   1893     return (result);
   1894 }
   1895 
   1896 /* get process table */
   1897 int
   1898 getptable (struct prpsinfo *baseptr)
   1899 {
   1900     struct prpsinfo *currproc;	/* pointer to current proc structure	*/
   1901 #ifndef USE_NEW_PROC
   1902     struct prstatus prstatus;     /* for additional information */
   1903 #endif
   1904     int numprocs = 0;
   1905     struct dirent *direntp;
   1906     struct oldproc *op;
   1907     hash_pos pos;
   1908     hash_item_pid *hi;
   1909     hash_item_pidthr *hip;
   1910     prheader_t *prp;
   1911     lwpsinfo_t *lwpp;
   1912     pidthr_t pidthr;
   1913     static struct timeval lasttime =
   1914 	{0, 0};
   1915     struct timeval thistime;
   1916     struct stat st;
   1917     double timediff;
   1918 
   1919     gettimeofday (&thistime, NULL);
   1920     /*
   1921      * To avoid divides, we keep times in nanoseconds.  This is
   1922      * scaled by 1e7 rather than 1e9 so that when we divide we
   1923      * get percent.
   1924      */
   1925     if (lasttime.tv_sec)
   1926 	timediff = ((double) thistime.tv_sec * 1.0e7 +
   1927 		    ((double) thistime.tv_usec * 10.0)) -
   1928 	    ((double) lasttime.tv_sec * 1.0e7 +
   1929 	     ((double) lasttime.tv_usec * 10.0));
   1930     else
   1931 	timediff = 1.0e7;
   1932 
   1933     /* get our first procs pointer */
   1934     currproc = procs_start();
   1935 
   1936     /* before reading /proc files, turn on root privs */
   1937     /* (we don't care if this fails since it will be caught later) */
   1938 #ifndef USE_NEW_PROC
   1939     seteuid(0);
   1940 #endif
   1941 
   1942     for (rewinddir (procdir); (direntp = readdir (procdir));)
   1943     {
   1944 	int fd;
   1945 	int pid;
   1946 	char buf[40];
   1947 
   1948 	/* skip dot files */
   1949 	if (direntp->d_name[0] == '.')
   1950 	    continue;
   1951 
   1952 	/* convert pid to a number (and make sure its valid) */
   1953 	pid = atoi(direntp->d_name);
   1954 	if (pid <= 0)
   1955 	    continue;
   1956 
   1957 	/* fetch the old proc data */
   1958 	op = (struct oldproc *)hash_lookup_pid(prochash, pid);
   1959 	if (op == NULL)
   1960 	{
   1961 	    /* new proc: create an entry for it */
   1962 	    op = (struct oldproc *)malloc(sizeof(struct oldproc));
   1963 	    hash_add_pid(prochash, pid, (void *)op);
   1964 	    op->pid = pid;
   1965 	    op->fd_psinfo = -1;
   1966 	    op->fd_lpsinfo = -1;
   1967 	    op->oldtime = 0.0;
   1968 	}
   1969 
   1970 	/* do we have a cached file? */
   1971 	fd = op->fd_psinfo;
   1972 	if (fd == -1)
   1973 	{
   1974 	    /* no: open the psinfo file */
   1975 	    snprintf(buf, sizeof(buf), "%s/psinfo", direntp->d_name);
   1976 	    if ((fd = open(buf, O_RDONLY)) < 0)
   1977 	    {
   1978 		/* cleanup??? */
   1979 		continue;
   1980 	    }
   1981 	}
   1982 
   1983 	/* read data from the file */
   1984 #ifdef USE_NEW_PROC
   1985 	if (pread(fd, currproc, sizeof(psinfo_t), 0) != sizeof(psinfo_t))
   1986 	{
   1987 	    (void) close (fd);
   1988 	    op->fd_psinfo = -1;
   1989 	    continue;
   1990 	}
   1991 #else
   1992 	if (ioctl(fd, PIOCPSINFO, currproc) < 0)
   1993 	{
   1994 	    (void) close(fd);
   1995 	    op->fd_psinfo = -1;
   1996 	    continue;
   1997 	}
   1998 
   1999 	if (ioctl(fd, PIOCSTATUS, &prstatus) < 0)
   2000 	{
   2001 	    /* not a show stopper -- just fill in the needed values */
   2002 	    currproc->pr_fill = 0;
   2003 	    currproc->px_onpro = 0;
   2004 	}
   2005 	else
   2006 	{
   2007 	    /* copy over the values we need from prstatus */
   2008 	    currproc->pr_fill = (short)prstatus.pr_nlwp;
   2009 	    currproc->px_onpro = prstatus.pr_processor;
   2010 	}
   2011 #endif
   2012 
   2013 	/*
   2014 	 * We track our own cpu% usage.
   2015 	 * We compute it based on CPU since the last update by calculating
   2016 	 * the difference in cumulative cpu time and dividing by the amount
   2017 	 * of time we measured between updates (timediff).
   2018 	 * NOTE:  Solaris 2.4 and higher do maintain CPU% in psinfo,
   2019 	 * but it does not produce the kind of results we really want,
   2020 	 * so we don't use it even though its there.
   2021 	 */
   2022 	if (lasttime.tv_sec > 0)
   2023 	{
   2024 	    percent_cpu(currproc) =
   2025 		(TIMESPEC_TO_DOUBLE(currproc->pr_time) - op->oldtime) / timediff;
   2026 	}
   2027 	else
   2028 	{
   2029 	    /* first screen -- no difference is possible */
   2030 	    percent_cpu(currproc) = 0.0;
   2031 	}
   2032 
   2033 	/* save data for next time */
   2034 	op->pid = currproc->pr_pid;
   2035 	op->oldtime = TIMESPEC_TO_DOUBLE(currproc->pr_time);
   2036 	op->owner_uid = currproc->pr_uid;
   2037 	op->seen = 1;
   2038 
   2039 	/* cache the file descriptor if we can */
   2040 	if (fd < maxfiles)
   2041 	{
   2042 	    op->fd_psinfo = fd;
   2043 	}
   2044 	else
   2045 	{
   2046 	    (void) close(fd);
   2047 	}
   2048 
   2049 #ifdef USE_NEW_PROC
   2050 	/* collect up the threads */
   2051 	/* use cached lps file if it's there */
   2052 	fd = op->fd_lpsinfo;
   2053 	if (fd == -1)
   2054 	{
   2055 	    snprintf(buf, sizeof(buf), "%s/lpsinfo", direntp->d_name);
   2056 	    fd = open(buf, O_RDONLY);
   2057 	}
   2058 
   2059 	/* make sure we have a valid descriptor and the file's current size */
   2060 	if (fd >= 0 && fstat(fd, &st) != -1)
   2061 	{
   2062 	    char *p;
   2063 	    int i;
   2064 
   2065 	    /* read the whole file */
   2066 	    p = malloc(st.st_size);
   2067 	    (void)pread(fd, p, st.st_size, 0);
   2068 
   2069 	    /* cache the file descriptor if we can */
   2070 	    if (fd < maxfiles)
   2071 	    {
   2072 		op->fd_lpsinfo = fd;
   2073 	    }
   2074 	    else
   2075 	    {
   2076 		(void)close(fd);
   2077 	    }
   2078 
   2079 	    /* the file starts with a struct prheader */
   2080 	    prp = (prheader_t *)p;
   2081 	    p += sizeof(prheader_t);
   2082 
   2083 	    /* there are prp->pr_nent entries in the file */
   2084 	    for (i = 0; i < prp->pr_nent; i++)
   2085 	    {
   2086 		/* process this entry */
   2087 		lwpp = (lwpsinfo_t *)p;
   2088 		p += prp->pr_entsize;
   2089 
   2090 		/* fetch the old thread data */
   2091 		/* this hash is indexed by both pid and lwpid */
   2092 		pidthr.k_pid = currproc->pr_pid;
   2093 		pidthr.k_thr = lwpp->pr_lwpid;
   2094 		dprintf("getptable: processing %d.%d\n",
   2095 			pidthr.k_pid, pidthr.k_thr);
   2096 		op = (struct oldproc *)hash_lookup_pidthr(threadhash, pidthr);
   2097 		if (op == NULL)
   2098 		{
   2099 		    /* new thread: create an entry for it */
   2100 		    op = (struct oldproc *)malloc(sizeof(struct oldproc));
   2101 		    hash_add_pidthr(threadhash, pidthr, (void *)op);
   2102 		    op->pid = pid;
   2103 		    op->lwpid = lwpp->pr_lwpid;
   2104 		    op->oldtime = 0.0;
   2105 		    dprintf("getptable: %d.%d: new thread\n",
   2106 			    pidthr.k_pid, pidthr.k_thr);
   2107 		}
   2108 
   2109 		/* are we showing individual threads? */
   2110 		if (show_threads)
   2111 		{
   2112 		    /* yes: if this is the first thread we reuse the proc
   2113 		       entry we have, otherwise we create a new one by
   2114 		       duping the current one */
   2115 		    if (i > 0)
   2116 		    {
   2117 			currproc = procs_dup(currproc);
   2118 			numprocs++;
   2119 		    }
   2120 
   2121 		    /* yes: copy over thread-specific data */
   2122 		    currproc->pr_time = lwpp->pr_time;
   2123 		    currproc->px_state = lwpp->pr_state;
   2124 		    currproc->px_pri = lwpp->pr_pri;
   2125 		    currproc->px_onpro = lwpp->pr_onpro;
   2126 		    currproc->pr_lwp.pr_lwpid = lwpp->pr_lwpid;
   2127 
   2128 		    /* calculate percent cpu for just this thread */
   2129 		    if (lasttime.tv_sec > 0)
   2130 		    {
   2131 			percent_cpu(currproc) =
   2132 			    (TIMESPEC_TO_DOUBLE(lwpp->pr_time) - op->oldtime) /
   2133 			    timediff;
   2134 		    }
   2135 		    else
   2136 		    {
   2137 			/* first screen -- no difference is possible */
   2138 			percent_cpu(currproc) = 0.0;
   2139 		    }
   2140 
   2141 		    dprintf("getptable: %d.%d: time %.0f, state %d, pctcpu %.2f\n",
   2142 			    currproc->pr_pid, lwpp->pr_lwpid,
   2143 			    TIMESPEC_TO_DOUBLE(currproc->pr_time),
   2144 			    currproc->px_state, percent_cpu(currproc));
   2145 		}
   2146 
   2147 		/* save data for next time */
   2148 		op->oldtime = TIMESPEC_TO_DOUBLE(lwpp->pr_time);
   2149 		op->seen = 1;
   2150 	    }
   2151 	    free(p);
   2152 	}
   2153 #endif
   2154 
   2155 	/* move to next */
   2156 	numprocs++;
   2157 	currproc = procs_next();
   2158     }
   2159 
   2160 #ifndef USE_NEW_PROC
   2161     /* turn off root privs */
   2162     seteuid(getuid());
   2163 #endif
   2164 
   2165     dprintf("getptable saw %d procs\n", numprocs);
   2166 
   2167     /* scan the hash tables and remove dead entries */
   2168     hi = hash_first_pid(prochash, &pos);
   2169     while (hi != NULL)
   2170     {
   2171 	op = (struct oldproc *)(hi->value);
   2172 	if (op->seen)
   2173 	{
   2174 	    op->seen = 0;
   2175 	}
   2176 	else
   2177 	{
   2178 	    dprintf("removing %d from prochash\n", op->pid);
   2179 	    if (op->fd_psinfo >= 0)
   2180 	    {
   2181 		(void)close(op->fd_psinfo);
   2182 	    }
   2183 	    if (op->fd_lpsinfo >= 0)
   2184 	    {
   2185 		(void)close(op->fd_lpsinfo);
   2186 	    }
   2187 	    hash_remove_pos_pid(&pos);
   2188 	    free(op);
   2189 	}
   2190 	hi = hash_next_pid(&pos);
   2191     }
   2192 
   2193     hip = hash_first_pidthr(threadhash, &pos);
   2194     while (hip != NULL)
   2195     {
   2196 	op = (struct oldproc *)(hip->value);
   2197 	if (op->seen)
   2198 	{
   2199 	    op->seen = 0;
   2200 	}
   2201 	else
   2202 	{
   2203 	    dprintf("removing %d from threadhash\n", op->pid);
   2204 	    hash_remove_pos_pidthr(&pos);
   2205 	    free(op);
   2206 	}
   2207 	hip = hash_next_pidthr(&pos);
   2208     }
   2209 
   2210     lasttime = thistime;
   2211 
   2212     return numprocs;
   2213 }
   2214 
   2215 /*
   2216  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
   2217  *              the process does not exist.
   2218  *              It is EXTREMLY IMPORTANT that this function work correctly.
   2219  *              If top runs setuid root (as in SVR4), then this function
   2220  *              is the only thing that stands in the way of a serious
   2221  *              security problem.  It validates requests for the "kill"
   2222  *              and "renice" commands.
   2223  */
   2224 int
   2225 proc_owner (int pid)
   2226 {
   2227     struct oldproc *op;
   2228 
   2229     /* we keep this information in the hash table */
   2230     op = (struct oldproc *)hash_lookup_pid(prochash, (pid_t)pid);
   2231     if (op != NULL)
   2232     {
   2233 	return((int)(op->owner_uid));
   2234     }
   2235     return(-1);
   2236 }
   2237 
   2238 /* older revisions don't supply a setpriority */
   2239 #if (OSREV < 55)
   2240 int
   2241 setpriority (int dummy, int who, int niceval)
   2242 {
   2243     int scale;
   2244     int prio;
   2245     pcinfo_t pcinfo;
   2246     pcparms_t pcparms;
   2247     tsparms_t *tsparms;
   2248 
   2249     strcpy (pcinfo.pc_clname, "TS");
   2250     if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
   2251 	return (-1);
   2252 
   2253     prio = niceval;
   2254     if (prio > PRIO_MAX)
   2255 	prio = PRIO_MAX;
   2256     else if (prio < PRIO_MIN)
   2257 	prio = PRIO_MIN;
   2258 
   2259     tsparms = (tsparms_t *) pcparms.pc_clparms;
   2260     scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
   2261     tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
   2262     pcparms.pc_cid = pcinfo.pc_cid;
   2263 
   2264     if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
   2265 	return (-1);
   2266 
   2267     return (0);
   2268 }
   2269 #endif
   2270 
   2271