machine.c revision 41358
1/*
2 * top - a top users display for Unix
3 *
4 * SYNOPSIS:  For FreeBSD-2.x system
5 *
6 * DESCRIPTION:
7 * Originally written for BSD4.4 system by Christos Zoulas.
8 * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
9 * Order support hacked in from top-3.5beta6/machine/m_aix41.c
10 *   by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/)
11 *
12 * This is the machine-dependent module for FreeBSD 2.2
13 * Works for:
14 *	FreeBSD 2.2, and probably FreeBSD 2.1.x
15 *
16 * LIBS: -lkvm
17 *
18 * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
19 *          Steven Wallace  <swallace@freebsd.org>
20 *          Wolfram Schneider <wosch@FreeBSD.org>
21 *
22 * $Id: machine.c,v 1.16 1998/11/25 09:45:28 dfr Exp $
23 */
24
25
26#include <sys/types.h>
27#include <sys/signal.h>
28#include <sys/param.h>
29
30#include "os.h"
31#include <stdio.h>
32#include <nlist.h>
33#include <math.h>
34#include <kvm.h>
35#include <pwd.h>
36#include <sys/errno.h>
37#include <sys/sysctl.h>
38#include <sys/dkstat.h>
39#include <sys/file.h>
40#include <sys/time.h>
41#include <sys/proc.h>
42#include <sys/user.h>
43#include <sys/vmmeter.h>
44#include <sys/resource.h>
45#include <sys/rtprio.h>
46
47/* Swap */
48#include <stdlib.h>
49#include <sys/rlist.h>
50#include <sys/conf.h>
51
52#include <osreldate.h> /* for changes in kernel structures */
53
54#include "top.h"
55#include "machine.h"
56
57static int check_nlist __P((struct nlist *));
58static int getkval __P((unsigned long, int *, int, char *));
59extern char* printable __P((char *));
60int swapmode __P((int *retavail, int *retfree));
61static int smpmode;
62static int namelength;
63static int cmdlength;
64
65
66/* get_process_info passes back a handle.  This is what it looks like: */
67
68struct handle
69{
70    struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
71    int remaining;		/* number of pointers remaining */
72};
73
74/* declarations for load_avg */
75#include "loadavg.h"
76
77#define PP(pp, field) ((pp)->kp_proc . field)
78#define EP(pp, field) ((pp)->kp_eproc . field)
79#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
80
81/* define what weighted cpu is.  */
82#define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \
83			 ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu))))
84
85/* what we consider to be process size: */
86#define PROCSIZE(pp) (VP((pp), vm_map.size) / 1024)
87
88/* definitions for indices in the nlist array */
89
90static struct nlist nlst[] = {
91#define X_CCPU		0
92    { "_ccpu" },
93#define X_CP_TIME	1
94    { "_cp_time" },
95#define X_AVENRUN	2
96    { "_averunnable" },
97
98/* Swap */
99#define VM_SWAPLIST	3
100	{ "_swaplist" },/* list of free swap areas */
101#define VM_SWDEVT	4
102	{ "_swdevt" },	/* list of swap devices and sizes */
103#define VM_NSWAP	5
104	{ "_nswap" },	/* size of largest swap device */
105#define VM_NSWDEV	6
106	{ "_nswdev" },	/* number of swap devices */
107#define VM_DMMAX	7
108	{ "_dmmax" },	/* maximum size of a swap block */
109#define X_BUFSPACE	8
110	{ "_bufspace" },	/* K in buffer cache */
111#define X_CNT           9
112    { "_cnt" },		        /* struct vmmeter cnt */
113
114/* Last pid */
115#define X_LASTPID	10
116    { "_nextpid" },
117    { 0 }
118};
119
120/*
121 *  These definitions control the format of the per-process area
122 */
123
124static char smp_header[] =
125  "  PID %-*.*s PRI NICE  SIZE    RES STATE  C   TIME   WCPU    CPU COMMAND";
126
127#define smp_Proc_format \
128	"%5d %-*.*s %3d %3d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s"
129
130static char up_header[] =
131  "  PID %-*.*s PRI NICE  SIZE    RES STATE    TIME   WCPU    CPU COMMAND";
132
133#define up_Proc_format \
134	"%5d %-*.*s %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s"
135
136
137
138/* process state names for the "STATE" column of the display */
139/* the extra nulls in the string "run" are for adding a slash and
140   the processor number when needed */
141
142char *state_abbrev[] =
143{
144    "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB",
145};
146
147
148static kvm_t *kd;
149
150/* values that we stash away in _init and use in later routines */
151
152static double logcpu;
153
154/* these are retrieved from the kernel in _init */
155
156static load_avg  ccpu;
157
158/* these are offsets obtained via nlist and used in the get_ functions */
159
160static unsigned long cp_time_offset;
161static unsigned long avenrun_offset;
162static unsigned long lastpid_offset;
163static long lastpid;
164static unsigned long cnt_offset;
165static unsigned long bufspace_offset;
166static long cnt;
167
168/* these are for calculating cpu state percentages */
169
170static long cp_time[CPUSTATES];
171static long cp_old[CPUSTATES];
172static long cp_diff[CPUSTATES];
173
174/* these are for detailing the process states */
175
176int process_states[6];
177char *procstatenames[] = {
178    "", " starting, ", " running, ", " sleeping, ", " stopped, ",
179    " zombie, ",
180    NULL
181};
182
183/* these are for detailing the cpu states */
184
185int cpu_states[CPUSTATES];
186char *cpustatenames[] = {
187    "user", "nice", "system", "interrupt", "idle", NULL
188};
189
190/* these are for detailing the memory statistics */
191
192int memory_stats[7];
193char *memorynames[] = {
194    "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
195    NULL
196};
197
198int swap_stats[7];
199char *swapnames[] = {
200/*   0           1            2           3            4       5 */
201    "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
202    NULL
203};
204
205
206/* these are for keeping track of the proc array */
207
208static int nproc;
209static int onproc = -1;
210static int pref_len;
211static struct kinfo_proc *pbase;
212static struct kinfo_proc **pref;
213
214/* these are for getting the memory statistics */
215
216static int pageshift;		/* log base 2 of the pagesize */
217
218/* define pagetok in terms of pageshift */
219
220#define pagetok(size) ((size) << pageshift)
221
222/* useful externals */
223long percentages();
224
225#ifdef ORDER
226/* sorting orders. first is default */
227char *ordernames[] = {
228    "cpu", "size", "res", "time", "pri", NULL
229};
230#endif
231
232int
233machine_init(statics)
234
235struct statics *statics;
236
237{
238    register int i = 0;
239    register int pagesize;
240    int modelen;
241    struct passwd *pw;
242
243    modelen = sizeof(smpmode);
244    if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 &&
245         sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) ||
246	modelen != sizeof(smpmode))
247	    smpmode = 0;
248
249    while ((pw = getpwent()) != NULL) {
250	if (strlen(pw->pw_name) > namelength)
251	    namelength = strlen(pw->pw_name);
252    }
253    if (namelength < 8)
254	namelength = 8;
255    if (namelength > 16)
256	namelength = 16;
257
258    if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL)
259	return -1;
260
261
262    /* get the list of symbols we want to access in the kernel */
263    (void) kvm_nlist(kd, nlst);
264    if (nlst[0].n_type == 0)
265    {
266	fprintf(stderr, "top: nlist failed\n");
267	return(-1);
268    }
269
270    /* make sure they were all found */
271    if (i > 0 && check_nlist(nlst) > 0)
272    {
273	return(-1);
274    }
275
276    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),	sizeof(ccpu),
277	    nlst[X_CCPU].n_name);
278
279    /* stash away certain offsets for later use */
280    cp_time_offset = nlst[X_CP_TIME].n_value;
281    avenrun_offset = nlst[X_AVENRUN].n_value;
282    lastpid_offset =  nlst[X_LASTPID].n_value;
283    cnt_offset = nlst[X_CNT].n_value;
284    bufspace_offset = nlst[X_BUFSPACE].n_value;
285
286    /* this is used in calculating WCPU -- calculate it ahead of time */
287    logcpu = log(loaddouble(ccpu));
288
289    pbase = NULL;
290    pref = NULL;
291    nproc = 0;
292    onproc = -1;
293    /* get the page size with "getpagesize" and calculate pageshift from it */
294    pagesize = getpagesize();
295    pageshift = 0;
296    while (pagesize > 1)
297    {
298	pageshift++;
299	pagesize >>= 1;
300    }
301
302    /* we only need the amount of log(2)1024 for our conversion */
303    pageshift -= LOG1024;
304
305    /* fill in the statics information */
306    statics->procstate_names = procstatenames;
307    statics->cpustate_names = cpustatenames;
308    statics->memory_names = memorynames;
309    statics->swap_names = swapnames;
310#ifdef ORDER
311    statics->order_names = ordernames;
312#endif
313
314    /* all done! */
315    return(0);
316}
317
318char *format_header(uname_field)
319
320register char *uname_field;
321
322{
323    register char *ptr;
324    static char Header[128];
325
326    snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header,
327	     namelength, namelength, uname_field);
328
329    cmdlength = 80 - strlen(Header) + 6;
330
331    return Header;
332}
333
334static int swappgsin = -1;
335static int swappgsout = -1;
336extern struct timeval timeout;
337
338void
339get_system_info(si)
340
341struct system_info *si;
342
343{
344    long total;
345    load_avg avenrun[3];
346
347    /* get the cp_time array */
348    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
349		   nlst[X_CP_TIME].n_name);
350    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
351		   nlst[X_AVENRUN].n_name);
352
353    (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid),
354		   "!");
355
356    /* convert load averages to doubles */
357    {
358	register int i;
359	register double *infoloadp;
360	load_avg *avenrunp;
361
362#ifdef notyet
363	struct loadavg sysload;
364	int size;
365	getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
366#endif
367
368	infoloadp = si->load_avg;
369	avenrunp = avenrun;
370	for (i = 0; i < 3; i++)
371	{
372#ifdef notyet
373	    *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
374#endif
375	    *infoloadp++ = loaddouble(*avenrunp++);
376	}
377    }
378
379    /* convert cp_time counts to percentages */
380    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
381
382    /* sum memory & swap statistics */
383    {
384	struct vmmeter sum;
385	static unsigned int swap_delay = 0;
386	static int swapavail = 0;
387	static int swapfree = 0;
388	static int bufspace = 0;
389
390        (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum),
391		   "_cnt");
392        (void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace),
393		   "_bufspace");
394
395	/* convert memory stats to Kbytes */
396	memory_stats[0] = pagetok(sum.v_active_count);
397	memory_stats[1] = pagetok(sum.v_inactive_count);
398	memory_stats[2] = pagetok(sum.v_wire_count);
399	memory_stats[3] = pagetok(sum.v_cache_count);
400	memory_stats[4] = bufspace / 1024;
401	memory_stats[5] = pagetok(sum.v_free_count);
402	memory_stats[6] = -1;
403
404	/* first interval */
405        if (swappgsin < 0) {
406	    swap_stats[4] = 0;
407	    swap_stats[5] = 0;
408	}
409
410	/* compute differences between old and new swap statistic */
411	else {
412	    swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin)));
413	    swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout)));
414	}
415
416        swappgsin = sum.v_swappgsin;
417	swappgsout = sum.v_swappgsout;
418
419	/* call CPU heavy swapmode() only for changes */
420        if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) {
421	    swap_stats[3] = swapmode(&swapavail, &swapfree);
422	    swap_stats[0] = swapavail;
423	    swap_stats[1] = swapavail - swapfree;
424	    swap_stats[2] = swapfree;
425	}
426        swap_delay = 1;
427	swap_stats[6] = -1;
428    }
429
430    /* set arrays and strings */
431    si->cpustates = cpu_states;
432    si->memory = memory_stats;
433    si->swap = swap_stats;
434
435
436    if(lastpid > 0) {
437	si->last_pid = lastpid;
438    } else {
439	si->last_pid = -1;
440    }
441}
442
443static struct handle handle;
444
445caddr_t get_process_info(si, sel, compare)
446
447struct system_info *si;
448struct process_select *sel;
449int (*compare)();
450
451{
452    register int i;
453    register int total_procs;
454    register int active_procs;
455    register struct kinfo_proc **prefp;
456    register struct kinfo_proc *pp;
457
458    /* these are copied out of sel for speed */
459    int show_idle;
460    int show_self;
461    int show_system;
462    int show_uid;
463    int show_command;
464
465
466    pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc);
467    if (nproc > onproc)
468	pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
469		* (onproc = nproc));
470    if (pref == NULL || pbase == NULL) {
471	(void) fprintf(stderr, "top: Out of memory.\n");
472	quit(23);
473    }
474    /* get a pointer to the states summary array */
475    si->procstates = process_states;
476
477    /* set up flags which define what we are going to select */
478    show_idle = sel->idle;
479    show_self = sel->self;
480    show_system = sel->system;
481    show_uid = sel->uid != -1;
482    show_command = sel->command != NULL;
483
484    /* count up process states and get pointers to interesting procs */
485    total_procs = 0;
486    active_procs = 0;
487    memset((char *)process_states, 0, sizeof(process_states));
488    prefp = pref;
489    for (pp = pbase, i = 0; i < nproc; pp++, i++)
490    {
491	/*
492	 *  Place pointers to each valid proc structure in pref[].
493	 *  Process slots that are actually in use have a non-zero
494	 *  status field.  Processes with P_SYSTEM set are system
495	 *  processes---these get ignored unless show_sysprocs is set.
496	 */
497	if (PP(pp, p_stat) != 0 &&
498	    (show_self != PP(pp, p_pid)) &&
499	    (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
500	{
501	    total_procs++;
502	    process_states[(unsigned char) PP(pp, p_stat)]++;
503	    if ((PP(pp, p_stat) != SZOMB) &&
504		(show_idle || (PP(pp, p_pctcpu) != 0) ||
505		 (PP(pp, p_stat) == SRUN)) &&
506		(!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
507	    {
508		*prefp++ = pp;
509		active_procs++;
510	    }
511	}
512    }
513
514    /* if requested, sort the "interesting" processes */
515    if (compare != NULL)
516    {
517	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
518    }
519
520    /* remember active and total counts */
521    si->p_total = total_procs;
522    si->p_active = pref_len = active_procs;
523
524    /* pass back a handle */
525    handle.next_proc = pref;
526    handle.remaining = active_procs;
527    return((caddr_t)&handle);
528}
529
530char fmt[128];		/* static area where result is built */
531
532char *format_next_process(handle, get_userid)
533
534caddr_t handle;
535char *(*get_userid)();
536
537{
538    register struct kinfo_proc *pp;
539    register long cputime;
540    register double pct;
541    struct handle *hp;
542    char status[16];
543
544    /* find and remember the next proc structure */
545    hp = (struct handle *)handle;
546    pp = *(hp->next_proc++);
547    hp->remaining--;
548
549
550    /* get the process's user struct and set cputime */
551    if ((PP(pp, p_flag) & P_INMEM) == 0) {
552	/*
553	 * Print swapped processes as <pname>
554	 */
555	char *comm = PP(pp, p_comm);
556#define COMSIZ sizeof(PP(pp, p_comm))
557	char buf[COMSIZ];
558	(void) strncpy(buf, comm, COMSIZ);
559	comm[0] = '<';
560	(void) strncpy(&comm[1], buf, COMSIZ - 2);
561	comm[COMSIZ - 2] = '\0';
562	(void) strncat(comm, ">", COMSIZ - 1);
563	comm[COMSIZ - 1] = '\0';
564    }
565
566#if 0
567    /* This does not produce the correct results */
568    cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks);
569#endif
570    /* This does not count interrupts */
571    cputime = (PP(pp, p_runtime) / 1000 + 500) / 1000;
572
573    /* calculate the base for cpu percentages */
574    pct = pctdouble(PP(pp, p_pctcpu));
575
576    /* generate "STATE" field */
577    switch (PP(pp, p_stat)) {
578	case SRUN:
579	    if (smpmode && PP(pp, p_oncpu) >= 0)
580		sprintf(status, "CPU%d", PP(pp, p_oncpu));
581	    else
582		strcpy(status, "RUN");
583	    break;
584	case SSLEEP:
585	    if (PP(pp, p_wmesg) != NULL) {
586		sprintf(status, "%.6s", EP(pp, e_wmesg));
587		break;
588	    }
589	    /* fall through */
590	default:
591	    sprintf(status, "%.6s", state_abbrev[(unsigned char) PP(pp, p_stat)]);
592	    break;
593    }
594
595    /* format this entry */
596    sprintf(fmt,
597	    smpmode ? smp_Proc_format : up_Proc_format,
598	    PP(pp, p_pid),
599	    namelength, namelength,
600	    (*get_userid)(EP(pp, e_pcred.p_ruid)),
601	    PP(pp, p_priority) - PZERO,
602
603	    /*
604	     * normal time      -> nice value -20 - +20
605	     * real time 0 - 31 -> nice value -52 - -21
606	     * idle time 0 - 31 -> nice value +21 - +52
607	     */
608	    (PP(pp, p_rtprio.type) ==  RTP_PRIO_NORMAL ?
609	    	PP(pp, p_nice) - NZERO :
610	    	(PP(pp, p_rtprio.type) ==  RTP_PRIO_REALTIME ?
611		    (PRIO_MIN - 1 - RTP_PRIO_MAX + PP(pp, p_rtprio.prio)) :
612		    (PRIO_MAX + 1 + PP(pp, p_rtprio.prio)))),
613	    format_k2(PROCSIZE(pp)),
614	    format_k2(pagetok(VP(pp, vm_rssize))),
615	    status,
616	    smpmode ? PP(pp, p_lastcpu) : 0,
617	    format_time(cputime),
618	    100.0 * weighted_cpu(pct, pp),
619	    100.0 * pct,
620	    cmdlength,
621	    printable(PP(pp, p_comm)));
622
623    /* return the result */
624    return(fmt);
625}
626
627
628/*
629 * check_nlist(nlst) - checks the nlist to see if any symbols were not
630 *		found.  For every symbol that was not found, a one-line
631 *		message is printed to stderr.  The routine returns the
632 *		number of symbols NOT found.
633 */
634
635static int check_nlist(nlst)
636
637register struct nlist *nlst;
638
639{
640    register int i;
641
642    /* check to see if we got ALL the symbols we requested */
643    /* this will write one line to stderr for every symbol not found */
644
645    i = 0;
646    while (nlst->n_name != NULL)
647    {
648	if (nlst->n_type == 0)
649	{
650	    /* this one wasn't found */
651	    (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
652			   nlst->n_name);
653	    i = 1;
654	}
655	nlst++;
656    }
657
658    return(i);
659}
660
661
662/*
663 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
664 *	"offset" is the byte offset into the kernel for the desired value,
665 *  	"ptr" points to a buffer into which the value is retrieved,
666 *  	"size" is the size of the buffer (and the object to retrieve),
667 *  	"refstr" is a reference string used when printing error meessages,
668 *	    if "refstr" starts with a '!', then a failure on read will not
669 *  	    be fatal (this may seem like a silly way to do things, but I
670 *  	    really didn't want the overhead of another argument).
671 *
672 */
673
674static int getkval(offset, ptr, size, refstr)
675
676unsigned long offset;
677int *ptr;
678int size;
679char *refstr;
680
681{
682    if (kvm_read(kd, offset, (char *) ptr, size) != size)
683    {
684	if (*refstr == '!')
685	{
686	    return(0);
687	}
688	else
689	{
690	    fprintf(stderr, "top: kvm_read for %s: %s\n",
691		refstr, strerror(errno));
692	    quit(23);
693	}
694    }
695    return(1);
696}
697
698/* comparison routines for qsort */
699
700/*
701 *  proc_compare - comparison function for "qsort"
702 *	Compares the resource consumption of two processes using five
703 *  	distinct keys.  The keys (in descending order of importance) are:
704 *  	percent cpu, cpu ticks, state, resident set size, total virtual
705 *  	memory usage.  The process states are ordered as follows (from least
706 *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
707 *  	array declaration below maps a process state index into a number
708 *  	that reflects this ordering.
709 */
710
711static unsigned char sorted_state[] =
712{
713    0,	/* not used		*/
714    3,	/* sleep		*/
715    1,	/* ABANDONED (WAIT)	*/
716    6,	/* run			*/
717    5,	/* start		*/
718    2,	/* zombie		*/
719    4	/* stop			*/
720};
721
722
723#define ORDERKEY_PCTCPU \
724  if (lresult = (long) PP(p2, p_pctcpu) - (long) PP(p1, p_pctcpu), \
725     (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
726
727#define ORDERKEY_CPTICKS \
728  if ((result = PP(p2, p_runtime) - PP(p1, p_runtime)) == 0)
729
730#define ORDERKEY_STATE \
731  if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \
732                sorted_state[(unsigned char) PP(p1, p_stat)]) == 0)
733
734#define ORDERKEY_PRIO \
735  if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
736
737#define ORDERKEY_RSSIZE \
738  if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
739
740#define ORDERKEY_MEM \
741  if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
742
743/* compare_cpu - the comparison function for sorting by cpu percentage */
744
745int
746#ifdef ORDER
747compare_cpu(pp1, pp2)
748#else
749proc_compare(pp1, pp2)
750#endif
751
752struct proc **pp1;
753struct proc **pp2;
754
755{
756    register struct kinfo_proc *p1;
757    register struct kinfo_proc *p2;
758    register int result;
759    register pctcpu lresult;
760
761    /* remove one level of indirection */
762    p1 = *(struct kinfo_proc **) pp1;
763    p2 = *(struct kinfo_proc **) pp2;
764
765    ORDERKEY_PCTCPU
766    ORDERKEY_CPTICKS
767    ORDERKEY_STATE
768    ORDERKEY_PRIO
769    ORDERKEY_RSSIZE
770    ORDERKEY_MEM
771    ;
772
773    return(result);
774}
775
776#ifdef ORDER
777/* compare routines */
778int compare_size(), compare_res(), compare_time(), compare_prio();
779
780int (*proc_compares[])() = {
781    compare_cpu,
782    compare_size,
783    compare_res,
784    compare_time,
785    compare_prio,
786    NULL
787};
788
789/* compare_size - the comparison function for sorting by total memory usage */
790
791int
792compare_size(pp1, pp2)
793
794struct proc **pp1;
795struct proc **pp2;
796
797{
798    register struct kinfo_proc *p1;
799    register struct kinfo_proc *p2;
800    register int result;
801    register pctcpu lresult;
802
803    /* remove one level of indirection */
804    p1 = *(struct kinfo_proc **) pp1;
805    p2 = *(struct kinfo_proc **) pp2;
806
807    ORDERKEY_MEM
808    ORDERKEY_RSSIZE
809    ORDERKEY_PCTCPU
810    ORDERKEY_CPTICKS
811    ORDERKEY_STATE
812    ORDERKEY_PRIO
813    ;
814
815    return(result);
816}
817
818/* compare_res - the comparison function for sorting by resident set size */
819
820int
821compare_res(pp1, pp2)
822
823struct proc **pp1;
824struct proc **pp2;
825
826{
827    register struct kinfo_proc *p1;
828    register struct kinfo_proc *p2;
829    register int result;
830    register pctcpu lresult;
831
832    /* remove one level of indirection */
833    p1 = *(struct kinfo_proc **) pp1;
834    p2 = *(struct kinfo_proc **) pp2;
835
836    ORDERKEY_RSSIZE
837    ORDERKEY_MEM
838    ORDERKEY_PCTCPU
839    ORDERKEY_CPTICKS
840    ORDERKEY_STATE
841    ORDERKEY_PRIO
842    ;
843
844    return(result);
845}
846
847/* compare_time - the comparison function for sorting by total cpu time */
848
849int
850compare_time(pp1, pp2)
851
852struct proc **pp1;
853struct proc **pp2;
854
855{
856    register struct kinfo_proc *p1;
857    register struct kinfo_proc *p2;
858    register int result;
859    register pctcpu lresult;
860
861    /* remove one level of indirection */
862    p1 = *(struct kinfo_proc **) pp1;
863    p2 = *(struct kinfo_proc **) pp2;
864
865    ORDERKEY_CPTICKS
866    ORDERKEY_PCTCPU
867    ORDERKEY_STATE
868    ORDERKEY_PRIO
869    ORDERKEY_RSSIZE
870    ORDERKEY_MEM
871    ;
872
873      return(result);
874  }
875
876/* compare_prio - the comparison function for sorting by cpu percentage */
877
878int
879compare_prio(pp1, pp2)
880
881struct proc **pp1;
882struct proc **pp2;
883
884{
885    register struct kinfo_proc *p1;
886    register struct kinfo_proc *p2;
887    register int result;
888    register pctcpu lresult;
889
890    /* remove one level of indirection */
891    p1 = *(struct kinfo_proc **) pp1;
892    p2 = *(struct kinfo_proc **) pp2;
893
894    ORDERKEY_PRIO
895    ORDERKEY_CPTICKS
896    ORDERKEY_PCTCPU
897    ORDERKEY_STATE
898    ORDERKEY_RSSIZE
899    ORDERKEY_MEM
900    ;
901
902    return(result);
903}
904#endif
905
906/*
907 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
908 *		the process does not exist.
909 *		It is EXTREMLY IMPORTANT that this function work correctly.
910 *		If top runs setuid root (as in SVR4), then this function
911 *		is the only thing that stands in the way of a serious
912 *		security problem.  It validates requests for the "kill"
913 *		and "renice" commands.
914 */
915
916int proc_owner(pid)
917
918int pid;
919
920{
921    register int cnt;
922    register struct kinfo_proc **prefp;
923    register struct kinfo_proc *pp;
924
925    prefp = pref;
926    cnt = pref_len;
927    while (--cnt >= 0)
928    {
929	pp = *prefp++;
930	if (PP(pp, p_pid) == (pid_t)pid)
931	{
932	    return((int)EP(pp, e_pcred.p_ruid));
933	}
934    }
935    return(-1);
936}
937
938
939/*
940 * swapmode is based on a program called swapinfo written
941 * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
942 */
943
944#define	SVAR(var) __STRING(var)	/* to force expansion */
945#define	KGET(idx, var)							\
946	KGET1(idx, &var, sizeof(var), SVAR(var))
947#define	KGET1(idx, p, s, msg)						\
948	KGET2(nlst[idx].n_value, p, s, msg)
949#define	KGET2(addr, p, s, msg)						\
950	if (kvm_read(kd, (u_long)(addr), p, s) != s) {		        \
951		warnx("cannot read %s: %s", msg, kvm_geterr(kd));       \
952		return (0);                                             \
953       }
954#define	KGETRET(addr, p, s, msg)					\
955	if (kvm_read(kd, (u_long)(addr), p, s) != s) {			\
956		warnx("cannot read %s: %s", msg, kvm_geterr(kd));	\
957		return (0);						\
958	}
959
960
961int
962swapmode(retavail, retfree)
963	int *retavail;
964	int *retfree;
965{
966	char *header;
967	int hlen, nswap, nswdev, dmmax;
968	int i, div, avail, nfree, npfree, used;
969	struct swdevt *sw;
970	long blocksize, *perdev;
971	u_long ptr;
972	struct rlist head;
973#if __FreeBSD_version >= 220000
974	struct rlisthdr swaplist;
975#else
976	struct rlist *swaplist;
977#endif
978	struct rlist *swapptr;
979
980	/*
981	 * Counter for error messages. If we reach the limit,
982	 * stop reading information from swap devices and
983	 * return zero. This prevent endless 'bad address'
984	 * messages.
985	 */
986	static warning = 10;
987
988	if (warning <= 0) {
989	    /* a single warning */
990	    if (!warning) {
991		warning--;
992		fprintf(stderr,
993			"Too much errors, stop reading swap devices ...\n");
994		(void)sleep(3);
995	    }
996	    return(0);
997	}
998	warning--; /* decrease counter, see end of function */
999
1000	KGET(VM_NSWAP, nswap);
1001	if (!nswap) {
1002		fprintf(stderr, "No swap space available\n");
1003		return(0);
1004	}
1005
1006	KGET(VM_NSWDEV, nswdev);
1007	KGET(VM_DMMAX, dmmax);
1008	KGET1(VM_SWAPLIST, &swaplist, sizeof(swaplist), "swaplist");
1009	if ((sw = (struct swdevt *)malloc(nswdev * sizeof(*sw))) == NULL ||
1010	    (perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
1011		err(1, "malloc");
1012	KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
1013	KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
1014
1015	/* Count up swap space. */
1016	nfree = 0;
1017	memset(perdev, 0, nswdev * sizeof(*perdev));
1018#if  __FreeBSD_version >= 220000
1019	swapptr = swaplist.rlh_list;
1020	while (swapptr) {
1021#else
1022	while (swaplist) {
1023#endif
1024		int	top, bottom, next_block;
1025#if  __FreeBSD_version >= 220000
1026		KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
1027#else
1028		KGET2(swaplist, &head, sizeof(struct rlist), "swaplist");
1029#endif
1030
1031		top = head.rl_end;
1032		bottom = head.rl_start;
1033
1034		nfree += top - bottom + 1;
1035
1036		/*
1037		 * Swap space is split up among the configured disks.
1038		 *
1039		 * For interleaved swap devices, the first dmmax blocks
1040		 * of swap space some from the first disk, the next dmmax
1041		 * blocks from the next, and so on up to nswap blocks.
1042		 *
1043		 * The list of free space joins adjacent free blocks,
1044		 * ignoring device boundries.  If we want to keep track
1045		 * of this information per device, we'll just have to
1046		 * extract it ourselves.
1047		 */
1048		while (top / dmmax != bottom / dmmax) {
1049			next_block = ((bottom + dmmax) / dmmax);
1050			perdev[(bottom / dmmax) % nswdev] +=
1051				next_block * dmmax - bottom;
1052			bottom = next_block * dmmax;
1053		}
1054		perdev[(bottom / dmmax) % nswdev] +=
1055			top - bottom + 1;
1056
1057#if  __FreeBSD_version >= 220000
1058		swapptr = head.rl_next;
1059#else
1060		swaplist = head.rl_next;
1061#endif
1062	}
1063
1064	header = getbsize(&hlen, &blocksize);
1065	div = blocksize / 512;
1066	avail = npfree = 0;
1067	for (i = 0; i < nswdev; i++) {
1068		int xsize, xfree;
1069
1070		/*
1071		 * Don't report statistics for partitions which have not
1072		 * yet been activated via swapon(8).
1073		 */
1074		if (!(sw[i].sw_flags & SW_FREED))
1075			continue;
1076
1077		/* The first dmmax is never allocated to avoid trashing of
1078		 * disklabels
1079		 */
1080		xsize = sw[i].sw_nblks - dmmax;
1081		xfree = perdev[i];
1082		used = xsize - xfree;
1083		npfree++;
1084		avail += xsize;
1085	}
1086
1087	/*
1088	 * If only one partition has been set up via swapon(8), we don't
1089	 * need to bother with totals.
1090	 */
1091	*retavail = avail / 2;
1092	*retfree = nfree / 2;
1093	used = avail - nfree;
1094	free(sw); free(perdev);
1095
1096	/* increase counter, no errors occurs */
1097	warning++;
1098
1099	return  (int)(((double)used / (double)avail * 100.0) + 0.5);
1100}
1101