xref: /freebsd/usr.bin/top/machine.c (revision e5aff02f684e47b69aceaa0ceee03f1f047252a7)
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  *
20e5aff02fSPeter Wemm  * $Id: machine.c,v 1.6 1997/08/27 03:48:25 peter 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>
33a2aff8b2SPeter Wemm #include <pwd.h>
34511d9c65SJoerg Wunsch #include <sys/errno.h>
35511d9c65SJoerg Wunsch #include <sys/sysctl.h>
36511d9c65SJoerg Wunsch #include <sys/dkstat.h>
37511d9c65SJoerg Wunsch #include <sys/file.h>
38511d9c65SJoerg Wunsch #include <sys/time.h>
39511d9c65SJoerg Wunsch #include <sys/proc.h>
40511d9c65SJoerg Wunsch #include <sys/user.h>
41511d9c65SJoerg Wunsch #include <sys/vmmeter.h>
42e5aff02fSPeter Wemm #include <sys/resource.h>
43e5aff02fSPeter Wemm #include <sys/rtprio.h>
44511d9c65SJoerg Wunsch 
45511d9c65SJoerg Wunsch /* Swap */
46511d9c65SJoerg Wunsch #include <stdlib.h>
47511d9c65SJoerg Wunsch #include <sys/rlist.h>
48511d9c65SJoerg Wunsch #include <sys/conf.h>
49511d9c65SJoerg Wunsch 
50511d9c65SJoerg Wunsch #include <osreldate.h> /* for changes in kernel structures */
51511d9c65SJoerg Wunsch 
52511d9c65SJoerg Wunsch #include "top.h"
53511d9c65SJoerg Wunsch #include "machine.h"
54511d9c65SJoerg Wunsch 
55511d9c65SJoerg Wunsch static int check_nlist __P((struct nlist *));
56511d9c65SJoerg Wunsch static int getkval __P((unsigned long, int *, int, char *));
57511d9c65SJoerg Wunsch extern char* printable __P((char *));
58511d9c65SJoerg Wunsch int swapmode __P((int *retavail, int *retfree));
5994154ff8SPeter Wemm static int smpmode;
60a2aff8b2SPeter Wemm static int namelength;
61a2aff8b2SPeter Wemm static int cmdlength;
62511d9c65SJoerg Wunsch 
63511d9c65SJoerg Wunsch 
64511d9c65SJoerg Wunsch /* get_process_info passes back a handle.  This is what it looks like: */
65511d9c65SJoerg Wunsch 
66511d9c65SJoerg Wunsch struct handle
67511d9c65SJoerg Wunsch {
68511d9c65SJoerg Wunsch     struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
69511d9c65SJoerg Wunsch     int remaining;		/* number of pointers remaining */
70511d9c65SJoerg Wunsch };
71511d9c65SJoerg Wunsch 
72511d9c65SJoerg Wunsch /* declarations for load_avg */
73511d9c65SJoerg Wunsch #include "loadavg.h"
74511d9c65SJoerg Wunsch 
75511d9c65SJoerg Wunsch #define PP(pp, field) ((pp)->kp_proc . field)
76511d9c65SJoerg Wunsch #define EP(pp, field) ((pp)->kp_eproc . field)
77511d9c65SJoerg Wunsch #define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
78511d9c65SJoerg Wunsch 
79511d9c65SJoerg Wunsch /* define what weighted cpu is.  */
80511d9c65SJoerg Wunsch #define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
81511d9c65SJoerg Wunsch 			 ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))
82511d9c65SJoerg Wunsch 
83511d9c65SJoerg Wunsch /* what we consider to be process size: */
84511d9c65SJoerg Wunsch #define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
85511d9c65SJoerg Wunsch 
86511d9c65SJoerg Wunsch /* definitions for indices in the nlist array */
87511d9c65SJoerg Wunsch 
88511d9c65SJoerg Wunsch 
89511d9c65SJoerg Wunsch static struct nlist nlst[] = {
90511d9c65SJoerg Wunsch #define X_CCPU		0
91511d9c65SJoerg Wunsch     { "_ccpu" },		/* 0 */
92511d9c65SJoerg Wunsch #define X_CP_TIME	1
93511d9c65SJoerg Wunsch     { "_cp_time" },		/* 1 */
94511d9c65SJoerg Wunsch #define X_HZ		2
95511d9c65SJoerg Wunsch     { "_hz" },		        /* 2 */
96511d9c65SJoerg Wunsch #define X_STATHZ	3
97511d9c65SJoerg Wunsch     { "_stathz" },		/* 3 */
98511d9c65SJoerg Wunsch #define X_AVENRUN	4
99511d9c65SJoerg Wunsch     { "_averunnable" },		/* 4 */
100511d9c65SJoerg Wunsch 
101511d9c65SJoerg Wunsch /* Swap */
102511d9c65SJoerg Wunsch #define VM_SWAPLIST	5
103511d9c65SJoerg Wunsch 	{ "_swaplist" },/* list of free swap areas */
104511d9c65SJoerg Wunsch #define VM_SWDEVT	6
105511d9c65SJoerg Wunsch 	{ "_swdevt" },	/* list of swap devices and sizes */
106511d9c65SJoerg Wunsch #define VM_NSWAP	7
107511d9c65SJoerg Wunsch 	{ "_nswap" },	/* size of largest swap device */
108511d9c65SJoerg Wunsch #define VM_NSWDEV	8
109511d9c65SJoerg Wunsch 	{ "_nswdev" },	/* number of swap devices */
110511d9c65SJoerg Wunsch #define VM_DMMAX	9
111511d9c65SJoerg Wunsch 	{ "_dmmax" },	/* maximum size of a swap block */
112511d9c65SJoerg Wunsch #define X_BUFSPACE	10
113511d9c65SJoerg Wunsch 	{ "_bufspace" },	/* K in buffer cache */
114511d9c65SJoerg Wunsch #define X_CNT           11
115511d9c65SJoerg Wunsch     { "_cnt" },		        /* struct vmmeter cnt */
116511d9c65SJoerg Wunsch 
117511d9c65SJoerg Wunsch /* Last pid */
118511d9c65SJoerg Wunsch #define X_LASTPID	12
119511d9c65SJoerg Wunsch     { "_nextpid" },
120511d9c65SJoerg Wunsch     { 0 }
121511d9c65SJoerg Wunsch };
122511d9c65SJoerg Wunsch 
123511d9c65SJoerg Wunsch /*
124511d9c65SJoerg Wunsch  *  These definitions control the format of the per-process area
125511d9c65SJoerg Wunsch  */
126511d9c65SJoerg Wunsch 
12794154ff8SPeter Wemm static char smp_header[] =
128a2aff8b2SPeter Wemm   "  PID %-*.*s PRI NICE  SIZE    RES STATE C   TIME   WCPU    CPU COMMAND";
129511d9c65SJoerg Wunsch 
13094154ff8SPeter Wemm #define smp_Proc_format \
131a2aff8b2SPeter Wemm 	"%5d %-*.*s %3d %3d%7s %6s %-6.6s%1x%7s %5.2f%% %5.2f%% %.*s"
132511d9c65SJoerg Wunsch 
13394154ff8SPeter Wemm static char up_header[] =
134a2aff8b2SPeter Wemm   "  PID %-*.*s PRI NICE  SIZE    RES STATE    TIME   WCPU    CPU COMMAND";
135511d9c65SJoerg Wunsch 
13694154ff8SPeter Wemm #define up_Proc_format \
137a2aff8b2SPeter Wemm 	"%5d %-*.*s %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s"
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;
238a2aff8b2SPeter Wemm     struct passwd *pw;
23994154ff8SPeter Wemm 
24094154ff8SPeter Wemm     modelen = sizeof(smpmode);
241ed550569SPeter Wemm     if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 &&
242ed550569SPeter Wemm          sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) ||
24394154ff8SPeter Wemm 	modelen != sizeof(smpmode))
24494154ff8SPeter Wemm 	    smpmode = 0;
245511d9c65SJoerg Wunsch 
246a2aff8b2SPeter Wemm     while ((pw = getpwent()) != NULL) {
247a2aff8b2SPeter Wemm 	if (strlen(pw->pw_name) > namelength)
248a2aff8b2SPeter Wemm 	    namelength = strlen(pw->pw_name);
249a2aff8b2SPeter Wemm     }
250a2aff8b2SPeter Wemm     if (namelength < 8)
251a2aff8b2SPeter Wemm 	namelength = 8;
252a2aff8b2SPeter Wemm     if (namelength > 16)
253a2aff8b2SPeter Wemm 	namelength = 16;
254a2aff8b2SPeter Wemm 
255511d9c65SJoerg Wunsch     if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
256511d9c65SJoerg Wunsch 	return -1;
257511d9c65SJoerg Wunsch 
258511d9c65SJoerg Wunsch 
259511d9c65SJoerg Wunsch     /* get the list of symbols we want to access in the kernel */
260511d9c65SJoerg Wunsch     (void) kvm_nlist(kd, nlst);
261511d9c65SJoerg Wunsch     if (nlst[0].n_type == 0)
262511d9c65SJoerg Wunsch     {
263511d9c65SJoerg Wunsch 	fprintf(stderr, "top: nlist failed\n");
264511d9c65SJoerg Wunsch 	return(-1);
265511d9c65SJoerg Wunsch     }
266511d9c65SJoerg Wunsch 
267511d9c65SJoerg Wunsch     /* make sure they were all found */
268511d9c65SJoerg Wunsch     if (i > 0 && check_nlist(nlst) > 0)
269511d9c65SJoerg Wunsch     {
270511d9c65SJoerg Wunsch 	return(-1);
271511d9c65SJoerg Wunsch     }
272511d9c65SJoerg Wunsch 
273511d9c65SJoerg Wunsch     /* get the symbol values out of kmem */
274511d9c65SJoerg Wunsch     (void) getkval(nlst[X_STATHZ].n_value, (int *)(&hz), sizeof(hz), "!");
275511d9c65SJoerg Wunsch     if (!hz) {
276511d9c65SJoerg Wunsch 	(void) getkval(nlst[X_HZ].n_value, (int *)(&hz), sizeof(hz),
277511d9c65SJoerg Wunsch 		       nlst[X_HZ].n_name);
278511d9c65SJoerg Wunsch     }
279511d9c65SJoerg Wunsch 
280511d9c65SJoerg Wunsch     (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),	sizeof(ccpu),
281511d9c65SJoerg Wunsch 	    nlst[X_CCPU].n_name);
282511d9c65SJoerg Wunsch 
283511d9c65SJoerg Wunsch     /* stash away certain offsets for later use */
284511d9c65SJoerg Wunsch     cp_time_offset = nlst[X_CP_TIME].n_value;
285511d9c65SJoerg Wunsch     avenrun_offset = nlst[X_AVENRUN].n_value;
286511d9c65SJoerg Wunsch     lastpid_offset =  nlst[X_LASTPID].n_value;
287511d9c65SJoerg Wunsch     cnt_offset = nlst[X_CNT].n_value;
288511d9c65SJoerg Wunsch     bufspace_offset = nlst[X_BUFSPACE].n_value;
289511d9c65SJoerg Wunsch 
290511d9c65SJoerg Wunsch     /* this is used in calculating WCPU -- calculate it ahead of time */
291511d9c65SJoerg Wunsch     logcpu = log(loaddouble(ccpu));
292511d9c65SJoerg Wunsch 
293511d9c65SJoerg Wunsch     pbase = NULL;
294511d9c65SJoerg Wunsch     pref = NULL;
295511d9c65SJoerg Wunsch     nproc = 0;
296511d9c65SJoerg Wunsch     onproc = -1;
297511d9c65SJoerg Wunsch     /* get the page size with "getpagesize" and calculate pageshift from it */
298511d9c65SJoerg Wunsch     pagesize = getpagesize();
299511d9c65SJoerg Wunsch     pageshift = 0;
300511d9c65SJoerg Wunsch     while (pagesize > 1)
301511d9c65SJoerg Wunsch     {
302511d9c65SJoerg Wunsch 	pageshift++;
303511d9c65SJoerg Wunsch 	pagesize >>= 1;
304511d9c65SJoerg Wunsch     }
305511d9c65SJoerg Wunsch 
306511d9c65SJoerg Wunsch     /* we only need the amount of log(2)1024 for our conversion */
307511d9c65SJoerg Wunsch     pageshift -= LOG1024;
308511d9c65SJoerg Wunsch 
309511d9c65SJoerg Wunsch     /* fill in the statics information */
310511d9c65SJoerg Wunsch     statics->procstate_names = procstatenames;
311511d9c65SJoerg Wunsch     statics->cpustate_names = cpustatenames;
312511d9c65SJoerg Wunsch     statics->memory_names = memorynames;
313511d9c65SJoerg Wunsch     statics->swap_names = swapnames;
314511d9c65SJoerg Wunsch 
315511d9c65SJoerg Wunsch     /* all done! */
316511d9c65SJoerg Wunsch     return(0);
317511d9c65SJoerg Wunsch }
318511d9c65SJoerg Wunsch 
319511d9c65SJoerg Wunsch char *format_header(uname_field)
320511d9c65SJoerg Wunsch 
321511d9c65SJoerg Wunsch register char *uname_field;
322511d9c65SJoerg Wunsch 
323511d9c65SJoerg Wunsch {
324511d9c65SJoerg Wunsch     register char *ptr;
325a2aff8b2SPeter Wemm     static char Header[128];
326511d9c65SJoerg Wunsch 
327a2aff8b2SPeter Wemm     snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header,
328a2aff8b2SPeter Wemm 	     namelength, namelength, uname_field);
32994154ff8SPeter Wemm 
330a2aff8b2SPeter Wemm     cmdlength = 80 - strlen(Header) + 6;
331511d9c65SJoerg Wunsch 
332a2aff8b2SPeter Wemm     return Header;
333511d9c65SJoerg Wunsch }
334511d9c65SJoerg Wunsch 
335511d9c65SJoerg Wunsch static int swappgsin = -1;
336511d9c65SJoerg Wunsch static int swappgsout = -1;
337511d9c65SJoerg Wunsch extern struct timeval timeout;
338511d9c65SJoerg Wunsch 
339511d9c65SJoerg Wunsch void
340511d9c65SJoerg Wunsch get_system_info(si)
341511d9c65SJoerg Wunsch 
342511d9c65SJoerg Wunsch struct system_info *si;
343511d9c65SJoerg Wunsch 
344511d9c65SJoerg Wunsch {
345511d9c65SJoerg Wunsch     long total;
346511d9c65SJoerg Wunsch     load_avg avenrun[3];
347511d9c65SJoerg Wunsch 
348511d9c65SJoerg Wunsch     /* get the cp_time array */
349511d9c65SJoerg Wunsch     (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
350511d9c65SJoerg Wunsch 		   nlst[X_CP_TIME].n_name);
351511d9c65SJoerg Wunsch     (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
352511d9c65SJoerg Wunsch 		   nlst[X_AVENRUN].n_name);
353511d9c65SJoerg Wunsch 
354511d9c65SJoerg Wunsch     (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
355511d9c65SJoerg Wunsch 		   "!");
356511d9c65SJoerg Wunsch 
357511d9c65SJoerg Wunsch     /* convert load averages to doubles */
358511d9c65SJoerg Wunsch     {
359511d9c65SJoerg Wunsch 	register int i;
360511d9c65SJoerg Wunsch 	register double *infoloadp;
361511d9c65SJoerg Wunsch 	load_avg *avenrunp;
362511d9c65SJoerg Wunsch 
363511d9c65SJoerg Wunsch #ifdef notyet
364511d9c65SJoerg Wunsch 	struct loadavg sysload;
365511d9c65SJoerg Wunsch 	int size;
366511d9c65SJoerg Wunsch 	getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
367511d9c65SJoerg Wunsch #endif
368511d9c65SJoerg Wunsch 
369511d9c65SJoerg Wunsch 	infoloadp = si->load_avg;
370511d9c65SJoerg Wunsch 	avenrunp = avenrun;
371511d9c65SJoerg Wunsch 	for (i = 0; i < 3; i++)
372511d9c65SJoerg Wunsch 	{
373511d9c65SJoerg Wunsch #ifdef notyet
374511d9c65SJoerg Wunsch 	    *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
375511d9c65SJoerg Wunsch #endif
376511d9c65SJoerg Wunsch 	    *infoloadp++ = loaddouble(*avenrunp++);
377511d9c65SJoerg Wunsch 	}
378511d9c65SJoerg Wunsch     }
379511d9c65SJoerg Wunsch 
380511d9c65SJoerg Wunsch     /* convert cp_time counts to percentages */
381511d9c65SJoerg Wunsch     total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
382511d9c65SJoerg Wunsch 
383511d9c65SJoerg Wunsch     /* sum memory & swap statistics */
384511d9c65SJoerg Wunsch     {
385511d9c65SJoerg Wunsch 	struct vmmeter sum;
386511d9c65SJoerg Wunsch 	static unsigned int swap_delay = 0;
387511d9c65SJoerg Wunsch 	static int swapavail = 0;
388511d9c65SJoerg Wunsch 	static int swapfree = 0;
389511d9c65SJoerg Wunsch 	static int bufspace = 0;
390511d9c65SJoerg Wunsch 
391511d9c65SJoerg Wunsch         (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
392511d9c65SJoerg Wunsch 		   "_cnt");
393511d9c65SJoerg Wunsch         (void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace),
394511d9c65SJoerg Wunsch 		   "_bufspace");
395511d9c65SJoerg Wunsch 
396511d9c65SJoerg Wunsch 	/* convert memory stats to Kbytes */
397511d9c65SJoerg Wunsch 	memory_stats[0] = pagetok(sum.v_active_count);
398511d9c65SJoerg Wunsch 	memory_stats[1] = pagetok(sum.v_inactive_count);
399511d9c65SJoerg Wunsch 	memory_stats[2] = pagetok(sum.v_wire_count);
400511d9c65SJoerg Wunsch 	memory_stats[3] = pagetok(sum.v_cache_count);
401511d9c65SJoerg Wunsch 	memory_stats[4] = bufspace / 1024;
402511d9c65SJoerg Wunsch 	memory_stats[5] = pagetok(sum.v_free_count);
403511d9c65SJoerg Wunsch 	memory_stats[6] = -1;
404511d9c65SJoerg Wunsch 
405511d9c65SJoerg Wunsch 	/* first interval */
406511d9c65SJoerg Wunsch         if (swappgsin < 0) {
407511d9c65SJoerg Wunsch 	    swap_stats[4] = 0;
408511d9c65SJoerg Wunsch 	    swap_stats[5] = 0;
409511d9c65SJoerg Wunsch 	}
410511d9c65SJoerg Wunsch 
411511d9c65SJoerg Wunsch 	/* compute differences between old and new swap statistic */
412511d9c65SJoerg Wunsch 	else {
413511d9c65SJoerg Wunsch 	    swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin)));
414511d9c65SJoerg Wunsch 	    swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout)));
415511d9c65SJoerg Wunsch 	}
416511d9c65SJoerg Wunsch 
417511d9c65SJoerg Wunsch         swappgsin = sum.v_swappgsin;
418511d9c65SJoerg Wunsch 	swappgsout = sum.v_swappgsout;
419511d9c65SJoerg Wunsch 
420511d9c65SJoerg Wunsch 	/* call CPU heavy swapmode() only for changes */
421511d9c65SJoerg Wunsch         if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
422511d9c65SJoerg Wunsch 	    swap_stats[3] = swapmode(&swapavail, &swapfree);
423511d9c65SJoerg Wunsch 	    swap_stats[0] = swapavail;
424511d9c65SJoerg Wunsch 	    swap_stats[1] = swapavail - swapfree;
425511d9c65SJoerg Wunsch 	    swap_stats[2] = swapfree;
426511d9c65SJoerg Wunsch 	}
427511d9c65SJoerg Wunsch         swap_delay = 1;
428511d9c65SJoerg Wunsch 	swap_stats[6] = -1;
429511d9c65SJoerg Wunsch     }
430511d9c65SJoerg Wunsch 
431511d9c65SJoerg Wunsch     /* set arrays and strings */
432511d9c65SJoerg Wunsch     si->cpustates = cpu_states;
433511d9c65SJoerg Wunsch     si->memory = memory_stats;
434511d9c65SJoerg Wunsch     si->swap = swap_stats;
435511d9c65SJoerg Wunsch 
436511d9c65SJoerg Wunsch 
437511d9c65SJoerg Wunsch     if(lastpid > 0) {
438511d9c65SJoerg Wunsch 	si->last_pid = lastpid;
439511d9c65SJoerg Wunsch     } else {
440511d9c65SJoerg Wunsch 	si->last_pid = -1;
441511d9c65SJoerg Wunsch     }
442511d9c65SJoerg Wunsch }
443511d9c65SJoerg Wunsch 
444511d9c65SJoerg Wunsch static struct handle handle;
445511d9c65SJoerg Wunsch 
446511d9c65SJoerg Wunsch caddr_t get_process_info(si, sel, compare)
447511d9c65SJoerg Wunsch 
448511d9c65SJoerg Wunsch struct system_info *si;
449511d9c65SJoerg Wunsch struct process_select *sel;
450511d9c65SJoerg Wunsch int (*compare)();
451511d9c65SJoerg Wunsch 
452511d9c65SJoerg Wunsch {
453511d9c65SJoerg Wunsch     register int i;
454511d9c65SJoerg Wunsch     register int total_procs;
455511d9c65SJoerg Wunsch     register int active_procs;
456511d9c65SJoerg Wunsch     register struct kinfo_proc **prefp;
457511d9c65SJoerg Wunsch     register struct kinfo_proc *pp;
458511d9c65SJoerg Wunsch 
459511d9c65SJoerg Wunsch     /* these are copied out of sel for speed */
460511d9c65SJoerg Wunsch     int show_idle;
461511d9c65SJoerg Wunsch     int show_system;
462511d9c65SJoerg Wunsch     int show_uid;
463511d9c65SJoerg Wunsch     int show_command;
464511d9c65SJoerg Wunsch 
465511d9c65SJoerg Wunsch 
466511d9c65SJoerg Wunsch     pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
467511d9c65SJoerg Wunsch     if (nproc > onproc)
468511d9c65SJoerg Wunsch 	pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
469511d9c65SJoerg Wunsch 		* (onproc = nproc));
470511d9c65SJoerg Wunsch     if (pref == NULL || pbase == NULL) {
471511d9c65SJoerg Wunsch 	(void) fprintf(stderr, "top: Out of memory.\n");
472511d9c65SJoerg Wunsch 	quit(23);
473511d9c65SJoerg Wunsch     }
474511d9c65SJoerg Wunsch     /* get a pointer to the states summary array */
475511d9c65SJoerg Wunsch     si->procstates = process_states;
476511d9c65SJoerg Wunsch 
477511d9c65SJoerg Wunsch     /* set up flags which define what we are going to select */
478511d9c65SJoerg Wunsch     show_idle = sel->idle;
479511d9c65SJoerg Wunsch     show_system = sel->system;
480511d9c65SJoerg Wunsch     show_uid = sel->uid != -1;
481511d9c65SJoerg Wunsch     show_command = sel->command != NULL;
482511d9c65SJoerg Wunsch 
483511d9c65SJoerg Wunsch     /* count up process states and get pointers to interesting procs */
484511d9c65SJoerg Wunsch     total_procs = 0;
485511d9c65SJoerg Wunsch     active_procs = 0;
486511d9c65SJoerg Wunsch     memset((char *)process_states, 0, sizeof(process_states));
487511d9c65SJoerg Wunsch     prefp = pref;
488511d9c65SJoerg Wunsch     for (pp = pbase, i = 0; i < nproc; pp++, i++)
489511d9c65SJoerg Wunsch     {
490511d9c65SJoerg Wunsch 	/*
491511d9c65SJoerg Wunsch 	 *  Place pointers to each valid proc structure in pref[].
492511d9c65SJoerg Wunsch 	 *  Process slots that are actually in use have a non-zero
493511d9c65SJoerg Wunsch 	 *  status field.  Processes with P_SYSTEM set are system
494511d9c65SJoerg Wunsch 	 *  processes---these get ignored unless show_sysprocs is set.
495511d9c65SJoerg Wunsch 	 */
496511d9c65SJoerg Wunsch 	if (PP(pp, p_stat) != 0 &&
497511d9c65SJoerg Wunsch 	    (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
498511d9c65SJoerg Wunsch 	{
499511d9c65SJoerg Wunsch 	    total_procs++;
500511d9c65SJoerg Wunsch 	    process_states[(unsigned char) PP(pp, p_stat)]++;
501511d9c65SJoerg Wunsch 	    if ((PP(pp, p_stat) != SZOMB) &&
502511d9c65SJoerg Wunsch 		(show_idle || (PP(pp, p_pctcpu) != 0) ||
503511d9c65SJoerg Wunsch 		 (PP(pp, p_stat) == SRUN)) &&
504511d9c65SJoerg Wunsch 		(!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
505511d9c65SJoerg Wunsch 	    {
506511d9c65SJoerg Wunsch 		*prefp++ = pp;
507511d9c65SJoerg Wunsch 		active_procs++;
508511d9c65SJoerg Wunsch 	    }
509511d9c65SJoerg Wunsch 	}
510511d9c65SJoerg Wunsch     }
511511d9c65SJoerg Wunsch 
512511d9c65SJoerg Wunsch     /* if requested, sort the "interesting" processes */
513511d9c65SJoerg Wunsch     if (compare != NULL)
514511d9c65SJoerg Wunsch     {
515511d9c65SJoerg Wunsch 	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
516511d9c65SJoerg Wunsch     }
517511d9c65SJoerg Wunsch 
518511d9c65SJoerg Wunsch     /* remember active and total counts */
519511d9c65SJoerg Wunsch     si->p_total = total_procs;
520511d9c65SJoerg Wunsch     si->p_active = pref_len = active_procs;
521511d9c65SJoerg Wunsch 
522511d9c65SJoerg Wunsch     /* pass back a handle */
523511d9c65SJoerg Wunsch     handle.next_proc = pref;
524511d9c65SJoerg Wunsch     handle.remaining = active_procs;
525511d9c65SJoerg Wunsch     return((caddr_t)&handle);
526511d9c65SJoerg Wunsch }
527511d9c65SJoerg Wunsch 
528511d9c65SJoerg Wunsch char fmt[128];		/* static area where result is built */
529511d9c65SJoerg Wunsch 
530511d9c65SJoerg Wunsch char *format_next_process(handle, get_userid)
531511d9c65SJoerg Wunsch 
532511d9c65SJoerg Wunsch caddr_t handle;
533511d9c65SJoerg Wunsch char *(*get_userid)();
534511d9c65SJoerg Wunsch 
535511d9c65SJoerg Wunsch {
536511d9c65SJoerg Wunsch     register struct kinfo_proc *pp;
537511d9c65SJoerg Wunsch     register long cputime;
538511d9c65SJoerg Wunsch     register double pct;
539511d9c65SJoerg Wunsch     struct handle *hp;
540511d9c65SJoerg Wunsch     char status[16];
541511d9c65SJoerg Wunsch 
542511d9c65SJoerg Wunsch     /* find and remember the next proc structure */
543511d9c65SJoerg Wunsch     hp = (struct handle *)handle;
544511d9c65SJoerg Wunsch     pp = *(hp->next_proc++);
545511d9c65SJoerg Wunsch     hp->remaining--;
546511d9c65SJoerg Wunsch 
547511d9c65SJoerg Wunsch 
548511d9c65SJoerg Wunsch     /* get the process's user struct and set cputime */
549511d9c65SJoerg Wunsch     if ((PP(pp, p_flag) & P_INMEM) == 0) {
550511d9c65SJoerg Wunsch 	/*
551511d9c65SJoerg Wunsch 	 * Print swapped processes as <pname>
552511d9c65SJoerg Wunsch 	 */
553511d9c65SJoerg Wunsch 	char *comm = PP(pp, p_comm);
554511d9c65SJoerg Wunsch #define COMSIZ sizeof(PP(pp, p_comm))
555511d9c65SJoerg Wunsch 	char buf[COMSIZ];
556511d9c65SJoerg Wunsch 	(void) strncpy(buf, comm, COMSIZ);
557511d9c65SJoerg Wunsch 	comm[0] = '<';
558511d9c65SJoerg Wunsch 	(void) strncpy(&comm[1], buf, COMSIZ - 2);
559511d9c65SJoerg Wunsch 	comm[COMSIZ - 2] = '\0';
560511d9c65SJoerg Wunsch 	(void) strncat(comm, ">", COMSIZ - 1);
561511d9c65SJoerg Wunsch 	comm[COMSIZ - 1] = '\0';
562511d9c65SJoerg Wunsch     }
563511d9c65SJoerg Wunsch 
564511d9c65SJoerg Wunsch #if 0
565511d9c65SJoerg Wunsch     /* This does not produce the correct results */
566511d9c65SJoerg Wunsch     cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
567511d9c65SJoerg Wunsch #endif
568511d9c65SJoerg Wunsch     cputime = PP(pp, p_rtime).tv_sec;	/* This does not count interrupts */
569511d9c65SJoerg Wunsch 
570511d9c65SJoerg Wunsch     /* calculate the base for cpu percentages */
571511d9c65SJoerg Wunsch     pct = pctdouble(PP(pp, p_pctcpu));
572511d9c65SJoerg Wunsch 
573511d9c65SJoerg Wunsch     /* generate "STATE" field */
574511d9c65SJoerg Wunsch     switch (PP(pp, p_stat)) {
575511d9c65SJoerg Wunsch 	case SRUN:
57694154ff8SPeter Wemm 	    if (smpmode && PP(pp, p_oncpu) >= 0)
577511d9c65SJoerg Wunsch 		sprintf(status, "CPU%d", PP(pp, p_oncpu));
578511d9c65SJoerg Wunsch 	    else
579511d9c65SJoerg Wunsch 		strcpy(status, "RUN");
580511d9c65SJoerg Wunsch 	    break;
581511d9c65SJoerg Wunsch 	case SSLEEP:
582511d9c65SJoerg Wunsch 	    if (PP(pp, p_wmesg) != NULL) {
583511d9c65SJoerg Wunsch 		sprintf(status, "%.6s", EP(pp, e_wmesg));
584511d9c65SJoerg Wunsch 		break;
585511d9c65SJoerg Wunsch 	    }
586511d9c65SJoerg Wunsch 	    /* fall through */
587511d9c65SJoerg Wunsch 	default:
588511d9c65SJoerg Wunsch 	    sprintf(status, "%.6s", state_abbrev[(unsigned char) PP(pp, p_stat)]);
589511d9c65SJoerg Wunsch 	    break;
590511d9c65SJoerg Wunsch     }
591511d9c65SJoerg Wunsch 
592511d9c65SJoerg Wunsch     /* format this entry */
593511d9c65SJoerg Wunsch     sprintf(fmt,
59494154ff8SPeter Wemm 	    smpmode ? smp_Proc_format : up_Proc_format,
595511d9c65SJoerg Wunsch 	    PP(pp, p_pid),
596a2aff8b2SPeter Wemm 	    namelength, namelength,
597511d9c65SJoerg Wunsch 	    (*get_userid)(EP(pp, e_pcred.p_ruid)),
598511d9c65SJoerg Wunsch 	    PP(pp, p_priority) - PZERO,
599e5aff02fSPeter Wemm 
600e5aff02fSPeter Wemm 	    /*
601e5aff02fSPeter Wemm 	     * normal time      -> nice value -20 - +20
602e5aff02fSPeter Wemm 	     * real time 0 - 31 -> nice value -52 - -21
603e5aff02fSPeter Wemm 	     * idle time 0 - 31 -> nice value +21 - +52
604e5aff02fSPeter Wemm 	     */
605e5aff02fSPeter Wemm 	    (PP(pp, p_rtprio.type) ==  RTP_PRIO_NORMAL ?
606e5aff02fSPeter Wemm 	    	PP(pp, p_nice) - NZERO :
607e5aff02fSPeter Wemm 	    	(PP(pp, p_rtprio.type) ==  RTP_PRIO_REALTIME ?
608e5aff02fSPeter Wemm 		    (PRIO_MIN - 1 - RTP_PRIO_MAX + PP(pp, p_rtprio.prio)) :
609e5aff02fSPeter Wemm 		    (PRIO_MAX + 1 + PP(pp, p_rtprio.prio)))),
610511d9c65SJoerg Wunsch 	    format_k2(pagetok(PROCSIZE(pp))),
611511d9c65SJoerg Wunsch 	    format_k2(pagetok(VP(pp, vm_rssize))),
612511d9c65SJoerg Wunsch 	    status,
61394154ff8SPeter Wemm 	    smpmode ? PP(pp, p_lastcpu) : 0,
614511d9c65SJoerg Wunsch 	    format_time(cputime),
615511d9c65SJoerg Wunsch 	    10000.0 * weighted_cpu(pct, pp) / hz,
616511d9c65SJoerg Wunsch 	    10000.0 * pct / hz,
617a2aff8b2SPeter Wemm 	    cmdlength,
618511d9c65SJoerg Wunsch 	    printable(PP(pp, p_comm)));
619511d9c65SJoerg Wunsch 
620511d9c65SJoerg Wunsch     /* return the result */
621511d9c65SJoerg Wunsch     return(fmt);
622511d9c65SJoerg Wunsch }
623511d9c65SJoerg Wunsch 
624511d9c65SJoerg Wunsch 
625511d9c65SJoerg Wunsch /*
626511d9c65SJoerg Wunsch  * check_nlist(nlst) - checks the nlist to see if any symbols were not
627511d9c65SJoerg Wunsch  *		found.  For every symbol that was not found, a one-line
628511d9c65SJoerg Wunsch  *		message is printed to stderr.  The routine returns the
629511d9c65SJoerg Wunsch  *		number of symbols NOT found.
630511d9c65SJoerg Wunsch  */
631511d9c65SJoerg Wunsch 
632511d9c65SJoerg Wunsch static int check_nlist(nlst)
633511d9c65SJoerg Wunsch 
634511d9c65SJoerg Wunsch register struct nlist *nlst;
635511d9c65SJoerg Wunsch 
636511d9c65SJoerg Wunsch {
637511d9c65SJoerg Wunsch     register int i;
638511d9c65SJoerg Wunsch 
639511d9c65SJoerg Wunsch     /* check to see if we got ALL the symbols we requested */
640511d9c65SJoerg Wunsch     /* this will write one line to stderr for every symbol not found */
641511d9c65SJoerg Wunsch 
642511d9c65SJoerg Wunsch     i = 0;
643511d9c65SJoerg Wunsch     while (nlst->n_name != NULL)
644511d9c65SJoerg Wunsch     {
645511d9c65SJoerg Wunsch 	if (nlst->n_type == 0)
646511d9c65SJoerg Wunsch 	{
647511d9c65SJoerg Wunsch 	    /* this one wasn't found */
648511d9c65SJoerg Wunsch 	    (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
649511d9c65SJoerg Wunsch 			   nlst->n_name);
650511d9c65SJoerg Wunsch 	    i = 1;
651511d9c65SJoerg Wunsch 	}
652511d9c65SJoerg Wunsch 	nlst++;
653511d9c65SJoerg Wunsch     }
654511d9c65SJoerg Wunsch 
655511d9c65SJoerg Wunsch     return(i);
656511d9c65SJoerg Wunsch }
657511d9c65SJoerg Wunsch 
658511d9c65SJoerg Wunsch 
659511d9c65SJoerg Wunsch /*
660511d9c65SJoerg Wunsch  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
661511d9c65SJoerg Wunsch  *	"offset" is the byte offset into the kernel for the desired value,
662511d9c65SJoerg Wunsch  *  	"ptr" points to a buffer into which the value is retrieved,
663511d9c65SJoerg Wunsch  *  	"size" is the size of the buffer (and the object to retrieve),
664511d9c65SJoerg Wunsch  *  	"refstr" is a reference string used when printing error meessages,
665511d9c65SJoerg Wunsch  *	    if "refstr" starts with a '!', then a failure on read will not
666511d9c65SJoerg Wunsch  *  	    be fatal (this may seem like a silly way to do things, but I
667511d9c65SJoerg Wunsch  *  	    really didn't want the overhead of another argument).
668511d9c65SJoerg Wunsch  *
669511d9c65SJoerg Wunsch  */
670511d9c65SJoerg Wunsch 
671511d9c65SJoerg Wunsch static int getkval(offset, ptr, size, refstr)
672511d9c65SJoerg Wunsch 
673511d9c65SJoerg Wunsch unsigned long offset;
674511d9c65SJoerg Wunsch int *ptr;
675511d9c65SJoerg Wunsch int size;
676511d9c65SJoerg Wunsch char *refstr;
677511d9c65SJoerg Wunsch 
678511d9c65SJoerg Wunsch {
679511d9c65SJoerg Wunsch     if (kvm_read(kd, offset, (char *) ptr, size) != size)
680511d9c65SJoerg Wunsch     {
681511d9c65SJoerg Wunsch 	if (*refstr == '!')
682511d9c65SJoerg Wunsch 	{
683511d9c65SJoerg Wunsch 	    return(0);
684511d9c65SJoerg Wunsch 	}
685511d9c65SJoerg Wunsch 	else
686511d9c65SJoerg Wunsch 	{
687511d9c65SJoerg Wunsch 	    fprintf(stderr, "top: kvm_read for %s: %s\n",
688511d9c65SJoerg Wunsch 		refstr, strerror(errno));
689511d9c65SJoerg Wunsch 	    quit(23);
690511d9c65SJoerg Wunsch 	}
691511d9c65SJoerg Wunsch     }
692511d9c65SJoerg Wunsch     return(1);
693511d9c65SJoerg Wunsch }
694511d9c65SJoerg Wunsch 
695511d9c65SJoerg Wunsch /* comparison routine for qsort */
696511d9c65SJoerg Wunsch 
697511d9c65SJoerg Wunsch /*
698511d9c65SJoerg Wunsch  *  proc_compare - comparison function for "qsort"
699511d9c65SJoerg Wunsch  *	Compares the resource consumption of two processes using five
700511d9c65SJoerg Wunsch  *  	distinct keys.  The keys (in descending order of importance) are:
701511d9c65SJoerg Wunsch  *  	percent cpu, cpu ticks, state, resident set size, total virtual
702511d9c65SJoerg Wunsch  *  	memory usage.  The process states are ordered as follows (from least
703511d9c65SJoerg Wunsch  *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
704511d9c65SJoerg Wunsch  *  	array declaration below maps a process state index into a number
705511d9c65SJoerg Wunsch  *  	that reflects this ordering.
706511d9c65SJoerg Wunsch  */
707511d9c65SJoerg Wunsch 
708511d9c65SJoerg Wunsch static unsigned char sorted_state[] =
709511d9c65SJoerg Wunsch {
710511d9c65SJoerg Wunsch     0,	/* not used		*/
711511d9c65SJoerg Wunsch     3,	/* sleep		*/
712511d9c65SJoerg Wunsch     1,	/* ABANDONED (WAIT)	*/
713511d9c65SJoerg Wunsch     6,	/* run			*/
714511d9c65SJoerg Wunsch     5,	/* start		*/
715511d9c65SJoerg Wunsch     2,	/* zombie		*/
716511d9c65SJoerg Wunsch     4	/* stop			*/
717511d9c65SJoerg Wunsch };
718511d9c65SJoerg Wunsch 
719511d9c65SJoerg Wunsch int
720511d9c65SJoerg Wunsch proc_compare(pp1, pp2)
721511d9c65SJoerg Wunsch 
722511d9c65SJoerg Wunsch struct proc **pp1;
723511d9c65SJoerg Wunsch struct proc **pp2;
724511d9c65SJoerg Wunsch 
725511d9c65SJoerg Wunsch {
726511d9c65SJoerg Wunsch     register struct kinfo_proc *p1;
727511d9c65SJoerg Wunsch     register struct kinfo_proc *p2;
728511d9c65SJoerg Wunsch     register int result;
729511d9c65SJoerg Wunsch     register pctcpu lresult;
730511d9c65SJoerg Wunsch 
731511d9c65SJoerg Wunsch     /* remove one level of indirection */
732511d9c65SJoerg Wunsch     p1 = *(struct kinfo_proc **) pp1;
733511d9c65SJoerg Wunsch     p2 = *(struct kinfo_proc **) pp2;
734511d9c65SJoerg Wunsch 
735511d9c65SJoerg Wunsch     /* compare percent cpu (pctcpu) */
736511d9c65SJoerg Wunsch     if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
737511d9c65SJoerg Wunsch     {
738511d9c65SJoerg Wunsch 	/* use cpticks to break the tie */
739511d9c65SJoerg Wunsch 	if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
740511d9c65SJoerg Wunsch 	{
741511d9c65SJoerg Wunsch 	    /* use process state to break the tie */
742511d9c65SJoerg Wunsch 	    if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
743511d9c65SJoerg Wunsch 			  sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
744511d9c65SJoerg Wunsch 	    {
745511d9c65SJoerg Wunsch 		/* use priority to break the tie */
746511d9c65SJoerg Wunsch 		if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
747511d9c65SJoerg Wunsch 		{
748511d9c65SJoerg Wunsch 		    /* use resident set size (rssize) to break the tie */
749511d9c65SJoerg Wunsch 		    if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
750511d9c65SJoerg Wunsch 		    {
751511d9c65SJoerg Wunsch 			/* use total memory to break the tie */
752511d9c65SJoerg Wunsch 			result = PROCSIZE(p2) - PROCSIZE(p1);
753511d9c65SJoerg Wunsch 		    }
754511d9c65SJoerg Wunsch 		}
755511d9c65SJoerg Wunsch 	    }
756511d9c65SJoerg Wunsch 	}
757511d9c65SJoerg Wunsch     }
758511d9c65SJoerg Wunsch     else
759511d9c65SJoerg Wunsch     {
760511d9c65SJoerg Wunsch 	result = lresult < 0 ? -1 : 1;
761511d9c65SJoerg Wunsch     }
762511d9c65SJoerg Wunsch 
763511d9c65SJoerg Wunsch     return(result);
764511d9c65SJoerg Wunsch }
765511d9c65SJoerg Wunsch 
766511d9c65SJoerg Wunsch 
767511d9c65SJoerg Wunsch /*
768511d9c65SJoerg Wunsch  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
769511d9c65SJoerg Wunsch  *		the process does not exist.
770511d9c65SJoerg Wunsch  *		It is EXTREMLY IMPORTANT that this function work correctly.
771511d9c65SJoerg Wunsch  *		If top runs setuid root (as in SVR4), then this function
772511d9c65SJoerg Wunsch  *		is the only thing that stands in the way of a serious
773511d9c65SJoerg Wunsch  *		security problem.  It validates requests for the "kill"
774511d9c65SJoerg Wunsch  *		and "renice" commands.
775511d9c65SJoerg Wunsch  */
776511d9c65SJoerg Wunsch 
777511d9c65SJoerg Wunsch int proc_owner(pid)
778511d9c65SJoerg Wunsch 
779511d9c65SJoerg Wunsch int pid;
780511d9c65SJoerg Wunsch 
781511d9c65SJoerg Wunsch {
782511d9c65SJoerg Wunsch     register int cnt;
783511d9c65SJoerg Wunsch     register struct kinfo_proc **prefp;
784511d9c65SJoerg Wunsch     register struct kinfo_proc *pp;
785511d9c65SJoerg Wunsch 
786511d9c65SJoerg Wunsch     prefp = pref;
787511d9c65SJoerg Wunsch     cnt = pref_len;
788511d9c65SJoerg Wunsch     while (--cnt >= 0)
789511d9c65SJoerg Wunsch     {
790511d9c65SJoerg Wunsch 	pp = *prefp++;
791511d9c65SJoerg Wunsch 	if (PP(pp, p_pid) == (pid_t)pid)
792511d9c65SJoerg Wunsch 	{
793511d9c65SJoerg Wunsch 	    return((int)EP(pp, e_pcred.p_ruid));
794511d9c65SJoerg Wunsch 	}
795511d9c65SJoerg Wunsch     }
796511d9c65SJoerg Wunsch     return(-1);
797511d9c65SJoerg Wunsch }
798511d9c65SJoerg Wunsch 
799511d9c65SJoerg Wunsch 
800511d9c65SJoerg Wunsch /*
801511d9c65SJoerg Wunsch  * swapmode is based on a program called swapinfo written
802511d9c65SJoerg Wunsch  * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
803511d9c65SJoerg Wunsch  */
804511d9c65SJoerg Wunsch 
805511d9c65SJoerg Wunsch #define	SVAR(var) __STRING(var)	/* to force expansion */
806511d9c65SJoerg Wunsch #define	KGET(idx, var)							\
807511d9c65SJoerg Wunsch 	KGET1(idx, &var, sizeof(var), SVAR(var))
808511d9c65SJoerg Wunsch #define	KGET1(idx, p, s, msg)						\
809511d9c65SJoerg Wunsch 	KGET2(nlst[idx].n_value, p, s, msg)
810511d9c65SJoerg Wunsch #define	KGET2(addr, p, s, msg)						\
811511d9c65SJoerg Wunsch 	if (kvm_read(kd, (u_long)(addr), p, s) != s) {		        \
812511d9c65SJoerg Wunsch 		warnx("cannot read %s: %s", msg, kvm_geterr(kd));       \
813511d9c65SJoerg Wunsch 		return (0);                                             \
814511d9c65SJoerg Wunsch        }
815511d9c65SJoerg Wunsch #define	KGETRET(addr, p, s, msg)					\
816511d9c65SJoerg Wunsch 	if (kvm_read(kd, (u_long)(addr), p, s) != s) {			\
817511d9c65SJoerg Wunsch 		warnx("cannot read %s: %s", msg, kvm_geterr(kd));	\
818511d9c65SJoerg Wunsch 		return (0);						\
819511d9c65SJoerg Wunsch 	}
820511d9c65SJoerg Wunsch 
821511d9c65SJoerg Wunsch 
822511d9c65SJoerg Wunsch int
823511d9c65SJoerg Wunsch swapmode(retavail, retfree)
824511d9c65SJoerg Wunsch 	int *retavail;
825511d9c65SJoerg Wunsch 	int *retfree;
826511d9c65SJoerg Wunsch {
827511d9c65SJoerg Wunsch 	char *header;
828511d9c65SJoerg Wunsch 	int hlen, nswap, nswdev, dmmax;
829511d9c65SJoerg Wunsch 	int i, div, avail, nfree, npfree, used;
830511d9c65SJoerg Wunsch 	struct swdevt *sw;
831511d9c65SJoerg Wunsch 	long blocksize, *perdev;
832511d9c65SJoerg Wunsch 	u_long ptr;
833511d9c65SJoerg Wunsch 	struct rlist head;
834511d9c65SJoerg Wunsch #if __FreeBSD_version >= 220000
835511d9c65SJoerg Wunsch 	struct rlisthdr swaplist;
836511d9c65SJoerg Wunsch #else
837511d9c65SJoerg Wunsch 	struct rlist *swaplist;
838511d9c65SJoerg Wunsch #endif
839511d9c65SJoerg Wunsch 	struct rlist *swapptr;
840511d9c65SJoerg Wunsch 
841511d9c65SJoerg Wunsch 	/*
842511d9c65SJoerg Wunsch 	 * Counter for error messages. If we reach the limit,
843511d9c65SJoerg Wunsch 	 * stop reading information from swap devices and
844511d9c65SJoerg Wunsch 	 * return zero. This prevent endless 'bad address'
845511d9c65SJoerg Wunsch 	 * messages.
846511d9c65SJoerg Wunsch 	 */
847511d9c65SJoerg Wunsch 	static warning = 10;
848511d9c65SJoerg Wunsch 
849511d9c65SJoerg Wunsch 	if (warning <= 0) {
850511d9c65SJoerg Wunsch 	    /* a single warning */
851511d9c65SJoerg Wunsch 	    if (!warning) {
852511d9c65SJoerg Wunsch 		warning--;
853511d9c65SJoerg Wunsch 		fprintf(stderr,
854511d9c65SJoerg Wunsch 			"Too much errors, stop reading swap devices ...\n");
855511d9c65SJoerg Wunsch 		(void)sleep(3);
856511d9c65SJoerg Wunsch 	    }
857511d9c65SJoerg Wunsch 	    return(0);
858511d9c65SJoerg Wunsch 	}
859511d9c65SJoerg Wunsch 	warning--; /* decrease counter, see end of function */
860511d9c65SJoerg Wunsch 
861511d9c65SJoerg Wunsch 	KGET(VM_NSWAP, nswap);
862511d9c65SJoerg Wunsch 	if (!nswap) {
863511d9c65SJoerg Wunsch 		fprintf(stderr, "No swap space available\n");
864511d9c65SJoerg Wunsch 		return(0);
865511d9c65SJoerg Wunsch 	}
866511d9c65SJoerg Wunsch 
867511d9c65SJoerg Wunsch 	KGET(VM_NSWDEV, nswdev);
868511d9c65SJoerg Wunsch 	KGET(VM_DMMAX, dmmax);
869511d9c65SJoerg Wunsch 	KGET1(VM_SWAPLIST, &swaplist, sizeof(swaplist), "swaplist");
870511d9c65SJoerg Wunsch 	if ((sw = (struct swdevt *)malloc(nswdev * sizeof(*sw))) == NULL ||
871511d9c65SJoerg Wunsch 	    (perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
872511d9c65SJoerg Wunsch 		err(1, "malloc");
873511d9c65SJoerg Wunsch 	KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
874511d9c65SJoerg Wunsch 	KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
875511d9c65SJoerg Wunsch 
876511d9c65SJoerg Wunsch 	/* Count up swap space. */
877511d9c65SJoerg Wunsch 	nfree = 0;
878511d9c65SJoerg Wunsch 	memset(perdev, 0, nswdev * sizeof(*perdev));
879511d9c65SJoerg Wunsch #if  __FreeBSD_version >= 220000
880511d9c65SJoerg Wunsch 	swapptr = swaplist.rlh_list;
881511d9c65SJoerg Wunsch 	while (swapptr) {
882511d9c65SJoerg Wunsch #else
883511d9c65SJoerg Wunsch 	while (swaplist) {
884511d9c65SJoerg Wunsch #endif
885511d9c65SJoerg Wunsch 		int	top, bottom, next_block;
886511d9c65SJoerg Wunsch #if  __FreeBSD_version >= 220000
887511d9c65SJoerg Wunsch 		KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
888511d9c65SJoerg Wunsch #else
889511d9c65SJoerg Wunsch 		KGET2(swaplist, &head, sizeof(struct rlist), "swaplist");
890511d9c65SJoerg Wunsch #endif
891511d9c65SJoerg Wunsch 
892511d9c65SJoerg Wunsch 		top = head.rl_end;
893511d9c65SJoerg Wunsch 		bottom = head.rl_start;
894511d9c65SJoerg Wunsch 
895511d9c65SJoerg Wunsch 		nfree += top - bottom + 1;
896511d9c65SJoerg Wunsch 
897511d9c65SJoerg Wunsch 		/*
898511d9c65SJoerg Wunsch 		 * Swap space is split up among the configured disks.
899511d9c65SJoerg Wunsch 		 *
900511d9c65SJoerg Wunsch 		 * For interleaved swap devices, the first dmmax blocks
901511d9c65SJoerg Wunsch 		 * of swap space some from the first disk, the next dmmax
902511d9c65SJoerg Wunsch 		 * blocks from the next, and so on up to nswap blocks.
903511d9c65SJoerg Wunsch 		 *
904511d9c65SJoerg Wunsch 		 * The list of free space joins adjacent free blocks,
905511d9c65SJoerg Wunsch 		 * ignoring device boundries.  If we want to keep track
906511d9c65SJoerg Wunsch 		 * of this information per device, we'll just have to
907511d9c65SJoerg Wunsch 		 * extract it ourselves.
908511d9c65SJoerg Wunsch 		 */
909511d9c65SJoerg Wunsch 		while (top / dmmax != bottom / dmmax) {
910511d9c65SJoerg Wunsch 			next_block = ((bottom + dmmax) / dmmax);
911511d9c65SJoerg Wunsch 			perdev[(bottom / dmmax) % nswdev] +=
912511d9c65SJoerg Wunsch 				next_block * dmmax - bottom;
913511d9c65SJoerg Wunsch 			bottom = next_block * dmmax;
914511d9c65SJoerg Wunsch 		}
915511d9c65SJoerg Wunsch 		perdev[(bottom / dmmax) % nswdev] +=
916511d9c65SJoerg Wunsch 			top - bottom + 1;
917511d9c65SJoerg Wunsch 
918511d9c65SJoerg Wunsch #if  __FreeBSD_version >= 220000
919511d9c65SJoerg Wunsch 		swapptr = head.rl_next;
920511d9c65SJoerg Wunsch #else
921511d9c65SJoerg Wunsch 		swaplist = head.rl_next;
922511d9c65SJoerg Wunsch #endif
923511d9c65SJoerg Wunsch 	}
924511d9c65SJoerg Wunsch 
925511d9c65SJoerg Wunsch 	header = getbsize(&hlen, &blocksize);
926511d9c65SJoerg Wunsch 	div = blocksize / 512;
927511d9c65SJoerg Wunsch 	avail = npfree = 0;
928511d9c65SJoerg Wunsch 	for (i = 0; i < nswdev; i++) {
929511d9c65SJoerg Wunsch 		int xsize, xfree;
930511d9c65SJoerg Wunsch 
931511d9c65SJoerg Wunsch 		/*
932511d9c65SJoerg Wunsch 		 * Don't report statistics for partitions which have not
933511d9c65SJoerg Wunsch 		 * yet been activated via swapon(8).
934511d9c65SJoerg Wunsch 		 */
935511d9c65SJoerg Wunsch 
936511d9c65SJoerg Wunsch 		xsize = sw[i].sw_nblks;
937511d9c65SJoerg Wunsch 		xfree = perdev[i];
938511d9c65SJoerg Wunsch 		used = xsize - xfree;
939511d9c65SJoerg Wunsch 		npfree++;
940511d9c65SJoerg Wunsch 		avail += xsize;
941511d9c65SJoerg Wunsch 	}
942511d9c65SJoerg Wunsch 
943511d9c65SJoerg Wunsch 	/*
944511d9c65SJoerg Wunsch 	 * If only one partition has been set up via swapon(8), we don't
945511d9c65SJoerg Wunsch 	 * need to bother with totals.
946511d9c65SJoerg Wunsch 	 */
947511d9c65SJoerg Wunsch 	*retavail = avail / 2;
948511d9c65SJoerg Wunsch 	*retfree = nfree / 2;
949511d9c65SJoerg Wunsch 	used = avail - nfree;
950511d9c65SJoerg Wunsch 	free(sw); free(perdev);
951511d9c65SJoerg Wunsch 
952511d9c65SJoerg Wunsch 	/* increase counter, no errors occurs */
953511d9c65SJoerg Wunsch 	warning++;
954511d9c65SJoerg Wunsch 
955511d9c65SJoerg Wunsch 	return  (int)(((double)used / (double)avail * 100.0) + 0.5);
956511d9c65SJoerg Wunsch }
957