xref: /freebsd/usr.bin/top/machine.c (revision 94154ff82b9968b88d1c9ce36235d05fe059192c)
1511d9c65SJoerg Wunsch /*
2511d9c65SJoerg Wunsch  * top - a top users display for Unix
3511d9c65SJoerg Wunsch  *
4511d9c65SJoerg Wunsch  * SYNOPSIS:  For FreeBSD-2.x system
5511d9c65SJoerg Wunsch  *
6511d9c65SJoerg Wunsch  * DESCRIPTION:
7511d9c65SJoerg Wunsch  * Originally written for BSD4.4 system by Christos Zoulas.
8511d9c65SJoerg Wunsch  * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
9511d9c65SJoerg Wunsch  *
10511d9c65SJoerg Wunsch  * This is the machine-dependent module for FreeBSD 2.2
11511d9c65SJoerg Wunsch  * Works for:
12511d9c65SJoerg Wunsch  *	FreeBSD 2.2, and probably FreeBSD 2.1.x
13511d9c65SJoerg Wunsch  *
14511d9c65SJoerg Wunsch  * LIBS: -lkvm
15511d9c65SJoerg Wunsch  *
16511d9c65SJoerg Wunsch  * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
17511d9c65SJoerg Wunsch  *          Steven Wallace  <swallace@freebsd.org>
18511d9c65SJoerg Wunsch  *          Wolfram Schneider <wosch@FreeBSD.org>
19511d9c65SJoerg Wunsch  *
2094154ff8SPeter Wemm  * $Id: machine.c,v 1.3 1997/04/21 13:53:47 ache Exp $
21511d9c65SJoerg Wunsch  */
22511d9c65SJoerg Wunsch 
23511d9c65SJoerg Wunsch 
24511d9c65SJoerg Wunsch #include <sys/types.h>
25511d9c65SJoerg Wunsch #include <sys/signal.h>
26511d9c65SJoerg Wunsch #include <sys/param.h>
27511d9c65SJoerg Wunsch 
28511d9c65SJoerg Wunsch #include "os.h"
29511d9c65SJoerg Wunsch #include <stdio.h>
30511d9c65SJoerg Wunsch #include <nlist.h>
31511d9c65SJoerg Wunsch #include <math.h>
32511d9c65SJoerg Wunsch #include <kvm.h>
33511d9c65SJoerg Wunsch #include <sys/errno.h>
34511d9c65SJoerg Wunsch #include <sys/sysctl.h>
35511d9c65SJoerg Wunsch #include <sys/dkstat.h>
36511d9c65SJoerg Wunsch #include <sys/file.h>
37511d9c65SJoerg Wunsch #include <sys/time.h>
38511d9c65SJoerg Wunsch #include <sys/proc.h>
39511d9c65SJoerg Wunsch #include <sys/user.h>
40511d9c65SJoerg Wunsch #include <sys/vmmeter.h>
41511d9c65SJoerg Wunsch 
42511d9c65SJoerg Wunsch /* Swap */
43511d9c65SJoerg Wunsch #include <stdlib.h>
44511d9c65SJoerg Wunsch #include <sys/rlist.h>
45511d9c65SJoerg Wunsch #include <sys/conf.h>
46511d9c65SJoerg Wunsch 
47511d9c65SJoerg Wunsch #include <osreldate.h> /* for changes in kernel structures */
48511d9c65SJoerg Wunsch 
49511d9c65SJoerg Wunsch #include "top.h"
50511d9c65SJoerg Wunsch #include "machine.h"
51511d9c65SJoerg Wunsch 
52511d9c65SJoerg Wunsch static int check_nlist __P((struct nlist *));
53511d9c65SJoerg Wunsch static int getkval __P((unsigned long, int *, int, char *));
54511d9c65SJoerg Wunsch extern char* printable __P((char *));
55511d9c65SJoerg Wunsch int swapmode __P((int *retavail, int *retfree));
5694154ff8SPeter Wemm static int smpmode;
57511d9c65SJoerg Wunsch 
58511d9c65SJoerg Wunsch 
59511d9c65SJoerg Wunsch 
60511d9c65SJoerg Wunsch /* get_process_info passes back a handle.  This is what it looks like: */
61511d9c65SJoerg Wunsch 
62511d9c65SJoerg Wunsch struct handle
63511d9c65SJoerg Wunsch {
64511d9c65SJoerg Wunsch     struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
65511d9c65SJoerg Wunsch     int remaining;		/* number of pointers remaining */
66511d9c65SJoerg Wunsch };
67511d9c65SJoerg Wunsch 
68511d9c65SJoerg Wunsch /* declarations for load_avg */
69511d9c65SJoerg Wunsch #include "loadavg.h"
70511d9c65SJoerg Wunsch 
71511d9c65SJoerg Wunsch #define PP(pp, field) ((pp)->kp_proc . field)
72511d9c65SJoerg Wunsch #define EP(pp, field) ((pp)->kp_eproc . field)
73511d9c65SJoerg Wunsch #define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
74511d9c65SJoerg Wunsch 
75511d9c65SJoerg Wunsch /* define what weighted cpu is.  */
76511d9c65SJoerg Wunsch #define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
77511d9c65SJoerg Wunsch 			 ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))
78511d9c65SJoerg Wunsch 
79511d9c65SJoerg Wunsch /* what we consider to be process size: */
80511d9c65SJoerg Wunsch #define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
81511d9c65SJoerg Wunsch 
82511d9c65SJoerg Wunsch /* definitions for indices in the nlist array */
83511d9c65SJoerg Wunsch 
84511d9c65SJoerg Wunsch 
85511d9c65SJoerg Wunsch static struct nlist nlst[] = {
86511d9c65SJoerg Wunsch #define X_CCPU		0
87511d9c65SJoerg Wunsch     { "_ccpu" },		/* 0 */
88511d9c65SJoerg Wunsch #define X_CP_TIME	1
89511d9c65SJoerg Wunsch     { "_cp_time" },		/* 1 */
90511d9c65SJoerg Wunsch #define X_HZ		2
91511d9c65SJoerg Wunsch     { "_hz" },		        /* 2 */
92511d9c65SJoerg Wunsch #define X_STATHZ	3
93511d9c65SJoerg Wunsch     { "_stathz" },		/* 3 */
94511d9c65SJoerg Wunsch #define X_AVENRUN	4
95511d9c65SJoerg Wunsch     { "_averunnable" },		/* 4 */
96511d9c65SJoerg Wunsch 
97511d9c65SJoerg Wunsch /* Swap */
98511d9c65SJoerg Wunsch #define VM_SWAPLIST	5
99511d9c65SJoerg Wunsch 	{ "_swaplist" },/* list of free swap areas */
100511d9c65SJoerg Wunsch #define VM_SWDEVT	6
101511d9c65SJoerg Wunsch 	{ "_swdevt" },	/* list of swap devices and sizes */
102511d9c65SJoerg Wunsch #define VM_NSWAP	7
103511d9c65SJoerg Wunsch 	{ "_nswap" },	/* size of largest swap device */
104511d9c65SJoerg Wunsch #define VM_NSWDEV	8
105511d9c65SJoerg Wunsch 	{ "_nswdev" },	/* number of swap devices */
106511d9c65SJoerg Wunsch #define VM_DMMAX	9
107511d9c65SJoerg Wunsch 	{ "_dmmax" },	/* maximum size of a swap block */
108511d9c65SJoerg Wunsch #define X_BUFSPACE	10
109511d9c65SJoerg Wunsch 	{ "_bufspace" },	/* K in buffer cache */
110511d9c65SJoerg Wunsch #define X_CNT           11
111511d9c65SJoerg Wunsch     { "_cnt" },		        /* struct vmmeter cnt */
112511d9c65SJoerg Wunsch 
113511d9c65SJoerg Wunsch /* Last pid */
114511d9c65SJoerg Wunsch #define X_LASTPID	12
115511d9c65SJoerg Wunsch     { "_nextpid" },
116511d9c65SJoerg Wunsch     { 0 }
117511d9c65SJoerg Wunsch };
118511d9c65SJoerg Wunsch 
119511d9c65SJoerg Wunsch /*
120511d9c65SJoerg Wunsch  *  These definitions control the format of the per-process area
121511d9c65SJoerg Wunsch  */
122511d9c65SJoerg Wunsch 
12394154ff8SPeter Wemm static char smp_header[] =
124511d9c65SJoerg Wunsch   "  PID X                PRI NICE SIZE   RES STATE C   TIME   WCPU    CPU COMMAND";
125511d9c65SJoerg Wunsch /* 0123456   -- field to fill in starts at header+6 */
12694154ff8SPeter Wemm #define SMP_UNAME_START 6
127511d9c65SJoerg Wunsch 
12894154ff8SPeter Wemm #define smp_Proc_format \
129595c8b2fSAndrey A. Chernov 	"%5d %-16.16s%3d%3d%7s %6s %-6.6s%1x%7s %5.2f%% %5.2f%% %.6s"
130511d9c65SJoerg Wunsch 
13194154ff8SPeter Wemm static char up_header[] =
132511d9c65SJoerg Wunsch   "  PID X                PRI NICE SIZE    RES STATE    TIME   WCPU    CPU COMMAND";
133511d9c65SJoerg Wunsch /* 0123456   -- field to fill in starts at header+6 */
13494154ff8SPeter Wemm #define UP_UNAME_START 6
135511d9c65SJoerg Wunsch 
13694154ff8SPeter Wemm #define up_Proc_format \
13794154ff8SPeter Wemm 	"%5d %-16.16s%3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.6s"
138511d9c65SJoerg Wunsch 
139511d9c65SJoerg Wunsch 
140511d9c65SJoerg Wunsch 
141511d9c65SJoerg Wunsch /* process state names for the "STATE" column of the display */
142511d9c65SJoerg Wunsch /* the extra nulls in the string "run" are for adding a slash and
143511d9c65SJoerg Wunsch    the processor number when needed */
144511d9c65SJoerg Wunsch 
145511d9c65SJoerg Wunsch char *state_abbrev[] =
146511d9c65SJoerg Wunsch {
147511d9c65SJoerg Wunsch     "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB",
148511d9c65SJoerg Wunsch };
149511d9c65SJoerg Wunsch 
150511d9c65SJoerg Wunsch 
151511d9c65SJoerg Wunsch static kvm_t *kd;
152511d9c65SJoerg Wunsch 
153511d9c65SJoerg Wunsch /* values that we stash away in _init and use in later routines */
154511d9c65SJoerg Wunsch 
155511d9c65SJoerg Wunsch static double logcpu;
156511d9c65SJoerg Wunsch 
157511d9c65SJoerg Wunsch /* these are retrieved from the kernel in _init */
158511d9c65SJoerg Wunsch 
159511d9c65SJoerg Wunsch static          long hz;
160511d9c65SJoerg Wunsch static load_avg  ccpu;
161511d9c65SJoerg Wunsch 
162511d9c65SJoerg Wunsch /* these are offsets obtained via nlist and used in the get_ functions */
163511d9c65SJoerg Wunsch 
164511d9c65SJoerg Wunsch static unsigned long cp_time_offset;
165511d9c65SJoerg Wunsch static unsigned long avenrun_offset;
166511d9c65SJoerg Wunsch static unsigned long lastpid_offset;
167511d9c65SJoerg Wunsch static long lastpid;
168511d9c65SJoerg Wunsch static unsigned long cnt_offset;
169511d9c65SJoerg Wunsch static unsigned long bufspace_offset;
170511d9c65SJoerg Wunsch static long cnt;
171511d9c65SJoerg Wunsch 
172511d9c65SJoerg Wunsch /* these are for calculating cpu state percentages */
173511d9c65SJoerg Wunsch 
174511d9c65SJoerg Wunsch static long cp_time[CPUSTATES];
175511d9c65SJoerg Wunsch static long cp_old[CPUSTATES];
176511d9c65SJoerg Wunsch static long cp_diff[CPUSTATES];
177511d9c65SJoerg Wunsch 
178511d9c65SJoerg Wunsch /* these are for detailing the process states */
179511d9c65SJoerg Wunsch 
180511d9c65SJoerg Wunsch int process_states[6];
181511d9c65SJoerg Wunsch char *procstatenames[] = {
182511d9c65SJoerg Wunsch     "", " starting, ", " running, ", " sleeping, ", " stopped, ",
183511d9c65SJoerg Wunsch     " zombie, ",
184511d9c65SJoerg Wunsch     NULL
185511d9c65SJoerg Wunsch };
186511d9c65SJoerg Wunsch 
187511d9c65SJoerg Wunsch /* these are for detailing the cpu states */
188511d9c65SJoerg Wunsch 
189511d9c65SJoerg Wunsch int cpu_states[CPUSTATES];
190511d9c65SJoerg Wunsch char *cpustatenames[] = {
191511d9c65SJoerg Wunsch     "user", "nice", "system", "interrupt", "idle", NULL
192511d9c65SJoerg Wunsch };
193511d9c65SJoerg Wunsch 
194511d9c65SJoerg Wunsch /* these are for detailing the memory statistics */
195511d9c65SJoerg Wunsch 
196511d9c65SJoerg Wunsch int memory_stats[7];
197511d9c65SJoerg Wunsch char *memorynames[] = {
198511d9c65SJoerg Wunsch     "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
199511d9c65SJoerg Wunsch     NULL
200511d9c65SJoerg Wunsch };
201511d9c65SJoerg Wunsch 
202511d9c65SJoerg Wunsch int swap_stats[7];
203511d9c65SJoerg Wunsch char *swapnames[] = {
204511d9c65SJoerg Wunsch /*   0           1            2           3            4       5 */
205511d9c65SJoerg Wunsch     "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
206511d9c65SJoerg Wunsch     NULL
207511d9c65SJoerg Wunsch };
208511d9c65SJoerg Wunsch 
209511d9c65SJoerg Wunsch 
210511d9c65SJoerg Wunsch /* these are for keeping track of the proc array */
211511d9c65SJoerg Wunsch 
212511d9c65SJoerg Wunsch static int nproc;
213511d9c65SJoerg Wunsch static int onproc = -1;
214511d9c65SJoerg Wunsch static int pref_len;
215511d9c65SJoerg Wunsch static struct kinfo_proc *pbase;
216511d9c65SJoerg Wunsch static struct kinfo_proc **pref;
217511d9c65SJoerg Wunsch 
218511d9c65SJoerg Wunsch /* these are for getting the memory statistics */
219511d9c65SJoerg Wunsch 
220511d9c65SJoerg Wunsch static int pageshift;		/* log base 2 of the pagesize */
221511d9c65SJoerg Wunsch 
222511d9c65SJoerg Wunsch /* define pagetok in terms of pageshift */
223511d9c65SJoerg Wunsch 
224511d9c65SJoerg Wunsch #define pagetok(size) ((size) << pageshift)
225511d9c65SJoerg Wunsch 
226511d9c65SJoerg Wunsch /* useful externals */
227511d9c65SJoerg Wunsch long percentages();
228511d9c65SJoerg Wunsch 
229511d9c65SJoerg Wunsch int
230511d9c65SJoerg Wunsch machine_init(statics)
231511d9c65SJoerg Wunsch 
232511d9c65SJoerg Wunsch struct statics *statics;
233511d9c65SJoerg Wunsch 
234511d9c65SJoerg Wunsch {
235511d9c65SJoerg Wunsch     register int i = 0;
236511d9c65SJoerg Wunsch     register int pagesize;
23794154ff8SPeter Wemm     int modelen;
23894154ff8SPeter Wemm 
23994154ff8SPeter Wemm     modelen = sizeof(smpmode);
24094154ff8SPeter Wemm     if (sysctlbyname("kern.smp_active", &smpmode, &modelen, NULL, 0) < 0 ||
24194154ff8SPeter Wemm 	modelen != sizeof(smpmode))
24294154ff8SPeter Wemm 	    smpmode = 0;
243511d9c65SJoerg Wunsch 
244511d9c65SJoerg Wunsch     if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
245511d9c65SJoerg Wunsch 	return -1;
246511d9c65SJoerg Wunsch 
247511d9c65SJoerg Wunsch 
248511d9c65SJoerg Wunsch     /* get the list of symbols we want to access in the kernel */
249511d9c65SJoerg Wunsch     (void) kvm_nlist(kd, nlst);
250511d9c65SJoerg Wunsch     if (nlst[0].n_type == 0)
251511d9c65SJoerg Wunsch     {
252511d9c65SJoerg Wunsch 	fprintf(stderr, "top: nlist failed\n");
253511d9c65SJoerg Wunsch 	return(-1);
254511d9c65SJoerg Wunsch     }
255511d9c65SJoerg Wunsch 
256511d9c65SJoerg Wunsch     /* make sure they were all found */
257511d9c65SJoerg Wunsch     if (i > 0 && check_nlist(nlst) > 0)
258511d9c65SJoerg Wunsch     {
259511d9c65SJoerg Wunsch 	return(-1);
260511d9c65SJoerg Wunsch     }
261511d9c65SJoerg Wunsch 
262511d9c65SJoerg Wunsch     /* get the symbol values out of kmem */
263511d9c65SJoerg Wunsch     (void) getkval(nlst[X_STATHZ].n_value, (int *)(&hz), sizeof(hz), "!");
264511d9c65SJoerg Wunsch     if (!hz) {
265511d9c65SJoerg Wunsch 	(void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
266511d9c65SJoerg Wunsch 		       nlst[X_HZ].n_name);
267511d9c65SJoerg Wunsch     }
268511d9c65SJoerg Wunsch 
269511d9c65SJoerg Wunsch     (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),	sizeof(ccpu),
270511d9c65SJoerg Wunsch 	    nlst[X_CCPU].n_name);
271511d9c65SJoerg Wunsch 
272511d9c65SJoerg Wunsch     /* stash away certain offsets for later use */
273511d9c65SJoerg Wunsch     cp_time_offset = nlst[X_CP_TIME].n_value;
274511d9c65SJoerg Wunsch     avenrun_offset = nlst[X_AVENRUN].n_value;
275511d9c65SJoerg Wunsch     lastpid_offset =  nlst[X_LASTPID].n_value;
276511d9c65SJoerg Wunsch     cnt_offset = nlst[X_CNT].n_value;
277511d9c65SJoerg Wunsch     bufspace_offset = nlst[X_BUFSPACE].n_value;
278511d9c65SJoerg Wunsch 
279511d9c65SJoerg Wunsch     /* this is used in calculating WCPU -- calculate it ahead of time */
280511d9c65SJoerg Wunsch     logcpu = log(loaddouble(ccpu));
281511d9c65SJoerg Wunsch 
282511d9c65SJoerg Wunsch     pbase = NULL;
283511d9c65SJoerg Wunsch     pref = NULL;
284511d9c65SJoerg Wunsch     nproc = 0;
285511d9c65SJoerg Wunsch     onproc = -1;
286511d9c65SJoerg Wunsch     /* get the page size with "getpagesize" and calculate pageshift from it */
287511d9c65SJoerg Wunsch     pagesize = getpagesize();
288511d9c65SJoerg Wunsch     pageshift = 0;
289511d9c65SJoerg Wunsch     while (pagesize > 1)
290511d9c65SJoerg Wunsch     {
291511d9c65SJoerg Wunsch 	pageshift++;
292511d9c65SJoerg Wunsch 	pagesize >>= 1;
293511d9c65SJoerg Wunsch     }
294511d9c65SJoerg Wunsch 
295511d9c65SJoerg Wunsch     /* we only need the amount of log(2)1024 for our conversion */
296511d9c65SJoerg Wunsch     pageshift -= LOG1024;
297511d9c65SJoerg Wunsch 
298511d9c65SJoerg Wunsch     /* fill in the statics information */
299511d9c65SJoerg Wunsch     statics->procstate_names = procstatenames;
300511d9c65SJoerg Wunsch     statics->cpustate_names = cpustatenames;
301511d9c65SJoerg Wunsch     statics->memory_names = memorynames;
302511d9c65SJoerg Wunsch     statics->swap_names = swapnames;
303511d9c65SJoerg Wunsch 
304511d9c65SJoerg Wunsch     /* all done! */
305511d9c65SJoerg Wunsch     return(0);
306511d9c65SJoerg Wunsch }
307511d9c65SJoerg Wunsch 
308511d9c65SJoerg Wunsch char *format_header(uname_field)
309511d9c65SJoerg Wunsch 
310511d9c65SJoerg Wunsch register char *uname_field;
311511d9c65SJoerg Wunsch 
312511d9c65SJoerg Wunsch {
313511d9c65SJoerg Wunsch     register char *ptr;
314511d9c65SJoerg Wunsch 
31594154ff8SPeter Wemm     if (smpmode)
31694154ff8SPeter Wemm 	ptr = smp_header + SMP_UNAME_START;
31794154ff8SPeter Wemm     else
31894154ff8SPeter Wemm 	ptr = up_header + UP_UNAME_START;
31994154ff8SPeter Wemm 
320511d9c65SJoerg Wunsch     while (*uname_field != '\0')
321511d9c65SJoerg Wunsch     {
322511d9c65SJoerg Wunsch 	*ptr++ = *uname_field++;
323511d9c65SJoerg Wunsch     }
324511d9c65SJoerg Wunsch 
32594154ff8SPeter Wemm     return(smpmode ? smp_header : up_header);
326511d9c65SJoerg Wunsch }
327511d9c65SJoerg Wunsch 
328511d9c65SJoerg Wunsch static int swappgsin = -1;
329511d9c65SJoerg Wunsch static int swappgsout = -1;
330511d9c65SJoerg Wunsch extern struct timeval timeout;
331511d9c65SJoerg Wunsch 
332511d9c65SJoerg Wunsch void
333511d9c65SJoerg Wunsch get_system_info(si)
334511d9c65SJoerg Wunsch 
335511d9c65SJoerg Wunsch struct system_info *si;
336511d9c65SJoerg Wunsch 
337511d9c65SJoerg Wunsch {
338511d9c65SJoerg Wunsch     long total;
339511d9c65SJoerg Wunsch     load_avg avenrun[3];
340511d9c65SJoerg Wunsch 
341511d9c65SJoerg Wunsch     /* get the cp_time array */
342511d9c65SJoerg Wunsch     (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
343511d9c65SJoerg Wunsch 		   nlst[X_CP_TIME].n_name);
344511d9c65SJoerg Wunsch     (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
345511d9c65SJoerg Wunsch 		   nlst[X_AVENRUN].n_name);
346511d9c65SJoerg Wunsch 
347511d9c65SJoerg Wunsch     (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
348511d9c65SJoerg Wunsch 		   "!");
349511d9c65SJoerg Wunsch 
350511d9c65SJoerg Wunsch     /* convert load averages to doubles */
351511d9c65SJoerg Wunsch     {
352511d9c65SJoerg Wunsch 	register int i;
353511d9c65SJoerg Wunsch 	register double *infoloadp;
354511d9c65SJoerg Wunsch 	load_avg *avenrunp;
355511d9c65SJoerg Wunsch 
356511d9c65SJoerg Wunsch #ifdef notyet
357511d9c65SJoerg Wunsch 	struct loadavg sysload;
358511d9c65SJoerg Wunsch 	int size;
359511d9c65SJoerg Wunsch 	getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
360511d9c65SJoerg Wunsch #endif
361511d9c65SJoerg Wunsch 
362511d9c65SJoerg Wunsch 	infoloadp = si->load_avg;
363511d9c65SJoerg Wunsch 	avenrunp = avenrun;
364511d9c65SJoerg Wunsch 	for (i = 0; i < 3; i++)
365511d9c65SJoerg Wunsch 	{
366511d9c65SJoerg Wunsch #ifdef notyet
367511d9c65SJoerg Wunsch 	    *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
368511d9c65SJoerg Wunsch #endif
369511d9c65SJoerg Wunsch 	    *infoloadp++ = loaddouble(*avenrunp++);
370511d9c65SJoerg Wunsch 	}
371511d9c65SJoerg Wunsch     }
372511d9c65SJoerg Wunsch 
373511d9c65SJoerg Wunsch     /* convert cp_time counts to percentages */
374511d9c65SJoerg Wunsch     total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
375511d9c65SJoerg Wunsch 
376511d9c65SJoerg Wunsch     /* sum memory & swap statistics */
377511d9c65SJoerg Wunsch     {
378511d9c65SJoerg Wunsch 	struct vmmeter sum;
379511d9c65SJoerg Wunsch 	static unsigned int swap_delay = 0;
380511d9c65SJoerg Wunsch 	static int swapavail = 0;
381511d9c65SJoerg Wunsch 	static int swapfree = 0;
382511d9c65SJoerg Wunsch 	static int bufspace = 0;
383511d9c65SJoerg Wunsch 
384511d9c65SJoerg Wunsch         (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
385511d9c65SJoerg Wunsch 		   "_cnt");
386511d9c65SJoerg Wunsch         (void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace),
387511d9c65SJoerg Wunsch 		   "_bufspace");
388511d9c65SJoerg Wunsch 
389511d9c65SJoerg Wunsch 	/* convert memory stats to Kbytes */
390511d9c65SJoerg Wunsch 	memory_stats[0] = pagetok(sum.v_active_count);
391511d9c65SJoerg Wunsch 	memory_stats[1] = pagetok(sum.v_inactive_count);
392511d9c65SJoerg Wunsch 	memory_stats[2] = pagetok(sum.v_wire_count);
393511d9c65SJoerg Wunsch 	memory_stats[3] = pagetok(sum.v_cache_count);
394511d9c65SJoerg Wunsch 	memory_stats[4] = bufspace / 1024;
395511d9c65SJoerg Wunsch 	memory_stats[5] = pagetok(sum.v_free_count);
396511d9c65SJoerg Wunsch 	memory_stats[6] = -1;
397511d9c65SJoerg Wunsch 
398511d9c65SJoerg Wunsch 	/* first interval */
399511d9c65SJoerg Wunsch         if (swappgsin < 0) {
400511d9c65SJoerg Wunsch 	    swap_stats[4] = 0;
401511d9c65SJoerg Wunsch 	    swap_stats[5] = 0;
402511d9c65SJoerg Wunsch 	}
403511d9c65SJoerg Wunsch 
404511d9c65SJoerg Wunsch 	/* compute differences between old and new swap statistic */
405511d9c65SJoerg Wunsch 	else {
406511d9c65SJoerg Wunsch 	    swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin)));
407511d9c65SJoerg Wunsch 	    swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout)));
408511d9c65SJoerg Wunsch 	}
409511d9c65SJoerg Wunsch 
410511d9c65SJoerg Wunsch         swappgsin = sum.v_swappgsin;
411511d9c65SJoerg Wunsch 	swappgsout = sum.v_swappgsout;
412511d9c65SJoerg Wunsch 
413511d9c65SJoerg Wunsch 	/* call CPU heavy swapmode() only for changes */
414511d9c65SJoerg Wunsch         if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
415511d9c65SJoerg Wunsch 	    swap_stats[3] = swapmode(&swapavail, &swapfree);
416511d9c65SJoerg Wunsch 	    swap_stats[0] = swapavail;
417511d9c65SJoerg Wunsch 	    swap_stats[1] = swapavail - swapfree;
418511d9c65SJoerg Wunsch 	    swap_stats[2] = swapfree;
419511d9c65SJoerg Wunsch 	}
420511d9c65SJoerg Wunsch         swap_delay = 1;
421511d9c65SJoerg Wunsch 	swap_stats[6] = -1;
422511d9c65SJoerg Wunsch     }
423511d9c65SJoerg Wunsch 
424511d9c65SJoerg Wunsch     /* set arrays and strings */
425511d9c65SJoerg Wunsch     si->cpustates = cpu_states;
426511d9c65SJoerg Wunsch     si->memory = memory_stats;
427511d9c65SJoerg Wunsch     si->swap = swap_stats;
428511d9c65SJoerg Wunsch 
429511d9c65SJoerg Wunsch 
430511d9c65SJoerg Wunsch     if(lastpid > 0) {
431511d9c65SJoerg Wunsch 	si->last_pid = lastpid;
432511d9c65SJoerg Wunsch     } else {
433511d9c65SJoerg Wunsch 	si->last_pid = -1;
434511d9c65SJoerg Wunsch     }
435511d9c65SJoerg Wunsch }
436511d9c65SJoerg Wunsch 
437511d9c65SJoerg Wunsch static struct handle handle;
438511d9c65SJoerg Wunsch 
439511d9c65SJoerg Wunsch caddr_t get_process_info(si, sel, compare)
440511d9c65SJoerg Wunsch 
441511d9c65SJoerg Wunsch struct system_info *si;
442511d9c65SJoerg Wunsch struct process_select *sel;
443511d9c65SJoerg Wunsch int (*compare)();
444511d9c65SJoerg Wunsch 
445511d9c65SJoerg Wunsch {
446511d9c65SJoerg Wunsch     register int i;
447511d9c65SJoerg Wunsch     register int total_procs;
448511d9c65SJoerg Wunsch     register int active_procs;
449511d9c65SJoerg Wunsch     register struct kinfo_proc **prefp;
450511d9c65SJoerg Wunsch     register struct kinfo_proc *pp;
451511d9c65SJoerg Wunsch 
452511d9c65SJoerg Wunsch     /* these are copied out of sel for speed */
453511d9c65SJoerg Wunsch     int show_idle;
454511d9c65SJoerg Wunsch     int show_system;
455511d9c65SJoerg Wunsch     int show_uid;
456511d9c65SJoerg Wunsch     int show_command;
457511d9c65SJoerg Wunsch 
458511d9c65SJoerg Wunsch 
459511d9c65SJoerg Wunsch     pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
460511d9c65SJoerg Wunsch     if (nproc > onproc)
461511d9c65SJoerg Wunsch 	pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
462511d9c65SJoerg Wunsch 		* (onproc = nproc));
463511d9c65SJoerg Wunsch     if (pref == NULL || pbase == NULL) {
464511d9c65SJoerg Wunsch 	(void) fprintf(stderr, "top: Out of memory.\n");
465511d9c65SJoerg Wunsch 	quit(23);
466511d9c65SJoerg Wunsch     }
467511d9c65SJoerg Wunsch     /* get a pointer to the states summary array */
468511d9c65SJoerg Wunsch     si->procstates = process_states;
469511d9c65SJoerg Wunsch 
470511d9c65SJoerg Wunsch     /* set up flags which define what we are going to select */
471511d9c65SJoerg Wunsch     show_idle = sel->idle;
472511d9c65SJoerg Wunsch     show_system = sel->system;
473511d9c65SJoerg Wunsch     show_uid = sel->uid != -1;
474511d9c65SJoerg Wunsch     show_command = sel->command != NULL;
475511d9c65SJoerg Wunsch 
476511d9c65SJoerg Wunsch     /* count up process states and get pointers to interesting procs */
477511d9c65SJoerg Wunsch     total_procs = 0;
478511d9c65SJoerg Wunsch     active_procs = 0;
479511d9c65SJoerg Wunsch     memset((char *)process_states, 0, sizeof(process_states));
480511d9c65SJoerg Wunsch     prefp = pref;
481511d9c65SJoerg Wunsch     for (pp = pbase, i = 0; i < nproc; pp++, i++)
482511d9c65SJoerg Wunsch     {
483511d9c65SJoerg Wunsch 	/*
484511d9c65SJoerg Wunsch 	 *  Place pointers to each valid proc structure in pref[].
485511d9c65SJoerg Wunsch 	 *  Process slots that are actually in use have a non-zero
486511d9c65SJoerg Wunsch 	 *  status field.  Processes with P_SYSTEM set are system
487511d9c65SJoerg Wunsch 	 *  processes---these get ignored unless show_sysprocs is set.
488511d9c65SJoerg Wunsch 	 */
489511d9c65SJoerg Wunsch 	if (PP(pp, p_stat) != 0 &&
490511d9c65SJoerg Wunsch 	    (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
491511d9c65SJoerg Wunsch 	{
492511d9c65SJoerg Wunsch 	    total_procs++;
493511d9c65SJoerg Wunsch 	    process_states[(unsigned char) PP(pp, p_stat)]++;
494511d9c65SJoerg Wunsch 	    if ((PP(pp, p_stat) != SZOMB) &&
495511d9c65SJoerg Wunsch 		(show_idle || (PP(pp, p_pctcpu) != 0) ||
496511d9c65SJoerg Wunsch 		 (PP(pp, p_stat) == SRUN)) &&
497511d9c65SJoerg Wunsch 		(!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
498511d9c65SJoerg Wunsch 	    {
499511d9c65SJoerg Wunsch 		*prefp++ = pp;
500511d9c65SJoerg Wunsch 		active_procs++;
501511d9c65SJoerg Wunsch 	    }
502511d9c65SJoerg Wunsch 	}
503511d9c65SJoerg Wunsch     }
504511d9c65SJoerg Wunsch 
505511d9c65SJoerg Wunsch     /* if requested, sort the "interesting" processes */
506511d9c65SJoerg Wunsch     if (compare != NULL)
507511d9c65SJoerg Wunsch     {
508511d9c65SJoerg Wunsch 	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
509511d9c65SJoerg Wunsch     }
510511d9c65SJoerg Wunsch 
511511d9c65SJoerg Wunsch     /* remember active and total counts */
512511d9c65SJoerg Wunsch     si->p_total = total_procs;
513511d9c65SJoerg Wunsch     si->p_active = pref_len = active_procs;
514511d9c65SJoerg Wunsch 
515511d9c65SJoerg Wunsch     /* pass back a handle */
516511d9c65SJoerg Wunsch     handle.next_proc = pref;
517511d9c65SJoerg Wunsch     handle.remaining = active_procs;
518511d9c65SJoerg Wunsch     return((caddr_t)&handle);
519511d9c65SJoerg Wunsch }
520511d9c65SJoerg Wunsch 
521511d9c65SJoerg Wunsch char fmt[128];		/* static area where result is built */
522511d9c65SJoerg Wunsch 
523511d9c65SJoerg Wunsch char *format_next_process(handle, get_userid)
524511d9c65SJoerg Wunsch 
525511d9c65SJoerg Wunsch caddr_t handle;
526511d9c65SJoerg Wunsch char *(*get_userid)();
527511d9c65SJoerg Wunsch 
528511d9c65SJoerg Wunsch {
529511d9c65SJoerg Wunsch     register struct kinfo_proc *pp;
530511d9c65SJoerg Wunsch     register long cputime;
531511d9c65SJoerg Wunsch     register double pct;
532511d9c65SJoerg Wunsch     struct handle *hp;
533511d9c65SJoerg Wunsch     char status[16];
534511d9c65SJoerg Wunsch 
535511d9c65SJoerg Wunsch     /* find and remember the next proc structure */
536511d9c65SJoerg Wunsch     hp = (struct handle *)handle;
537511d9c65SJoerg Wunsch     pp = *(hp->next_proc++);
538511d9c65SJoerg Wunsch     hp->remaining--;
539511d9c65SJoerg Wunsch 
540511d9c65SJoerg Wunsch 
541511d9c65SJoerg Wunsch     /* get the process's user struct and set cputime */
542511d9c65SJoerg Wunsch     if ((PP(pp, p_flag) & P_INMEM) == 0) {
543511d9c65SJoerg Wunsch 	/*
544511d9c65SJoerg Wunsch 	 * Print swapped processes as <pname>
545511d9c65SJoerg Wunsch 	 */
546511d9c65SJoerg Wunsch 	char *comm = PP(pp, p_comm);
547511d9c65SJoerg Wunsch #define COMSIZ sizeof(PP(pp, p_comm))
548511d9c65SJoerg Wunsch 	char buf[COMSIZ];
549511d9c65SJoerg Wunsch 	(void) strncpy(buf, comm, COMSIZ);
550511d9c65SJoerg Wunsch 	comm[0] = '<';
551511d9c65SJoerg Wunsch 	(void) strncpy(&comm[1], buf, COMSIZ - 2);
552511d9c65SJoerg Wunsch 	comm[COMSIZ - 2] = '\0';
553511d9c65SJoerg Wunsch 	(void) strncat(comm, ">", COMSIZ - 1);
554511d9c65SJoerg Wunsch 	comm[COMSIZ - 1] = '\0';
555511d9c65SJoerg Wunsch     }
556511d9c65SJoerg Wunsch 
557511d9c65SJoerg Wunsch #if 0
558511d9c65SJoerg Wunsch     /* This does not produce the correct results */
559511d9c65SJoerg Wunsch     cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
560511d9c65SJoerg Wunsch #endif
561511d9c65SJoerg Wunsch     cputime = PP(pp, p_rtime).tv_sec;	/* This does not count interrupts */
562511d9c65SJoerg Wunsch 
563511d9c65SJoerg Wunsch     /* calculate the base for cpu percentages */
564511d9c65SJoerg Wunsch     pct = pctdouble(PP(pp, p_pctcpu));
565511d9c65SJoerg Wunsch 
566511d9c65SJoerg Wunsch     /* generate "STATE" field */
567511d9c65SJoerg Wunsch     switch (PP(pp, p_stat)) {
568511d9c65SJoerg Wunsch 	case SRUN:
56994154ff8SPeter Wemm 	    if (smpmode && PP(pp, p_oncpu) >= 0)
570511d9c65SJoerg Wunsch 		sprintf(status, "CPU%d", PP(pp, p_oncpu));
571511d9c65SJoerg Wunsch 	    else
572511d9c65SJoerg Wunsch 		strcpy(status, "RUN");
573511d9c65SJoerg Wunsch 	    break;
574511d9c65SJoerg Wunsch 	case SSLEEP:
575511d9c65SJoerg Wunsch 	    if (PP(pp, p_wmesg) != NULL) {
576511d9c65SJoerg Wunsch 		sprintf(status, "%.6s", EP(pp, e_wmesg));
577511d9c65SJoerg Wunsch 		break;
578511d9c65SJoerg Wunsch 	    }
579511d9c65SJoerg Wunsch 	    /* fall through */
580511d9c65SJoerg Wunsch 	default:
581511d9c65SJoerg Wunsch 	    sprintf(status, "%.6s", state_abbrev[(unsigned char) PP(pp, p_stat)]);
582511d9c65SJoerg Wunsch 	    break;
583511d9c65SJoerg Wunsch     }
584511d9c65SJoerg Wunsch 
585511d9c65SJoerg Wunsch     /* format this entry */
586511d9c65SJoerg Wunsch     sprintf(fmt,
58794154ff8SPeter Wemm 	    smpmode ? smp_Proc_format : up_Proc_format,
588511d9c65SJoerg Wunsch 	    PP(pp, p_pid),
589511d9c65SJoerg Wunsch 	    (*get_userid)(EP(pp, e_pcred.p_ruid)),
590511d9c65SJoerg Wunsch 	    PP(pp, p_priority) - PZERO,
591511d9c65SJoerg Wunsch 	    PP(pp, p_nice) - NZERO,
592511d9c65SJoerg Wunsch 	    format_k2(pagetok(PROCSIZE(pp))),
593511d9c65SJoerg Wunsch 	    format_k2(pagetok(VP(pp, vm_rssize))),
594511d9c65SJoerg Wunsch 	    status,
59594154ff8SPeter Wemm 	    smpmode ? PP(pp, p_lastcpu) : 0,
596511d9c65SJoerg Wunsch 	    format_time(cputime),
597511d9c65SJoerg Wunsch 	    10000.0 * weighted_cpu(pct, pp) / hz,
598511d9c65SJoerg Wunsch 	    10000.0 * pct / hz,
599511d9c65SJoerg Wunsch 	    printable(PP(pp, p_comm)));
600511d9c65SJoerg Wunsch 
601511d9c65SJoerg Wunsch     /* return the result */
602511d9c65SJoerg Wunsch     return(fmt);
603511d9c65SJoerg Wunsch }
604511d9c65SJoerg Wunsch 
605511d9c65SJoerg Wunsch 
606511d9c65SJoerg Wunsch /*
607511d9c65SJoerg Wunsch  * check_nlist(nlst) - checks the nlist to see if any symbols were not
608511d9c65SJoerg Wunsch  *		found.  For every symbol that was not found, a one-line
609511d9c65SJoerg Wunsch  *		message is printed to stderr.  The routine returns the
610511d9c65SJoerg Wunsch  *		number of symbols NOT found.
611511d9c65SJoerg Wunsch  */
612511d9c65SJoerg Wunsch 
613511d9c65SJoerg Wunsch static int check_nlist(nlst)
614511d9c65SJoerg Wunsch 
615511d9c65SJoerg Wunsch register struct nlist *nlst;
616511d9c65SJoerg Wunsch 
617511d9c65SJoerg Wunsch {
618511d9c65SJoerg Wunsch     register int i;
619511d9c65SJoerg Wunsch 
620511d9c65SJoerg Wunsch     /* check to see if we got ALL the symbols we requested */
621511d9c65SJoerg Wunsch     /* this will write one line to stderr for every symbol not found */
622511d9c65SJoerg Wunsch 
623511d9c65SJoerg Wunsch     i = 0;
624511d9c65SJoerg Wunsch     while (nlst->n_name != NULL)
625511d9c65SJoerg Wunsch     {
626511d9c65SJoerg Wunsch 	if (nlst->n_type == 0)
627511d9c65SJoerg Wunsch 	{
628511d9c65SJoerg Wunsch 	    /* this one wasn't found */
629511d9c65SJoerg Wunsch 	    (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
630511d9c65SJoerg Wunsch 			   nlst->n_name);
631511d9c65SJoerg Wunsch 	    i = 1;
632511d9c65SJoerg Wunsch 	}
633511d9c65SJoerg Wunsch 	nlst++;
634511d9c65SJoerg Wunsch     }
635511d9c65SJoerg Wunsch 
636511d9c65SJoerg Wunsch     return(i);
637511d9c65SJoerg Wunsch }
638511d9c65SJoerg Wunsch 
639511d9c65SJoerg Wunsch 
640511d9c65SJoerg Wunsch /*
641511d9c65SJoerg Wunsch  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
642511d9c65SJoerg Wunsch  *	"offset" is the byte offset into the kernel for the desired value,
643511d9c65SJoerg Wunsch  *  	"ptr" points to a buffer into which the value is retrieved,
644511d9c65SJoerg Wunsch  *  	"size" is the size of the buffer (and the object to retrieve),
645511d9c65SJoerg Wunsch  *  	"refstr" is a reference string used when printing error meessages,
646511d9c65SJoerg Wunsch  *	    if "refstr" starts with a '!', then a failure on read will not
647511d9c65SJoerg Wunsch  *  	    be fatal (this may seem like a silly way to do things, but I
648511d9c65SJoerg Wunsch  *  	    really didn't want the overhead of another argument).
649511d9c65SJoerg Wunsch  *
650511d9c65SJoerg Wunsch  */
651511d9c65SJoerg Wunsch 
652511d9c65SJoerg Wunsch static int getkval(offset, ptr, size, refstr)
653511d9c65SJoerg Wunsch 
654511d9c65SJoerg Wunsch unsigned long offset;
655511d9c65SJoerg Wunsch int *ptr;
656511d9c65SJoerg Wunsch int size;
657511d9c65SJoerg Wunsch char *refstr;
658511d9c65SJoerg Wunsch 
659511d9c65SJoerg Wunsch {
660511d9c65SJoerg Wunsch     if (kvm_read(kd, offset, (char *) ptr, size) != size)
661511d9c65SJoerg Wunsch     {
662511d9c65SJoerg Wunsch 	if (*refstr == '!')
663511d9c65SJoerg Wunsch 	{
664511d9c65SJoerg Wunsch 	    return(0);
665511d9c65SJoerg Wunsch 	}
666511d9c65SJoerg Wunsch 	else
667511d9c65SJoerg Wunsch 	{
668511d9c65SJoerg Wunsch 	    fprintf(stderr, "top: kvm_read for %s: %s\n",
669511d9c65SJoerg Wunsch 		refstr, strerror(errno));
670511d9c65SJoerg Wunsch 	    quit(23);
671511d9c65SJoerg Wunsch 	}
672511d9c65SJoerg Wunsch     }
673511d9c65SJoerg Wunsch     return(1);
674511d9c65SJoerg Wunsch }
675511d9c65SJoerg Wunsch 
676511d9c65SJoerg Wunsch /* comparison routine for qsort */
677511d9c65SJoerg Wunsch 
678511d9c65SJoerg Wunsch /*
679511d9c65SJoerg Wunsch  *  proc_compare - comparison function for "qsort"
680511d9c65SJoerg Wunsch  *	Compares the resource consumption of two processes using five
681511d9c65SJoerg Wunsch  *  	distinct keys.  The keys (in descending order of importance) are:
682511d9c65SJoerg Wunsch  *  	percent cpu, cpu ticks, state, resident set size, total virtual
683511d9c65SJoerg Wunsch  *  	memory usage.  The process states are ordered as follows (from least
684511d9c65SJoerg Wunsch  *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
685511d9c65SJoerg Wunsch  *  	array declaration below maps a process state index into a number
686511d9c65SJoerg Wunsch  *  	that reflects this ordering.
687511d9c65SJoerg Wunsch  */
688511d9c65SJoerg Wunsch 
689511d9c65SJoerg Wunsch static unsigned char sorted_state[] =
690511d9c65SJoerg Wunsch {
691511d9c65SJoerg Wunsch     0,	/* not used		*/
692511d9c65SJoerg Wunsch     3,	/* sleep		*/
693511d9c65SJoerg Wunsch     1,	/* ABANDONED (WAIT)	*/
694511d9c65SJoerg Wunsch     6,	/* run			*/
695511d9c65SJoerg Wunsch     5,	/* start		*/
696511d9c65SJoerg Wunsch     2,	/* zombie		*/
697511d9c65SJoerg Wunsch     4	/* stop			*/
698511d9c65SJoerg Wunsch };
699511d9c65SJoerg Wunsch 
700511d9c65SJoerg Wunsch int
701511d9c65SJoerg Wunsch proc_compare(pp1, pp2)
702511d9c65SJoerg Wunsch 
703511d9c65SJoerg Wunsch struct proc **pp1;
704511d9c65SJoerg Wunsch struct proc **pp2;
705511d9c65SJoerg Wunsch 
706511d9c65SJoerg Wunsch {
707511d9c65SJoerg Wunsch     register struct kinfo_proc *p1;
708511d9c65SJoerg Wunsch     register struct kinfo_proc *p2;
709511d9c65SJoerg Wunsch     register int result;
710511d9c65SJoerg Wunsch     register pctcpu lresult;
711511d9c65SJoerg Wunsch 
712511d9c65SJoerg Wunsch     /* remove one level of indirection */
713511d9c65SJoerg Wunsch     p1 = *(struct kinfo_proc **) pp1;
714511d9c65SJoerg Wunsch     p2 = *(struct kinfo_proc **) pp2;
715511d9c65SJoerg Wunsch 
716511d9c65SJoerg Wunsch     /* compare percent cpu (pctcpu) */
717511d9c65SJoerg Wunsch     if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
718511d9c65SJoerg Wunsch     {
719511d9c65SJoerg Wunsch 	/* use cpticks to break the tie */
720511d9c65SJoerg Wunsch 	if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
721511d9c65SJoerg Wunsch 	{
722511d9c65SJoerg Wunsch 	    /* use process state to break the tie */
723511d9c65SJoerg Wunsch 	    if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
724511d9c65SJoerg Wunsch 			  sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
725511d9c65SJoerg Wunsch 	    {
726511d9c65SJoerg Wunsch 		/* use priority to break the tie */
727511d9c65SJoerg Wunsch 		if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
728511d9c65SJoerg Wunsch 		{
729511d9c65SJoerg Wunsch 		    /* use resident set size (rssize) to break the tie */
730511d9c65SJoerg Wunsch 		    if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
731511d9c65SJoerg Wunsch 		    {
732511d9c65SJoerg Wunsch 			/* use total memory to break the tie */
733511d9c65SJoerg Wunsch 			result = PROCSIZE(p2) - PROCSIZE(p1);
734511d9c65SJoerg Wunsch 		    }
735511d9c65SJoerg Wunsch 		}
736511d9c65SJoerg Wunsch 	    }
737511d9c65SJoerg Wunsch 	}
738511d9c65SJoerg Wunsch     }
739511d9c65SJoerg Wunsch     else
740511d9c65SJoerg Wunsch     {
741511d9c65SJoerg Wunsch 	result = lresult < 0 ? -1 : 1;
742511d9c65SJoerg Wunsch     }
743511d9c65SJoerg Wunsch 
744511d9c65SJoerg Wunsch     return(result);
745511d9c65SJoerg Wunsch }
746511d9c65SJoerg Wunsch 
747511d9c65SJoerg Wunsch 
748511d9c65SJoerg Wunsch /*
749511d9c65SJoerg Wunsch  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
750511d9c65SJoerg Wunsch  *		the process does not exist.
751511d9c65SJoerg Wunsch  *		It is EXTREMLY IMPORTANT that this function work correctly.
752511d9c65SJoerg Wunsch  *		If top runs setuid root (as in SVR4), then this function
753511d9c65SJoerg Wunsch  *		is the only thing that stands in the way of a serious
754511d9c65SJoerg Wunsch  *		security problem.  It validates requests for the "kill"
755511d9c65SJoerg Wunsch  *		and "renice" commands.
756511d9c65SJoerg Wunsch  */
757511d9c65SJoerg Wunsch 
758511d9c65SJoerg Wunsch int proc_owner(pid)
759511d9c65SJoerg Wunsch 
760511d9c65SJoerg Wunsch int pid;
761511d9c65SJoerg Wunsch 
762511d9c65SJoerg Wunsch {
763511d9c65SJoerg Wunsch     register int cnt;
764511d9c65SJoerg Wunsch     register struct kinfo_proc **prefp;
765511d9c65SJoerg Wunsch     register struct kinfo_proc *pp;
766511d9c65SJoerg Wunsch 
767511d9c65SJoerg Wunsch     prefp = pref;
768511d9c65SJoerg Wunsch     cnt = pref_len;
769511d9c65SJoerg Wunsch     while (--cnt >= 0)
770511d9c65SJoerg Wunsch     {
771511d9c65SJoerg Wunsch 	pp = *prefp++;
772511d9c65SJoerg Wunsch 	if (PP(pp, p_pid) == (pid_t)pid)
773511d9c65SJoerg Wunsch 	{
774511d9c65SJoerg Wunsch 	    return((int)EP(pp, e_pcred.p_ruid));
775511d9c65SJoerg Wunsch 	}
776511d9c65SJoerg Wunsch     }
777511d9c65SJoerg Wunsch     return(-1);
778511d9c65SJoerg Wunsch }
779511d9c65SJoerg Wunsch 
780511d9c65SJoerg Wunsch 
781511d9c65SJoerg Wunsch /*
782511d9c65SJoerg Wunsch  * swapmode is based on a program called swapinfo written
783511d9c65SJoerg Wunsch  * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
784511d9c65SJoerg Wunsch  */
785511d9c65SJoerg Wunsch 
786511d9c65SJoerg Wunsch #define	SVAR(var) __STRING(var)	/* to force expansion */
787511d9c65SJoerg Wunsch #define	KGET(idx, var)							\
788511d9c65SJoerg Wunsch 	KGET1(idx, &var, sizeof(var), SVAR(var))
789511d9c65SJoerg Wunsch #define	KGET1(idx, p, s, msg)						\
790511d9c65SJoerg Wunsch 	KGET2(nlst[idx].n_value, p, s, msg)
791511d9c65SJoerg Wunsch #define	KGET2(addr, p, s, msg)						\
792511d9c65SJoerg Wunsch 	if (kvm_read(kd, (u_long)(addr), p, s) != s) {		        \
793511d9c65SJoerg Wunsch 		warnx("cannot read %s: %s", msg, kvm_geterr(kd));       \
794511d9c65SJoerg Wunsch 		return (0);                                             \
795511d9c65SJoerg Wunsch        }
796511d9c65SJoerg Wunsch #define	KGETRET(addr, p, s, msg)					\
797511d9c65SJoerg Wunsch 	if (kvm_read(kd, (u_long)(addr), p, s) != s) {			\
798511d9c65SJoerg Wunsch 		warnx("cannot read %s: %s", msg, kvm_geterr(kd));	\
799511d9c65SJoerg Wunsch 		return (0);						\
800511d9c65SJoerg Wunsch 	}
801511d9c65SJoerg Wunsch 
802511d9c65SJoerg Wunsch 
803511d9c65SJoerg Wunsch int
804511d9c65SJoerg Wunsch swapmode(retavail, retfree)
805511d9c65SJoerg Wunsch 	int *retavail;
806511d9c65SJoerg Wunsch 	int *retfree;
807511d9c65SJoerg Wunsch {
808511d9c65SJoerg Wunsch 	char *header;
809511d9c65SJoerg Wunsch 	int hlen, nswap, nswdev, dmmax;
810511d9c65SJoerg Wunsch 	int i, div, avail, nfree, npfree, used;
811511d9c65SJoerg Wunsch 	struct swdevt *sw;
812511d9c65SJoerg Wunsch 	long blocksize, *perdev;
813511d9c65SJoerg Wunsch 	u_long ptr;
814511d9c65SJoerg Wunsch 	struct rlist head;
815511d9c65SJoerg Wunsch #if __FreeBSD_version >= 220000
816511d9c65SJoerg Wunsch 	struct rlisthdr swaplist;
817511d9c65SJoerg Wunsch #else
818511d9c65SJoerg Wunsch 	struct rlist *swaplist;
819511d9c65SJoerg Wunsch #endif
820511d9c65SJoerg Wunsch 	struct rlist *swapptr;
821511d9c65SJoerg Wunsch 
822511d9c65SJoerg Wunsch 	/*
823511d9c65SJoerg Wunsch 	 * Counter for error messages. If we reach the limit,
824511d9c65SJoerg Wunsch 	 * stop reading information from swap devices and
825511d9c65SJoerg Wunsch 	 * return zero. This prevent endless 'bad address'
826511d9c65SJoerg Wunsch 	 * messages.
827511d9c65SJoerg Wunsch 	 */
828511d9c65SJoerg Wunsch 	static warning = 10;
829511d9c65SJoerg Wunsch 
830511d9c65SJoerg Wunsch 	if (warning <= 0) {
831511d9c65SJoerg Wunsch 	    /* a single warning */
832511d9c65SJoerg Wunsch 	    if (!warning) {
833511d9c65SJoerg Wunsch 		warning--;
834511d9c65SJoerg Wunsch 		fprintf(stderr,
835511d9c65SJoerg Wunsch 			"Too much errors, stop reading swap devices ...\n");
836511d9c65SJoerg Wunsch 		(void)sleep(3);
837511d9c65SJoerg Wunsch 	    }
838511d9c65SJoerg Wunsch 	    return(0);
839511d9c65SJoerg Wunsch 	}
840511d9c65SJoerg Wunsch 	warning--; /* decrease counter, see end of function */
841511d9c65SJoerg Wunsch 
842511d9c65SJoerg Wunsch 	KGET(VM_NSWAP, nswap);
843511d9c65SJoerg Wunsch 	if (!nswap) {
844511d9c65SJoerg Wunsch 		fprintf(stderr, "No swap space available\n");
845511d9c65SJoerg Wunsch 		return(0);
846511d9c65SJoerg Wunsch 	}
847511d9c65SJoerg Wunsch 
848511d9c65SJoerg Wunsch 	KGET(VM_NSWDEV, nswdev);
849511d9c65SJoerg Wunsch 	KGET(VM_DMMAX, dmmax);
850511d9c65SJoerg Wunsch 	KGET1(VM_SWAPLIST, &swaplist, sizeof(swaplist), "swaplist");
851511d9c65SJoerg Wunsch 	if ((sw = (struct swdevt *)malloc(nswdev * sizeof(*sw))) == NULL ||
852511d9c65SJoerg Wunsch 	    (perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
853511d9c65SJoerg Wunsch 		err(1, "malloc");
854511d9c65SJoerg Wunsch 	KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
855511d9c65SJoerg Wunsch 	KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
856511d9c65SJoerg Wunsch 
857511d9c65SJoerg Wunsch 	/* Count up swap space. */
858511d9c65SJoerg Wunsch 	nfree = 0;
859511d9c65SJoerg Wunsch 	memset(perdev, 0, nswdev * sizeof(*perdev));
860511d9c65SJoerg Wunsch #if  __FreeBSD_version >= 220000
861511d9c65SJoerg Wunsch 	swapptr = swaplist.rlh_list;
862511d9c65SJoerg Wunsch 	while (swapptr) {
863511d9c65SJoerg Wunsch #else
864511d9c65SJoerg Wunsch 	while (swaplist) {
865511d9c65SJoerg Wunsch #endif
866511d9c65SJoerg Wunsch 		int	top, bottom, next_block;
867511d9c65SJoerg Wunsch #if  __FreeBSD_version >= 220000
868511d9c65SJoerg Wunsch 		KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
869511d9c65SJoerg Wunsch #else
870511d9c65SJoerg Wunsch 		KGET2(swaplist, &head, sizeof(struct rlist), "swaplist");
871511d9c65SJoerg Wunsch #endif
872511d9c65SJoerg Wunsch 
873511d9c65SJoerg Wunsch 		top = head.rl_end;
874511d9c65SJoerg Wunsch 		bottom = head.rl_start;
875511d9c65SJoerg Wunsch 
876511d9c65SJoerg Wunsch 		nfree += top - bottom + 1;
877511d9c65SJoerg Wunsch 
878511d9c65SJoerg Wunsch 		/*
879511d9c65SJoerg Wunsch 		 * Swap space is split up among the configured disks.
880511d9c65SJoerg Wunsch 		 *
881511d9c65SJoerg Wunsch 		 * For interleaved swap devices, the first dmmax blocks
882511d9c65SJoerg Wunsch 		 * of swap space some from the first disk, the next dmmax
883511d9c65SJoerg Wunsch 		 * blocks from the next, and so on up to nswap blocks.
884511d9c65SJoerg Wunsch 		 *
885511d9c65SJoerg Wunsch 		 * The list of free space joins adjacent free blocks,
886511d9c65SJoerg Wunsch 		 * ignoring device boundries.  If we want to keep track
887511d9c65SJoerg Wunsch 		 * of this information per device, we'll just have to
888511d9c65SJoerg Wunsch 		 * extract it ourselves.
889511d9c65SJoerg Wunsch 		 */
890511d9c65SJoerg Wunsch 		while (top / dmmax != bottom / dmmax) {
891511d9c65SJoerg Wunsch 			next_block = ((bottom + dmmax) / dmmax);
892511d9c65SJoerg Wunsch 			perdev[(bottom / dmmax) % nswdev] +=
893511d9c65SJoerg Wunsch 				next_block * dmmax - bottom;
894511d9c65SJoerg Wunsch 			bottom = next_block * dmmax;
895511d9c65SJoerg Wunsch 		}
896511d9c65SJoerg Wunsch 		perdev[(bottom / dmmax) % nswdev] +=
897511d9c65SJoerg Wunsch 			top - bottom + 1;
898511d9c65SJoerg Wunsch 
899511d9c65SJoerg Wunsch #if  __FreeBSD_version >= 220000
900511d9c65SJoerg Wunsch 		swapptr = head.rl_next;
901511d9c65SJoerg Wunsch #else
902511d9c65SJoerg Wunsch 		swaplist = head.rl_next;
903511d9c65SJoerg Wunsch #endif
904511d9c65SJoerg Wunsch 	}
905511d9c65SJoerg Wunsch 
906511d9c65SJoerg Wunsch 	header = getbsize(&hlen, &blocksize);
907511d9c65SJoerg Wunsch 	div = blocksize / 512;
908511d9c65SJoerg Wunsch 	avail = npfree = 0;
909511d9c65SJoerg Wunsch 	for (i = 0; i < nswdev; i++) {
910511d9c65SJoerg Wunsch 		int xsize, xfree;
911511d9c65SJoerg Wunsch 
912511d9c65SJoerg Wunsch 		/*
913511d9c65SJoerg Wunsch 		 * Don't report statistics for partitions which have not
914511d9c65SJoerg Wunsch 		 * yet been activated via swapon(8).
915511d9c65SJoerg Wunsch 		 */
916511d9c65SJoerg Wunsch 
917511d9c65SJoerg Wunsch 		xsize = sw[i].sw_nblks;
918511d9c65SJoerg Wunsch 		xfree = perdev[i];
919511d9c65SJoerg Wunsch 		used = xsize - xfree;
920511d9c65SJoerg Wunsch 		npfree++;
921511d9c65SJoerg Wunsch 		avail += xsize;
922511d9c65SJoerg Wunsch 	}
923511d9c65SJoerg Wunsch 
924511d9c65SJoerg Wunsch 	/*
925511d9c65SJoerg Wunsch 	 * If only one partition has been set up via swapon(8), we don't
926511d9c65SJoerg Wunsch 	 * need to bother with totals.
927511d9c65SJoerg Wunsch 	 */
928511d9c65SJoerg Wunsch 	*retavail = avail / 2;
929511d9c65SJoerg Wunsch 	*retfree = nfree / 2;
930511d9c65SJoerg Wunsch 	used = avail - nfree;
931511d9c65SJoerg Wunsch 	free(sw); free(perdev);
932511d9c65SJoerg Wunsch 
933511d9c65SJoerg Wunsch 	/* increase counter, no errors occurs */
934511d9c65SJoerg Wunsch 	warning++;
935511d9c65SJoerg Wunsch 
936511d9c65SJoerg Wunsch 	return  (int)(((double)used / (double)avail * 100.0) + 0.5);
937511d9c65SJoerg Wunsch }
938