xref: /minix/external/bsd/top/dist/machine/m_sunos5.c (revision b89261ba)
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@techfak.uni-bielefeld.de>
14  *               Robert Boucher		<boucher@sofkin.ca>
15  * CONTRIBUTORS: Marc Cohen 		<marc@aai.com>
16  *               Charles Hedrick 	<hedrick@geneva.rutgers.edu>
17  *	         William L. Jones 	<jones@chpc>
18  *               Petri Kutvonen         <kutvonen@cs.helsinki.fi>
19  *	         Casper Dik             <casper.dik@sun.com>
20  *               Tim Pugh               <tpugh@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
fmt_pid(char * buf,int sz,struct prpsinfo * pp)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
fmt_username(char * buf,int sz,struct prpsinfo * pp)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
fmt_uid(char * buf,int sz,struct prpsinfo * pp)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
fmt_nlwp(char * buf,int sz,struct prpsinfo * pp)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
fmt_pri(char * buf,int sz,struct prpsinfo * pp)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
fmt_nice(char * buf,int sz,struct prpsinfo * pp)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
fmt_size(char * buf,int sz,struct prpsinfo * pp)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
fmt_res(char * buf,int sz,struct prpsinfo * pp)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
fmt_state(char * buf,int sz,struct prpsinfo * pp)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
fmt_time(char * buf,int sz,struct prpsinfo * pp)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
fmt_cpu(char * buf,int sz,struct prpsinfo * pp)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
fmt_command(char * buf,int sz,struct prpsinfo * pp)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
fmt_lwp(char * buf,int sz,struct prpsinfo * pp)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
field_index(char * col)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
field_subst(int * fp,int old,int new)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 
pagetok_none(long size)515 long pagetok_none(long size)
516 
517 {
518     return(size);
519 }
520 
pagetok_left(long size)521 long pagetok_left(long size)
522 
523 {
524     return(size << pageshift);
525 }
526 
pagetok_right(long size)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
getkval(unsigned long offset,int * ptr,int size,char * refstr)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
procs_prealloc(int max)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 *
procs_next()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 *
procs_dup(struct prpsinfo * p)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 *
procs_start()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
procs_max()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
check_nlist(register struct nlist * nlst)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 *
format_header(register char * uname_field)703 format_header (register char *uname_field)
704 {
705   return ("");
706 }
707 
708 #ifdef USE_KSTAT
709 
710 long
kstat_data_value_l(kstat_named_t * kn)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
kstat_safe_retrieve(kstat_t ** ksp,char * module,int instance,char * name,void * buf)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
kstat_safe_namematch(int num,kstat_t ** ksparg,char * name,void * buf,int size)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
get_avenrun(int avenrun[3])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
get_ncpus()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
get_nproc()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 *
get_cpustats(int * cnt,struct cpustats * 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
get_meminfo(long * total,long * fr)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
get_swapinfo(long * total,long * fr)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
machine_init(struct statics * statics)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
get_system_info(struct system_info * si)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
get_process_info(struct system_info * si,struct process_select * sel,int compare_index)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 *
format_process_header(struct process_select * sel,caddr_t handle,int count)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 *
format_next_process(caddr_t handle,char * (* get_userid)(int))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
compare_cpu(struct prpsinfo ** pp1,struct prpsinfo ** pp2)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
compare_size(struct prpsinfo ** pp1,struct prpsinfo ** pp2)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
compare_res(struct prpsinfo ** pp1,struct prpsinfo ** pp2)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
compare_time(struct prpsinfo ** pp1,struct prpsinfo ** pp2)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
compare_pid(struct prpsinfo ** pp1,struct prpsinfo ** pp2)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
getptable(struct prpsinfo * baseptr)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
proc_owner(int pid)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
setpriority(int dummy,int who,int niceval)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