machine.c revision 1.19
1/*	$OpenBSD: machine.c,v 1.19 2000/06/18 17:59:56 niklas Exp $	*/
2
3/*
4 * top - a top users display for Unix
5 *
6 * SYNOPSIS:  For an OpenBSD system
7 *
8 * DESCRIPTION:
9 * This is the machine-dependent module for OpenBSD
10 * Tested on:
11 *	i386
12 *
13 * LIBS: -lkvm
14 *
15 * TERMCAP: -ltermlib
16 *
17 * CFLAGS: -DHAVE_GETOPT -DORDER
18 *
19 * AUTHOR:  Thorsten Lockert <tholo@sigmasoft.com>
20 *          Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu>
21 *          Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no>
22 *	    Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com>
23 *	    Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org>
24 */
25
26#include <sys/types.h>
27#include <sys/signal.h>
28#include <sys/param.h>
29
30#define DOSWAP
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <limits.h>
36#include <err.h>
37#include <nlist.h>
38#include <math.h>
39#include <kvm.h>
40#include <unistd.h>
41#include <sys/errno.h>
42#include <sys/sysctl.h>
43#include <sys/dir.h>
44#include <sys/dkstat.h>
45#include <sys/file.h>
46#include <sys/time.h>
47#include <sys/resource.h>
48
49#ifdef DOSWAP
50#include <sys/swap.h>
51#include <err.h>
52#endif
53
54static int check_nlist __P((struct nlist *));
55static int getkval __P((unsigned long, int *, int, char *));
56static int swapmode __P((int *, int *));
57
58#include "top.h"
59#include "display.h"
60#include "machine.h"
61#include "utils.h"
62
63/* get_process_info passes back a handle.  This is what it looks like: */
64
65struct handle
66{
67    struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
68    int remaining;		/* number of pointers remaining */
69};
70
71/* declarations for load_avg */
72#include "loadavg.h"
73
74#define PP(pp, field) ((pp)->kp_proc . field)
75#define EP(pp, field) ((pp)->kp_eproc . field)
76#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
77
78/* what we consider to be process size: */
79#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
80
81/* definitions for indices in the nlist array */
82#define X_CP_TIME	0
83
84static struct nlist nlst[] = {
85    { "_cp_time" },		/* 0 */
86    { 0 }
87};
88
89/*
90 *  These definitions control the format of the per-process area
91 */
92
93static char header[] =
94  "  PID X        PRI NICE  SIZE   RES STATE WAIT     TIME    CPU COMMAND";
95/* 0123456   -- field to fill in starts at header+6 */
96#define UNAME_START 6
97
98#define Proc_format \
99	"%5d %-8.8s %3d %4d %5s %5s %-5s %-6.6s %6s %5.2f%% %.14s"
100
101
102/* process state names for the "STATE" column of the display */
103/* the extra nulls in the string "run" are for adding a slash and
104   the processor number when needed */
105
106char *state_abbrev[] =
107{
108    "", "start", "run\0\0\0", "sleep", "stop", "zomb",
109};
110
111
112static kvm_t *kd;
113
114/* these are retrieved from the kernel in _init */
115
116static          int stathz;
117
118/* these are offsets obtained via nlist and used in the get_ functions */
119
120static unsigned long cp_time_offset;
121
122/* these are for calculating cpu state percentages */
123static long cp_time[CPUSTATES];
124static long cp_old[CPUSTATES];
125static long cp_diff[CPUSTATES];
126
127/* these are for detailing the process states */
128
129int process_states[7];
130char *procstatenames[] = {
131    "", " starting, ", " running, ", " idle, ", " stopped, ", " zombie, ",
132    NULL
133};
134
135/* these are for detailing the cpu states */
136
137int cpu_states[CPUSTATES];
138char *cpustatenames[] = {
139    "user", "nice", "system", "interrupt", "idle", NULL
140};
141
142/* these are for detailing the memory statistics */
143
144int memory_stats[8];
145char *memorynames[] = {
146    "Real: ", "K/", "K act/tot  ", "Free: ", "K  ",
147#ifdef DOSWAP
148    "Swap: ", "K/", "K used/tot",
149#endif
150    NULL
151};
152
153#ifdef ORDER
154/* these are names given to allowed sorting orders -- first is default */
155
156char *ordernames[] = {"cpu", "size", "res", "time", "pri", NULL};
157#endif
158
159/* these are for keeping track of the proc array */
160
161static int nproc;
162static int onproc = -1;
163static int pref_len;
164static struct kinfo_proc *pbase;
165static struct kinfo_proc **pref;
166
167/* these are for getting the memory statistics */
168
169static int pageshift;		/* log base 2 of the pagesize */
170
171/* define pagetok in terms of pageshift */
172
173#define pagetok(size) ((size) << pageshift)
174
175int
176getstathz()
177{
178	int mib[2];
179	struct clockinfo cinf;
180	size_t size = sizeof(cinf);
181
182	mib[0] = CTL_KERN;
183	mib[1] = KERN_CLOCKRATE;
184	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
185		return (-1);
186	return (cinf.stathz);
187}
188
189int
190machine_init(statics)
191struct statics *statics;
192{
193    register int i = 0;
194    register int pagesize;
195    char errbuf[_POSIX2_LINE_MAX];
196
197    if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
198	warnx("%s", errbuf);
199	return(-1);
200    }
201
202    setegid(getgid());
203    setgid(getgid());
204
205    /* get the list of symbols we want to access in the kernel */
206    if (kvm_nlist(kd, nlst) < 0) {
207	warnx("nlist failed");
208	return(-1);
209    }
210
211    /* make sure they were all found */
212    if (i > 0 && check_nlist(nlst) > 0)
213	return(-1);
214
215    stathz = getstathz();
216    if (stathz == -1)
217	return(-1);
218
219    /* stash away certain offsets for later use */
220    cp_time_offset = nlst[X_CP_TIME].n_value;
221
222    pbase = NULL;
223    pref = NULL;
224    onproc = -1;
225    nproc = 0;
226
227    /* get the page size with "getpagesize" and calculate pageshift from it */
228    pagesize = getpagesize();
229    pageshift = 0;
230    while (pagesize > 1)
231    {
232	pageshift++;
233	pagesize >>= 1;
234    }
235
236    /* we only need the amount of log(2)1024 for our conversion */
237    pageshift -= LOG1024;
238
239    /* fill in the statics information */
240    statics->procstate_names = procstatenames;
241    statics->cpustate_names = cpustatenames;
242    statics->memory_names = memorynames;
243#ifdef ORDER
244    statics->order_names = ordernames;
245#endif
246
247    /* all done! */
248    return(0);
249}
250
251char *format_header(uname_field)
252
253register char *uname_field;
254
255{
256    register char *ptr;
257
258    ptr = header + UNAME_START;
259    while (*uname_field != '\0')
260    {
261	*ptr++ = *uname_field++;
262    }
263
264    return(header);
265}
266
267void
268get_system_info(si)
269
270struct system_info *si;
271
272{
273    int total;
274
275    /* get the cp_time array */
276    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
277		   "_cp_time");
278
279    /* convert load averages to doubles */
280    {
281	register int i;
282	register double *infoloadp;
283	struct loadavg sysload;
284	size_t size = sizeof(sysload);
285	static int mib[] = { CTL_VM, VM_LOADAVG };
286
287	if (sysctl(mib, 2, &sysload, &size, NULL, 0) < 0) {
288	    warn("sysctl failed");
289	    bzero(&total, sizeof(total));
290	}
291
292	infoloadp = si->load_avg;
293	for (i = 0; i < 3; i++)
294	    *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
295    }
296
297    /* convert cp_time counts to percentages */
298    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
299
300    /* sum memory statistics */
301    {
302	struct vmtotal total;
303	size_t size = sizeof(total);
304	static int mib[] = { CTL_VM, VM_METER };
305
306	/* get total -- systemwide main memory usage structure */
307	if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
308	    warn("sysctl failed");
309	    bzero(&total, sizeof(total));
310	}
311	/* convert memory stats to Kbytes */
312	memory_stats[0] = -1;
313	memory_stats[1] = pagetok(total.t_arm);
314	memory_stats[2] = pagetok(total.t_rm);
315	memory_stats[3] = -1;
316	memory_stats[4] = pagetok(total.t_free);
317	memory_stats[5] = -1;
318#ifdef DOSWAP
319	if (!swapmode(&memory_stats[6], &memory_stats[7])) {
320	    memory_stats[6] = 0;
321	    memory_stats[7] = 0;
322	}
323#endif
324    }
325
326    /* set arrays and strings */
327    si->cpustates = cpu_states;
328    si->memory = memory_stats;
329    si->last_pid = -1;
330}
331
332static struct handle handle;
333
334caddr_t get_process_info(si, sel, compare)
335
336struct system_info *si;
337struct process_select *sel;
338int (*compare) __P((const void *, const void *));
339
340{
341    register int i;
342    register int total_procs;
343    register int active_procs;
344    register struct kinfo_proc **prefp;
345    register struct kinfo_proc *pp;
346
347    /* these are copied out of sel for speed */
348    int show_idle;
349    int show_system;
350    int show_uid;
351    int show_command;
352
353
354    if ((pbase = kvm_getprocs(kd, KERN_PROC_KTHREAD, 0, &nproc)) == NULL) {
355	warnx("%s", kvm_geterr(kd));
356	quit(23);
357    }
358    if (nproc > onproc)
359	pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
360		* (onproc = nproc));
361    if (pref == NULL) {
362	warnx("Out of memory.");
363	quit(23);
364    }
365    /* get a pointer to the states summary array */
366    si->procstates = process_states;
367
368    /* set up flags which define what we are going to select */
369    show_idle = sel->idle;
370    show_system = sel->system;
371    show_uid = sel->uid != -1;
372    show_command = sel->command != NULL;
373
374    /* count up process states and get pointers to interesting procs */
375    total_procs = 0;
376    active_procs = 0;
377    memset((char *)process_states, 0, sizeof(process_states));
378    prefp = pref;
379    for (pp = pbase, i = 0; i < nproc; pp++, i++)
380    {
381	/*
382	 *  Place pointers to each valid proc structure in pref[].
383	 *  Process slots that are actually in use have a non-zero
384	 *  status field.  Processes with SSYS set are system
385	 *  processes---these get ignored unless show_sysprocs is set.
386	 */
387	if (PP(pp, p_stat) != 0 &&
388	    (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
389	{
390	    total_procs++;
391	    process_states[(unsigned char) PP(pp, p_stat)]++;
392	    if ((PP(pp, p_stat) != SZOMB) &&
393		(show_idle || (PP(pp, p_pctcpu) != 0) ||
394		 (PP(pp, p_stat) == SRUN)) &&
395		(!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
396	    {
397		*prefp++ = pp;
398		active_procs++;
399	    }
400	}
401    }
402
403    /* if requested, sort the "interesting" processes */
404    if (compare != NULL)
405    {
406	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
407    }
408
409    /* remember active and total counts */
410    si->p_total = total_procs;
411    si->p_active = pref_len = active_procs;
412
413    /* pass back a handle */
414    handle.next_proc = pref;
415    handle.remaining = active_procs;
416    return((caddr_t)&handle);
417}
418
419char fmt[MAX_COLS];		/* static area where result is built */
420
421char *format_next_process(handle, get_userid)
422
423caddr_t handle;
424char *(*get_userid)();
425
426{
427    register struct kinfo_proc *pp;
428    register int cputime;
429    register double pct;
430    struct handle *hp;
431    char waddr[sizeof(void *) * 2 + 3];	/* Hexify void pointer */
432    char *p_wait;
433
434    /* find and remember the next proc structure */
435    hp = (struct handle *)handle;
436    pp = *(hp->next_proc++);
437    hp->remaining--;
438
439
440    /* get the process's user struct and set cputime */
441    if ((PP(pp, p_flag) & P_INMEM) == 0) {
442	/*
443	 * Print swapped processes as <pname>
444	 */
445	char *comm = PP(pp, p_comm);
446#define COMSIZ sizeof(PP(pp, p_comm))
447	char buf[COMSIZ];
448	(void) strncpy(buf, comm, COMSIZ);
449	comm[0] = '<';
450	(void) strncpy(&comm[1], buf, COMSIZ - 2);
451	comm[COMSIZ - 2] = '\0';
452	(void) strncat(comm, ">", COMSIZ - 1);
453	comm[COMSIZ - 1] = '\0';
454    }
455
456    cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz;
457
458    /* calculate the base for cpu percentages */
459    pct = pctdouble(PP(pp, p_pctcpu));
460
461    if (PP(pp, p_wchan))
462        if (PP(pp, p_wmesg))
463	    p_wait = EP(pp, e_wmesg);
464	else {
465	    snprintf(waddr, sizeof(waddr), "%lx",
466		(unsigned long)(PP(pp, p_wchan)) & ~KERNBASE);
467	    p_wait = waddr;
468        }
469    else
470	p_wait = "-";
471
472    /* format this entry */
473    snprintf(fmt, MAX_COLS,
474	    Proc_format,
475	    PP(pp, p_pid),
476	    (*get_userid)(EP(pp, e_pcred.p_ruid)),
477	    PP(pp, p_priority) - PZERO,
478	    PP(pp, p_nice) - NZERO,
479	    format_k(pagetok(PROCSIZE(pp))),
480	    format_k(pagetok(VP(pp, vm_rssize))),
481	    (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > MAXSLP)
482	     ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)],
483	    p_wait,
484	    format_time(cputime),
485	    100.0 * pct,
486	    printable(PP(pp, p_comm)));
487
488    /* return the result */
489    return(fmt);
490}
491
492
493/*
494 * check_nlist(nlst) - checks the nlist to see if any symbols were not
495 *		found.  For every symbol that was not found, a one-line
496 *		message is printed to stderr.  The routine returns the
497 *		number of symbols NOT found.
498 */
499
500static int check_nlist(nlst)
501
502register struct nlist *nlst;
503
504{
505    register int i;
506
507    /* check to see if we got ALL the symbols we requested */
508    /* this will write one line to stderr for every symbol not found */
509
510    i = 0;
511    while (nlst->n_name != NULL)
512    {
513	if (nlst->n_type == 0)
514	{
515	    /* this one wasn't found */
516	    (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
517			   nlst->n_name);
518	    i = 1;
519	}
520	nlst++;
521    }
522
523    return(i);
524}
525
526
527/*
528 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
529 *	"offset" is the byte offset into the kernel for the desired value,
530 *  	"ptr" points to a buffer into which the value is retrieved,
531 *  	"size" is the size of the buffer (and the object to retrieve),
532 *  	"refstr" is a reference string used when printing error meessages,
533 *	    if "refstr" starts with a '!', then a failure on read will not
534 *  	    be fatal (this may seem like a silly way to do things, but I
535 *  	    really didn't want the overhead of another argument).
536 *
537 */
538
539static int getkval(offset, ptr, size, refstr)
540
541unsigned long offset;
542int *ptr;
543int size;
544char *refstr;
545
546{
547    if (kvm_read(kd, offset, ptr, size) != size)
548    {
549	if (*refstr == '!')
550	{
551	    return(0);
552	}
553	else
554	{
555	    warn("kvm_read for %s", refstr);
556	    quit(23);
557	}
558    }
559    return(1);
560}
561
562/* comparison routine for qsort */
563
564static unsigned char sorted_state[] =
565{
566    0,	/* not used		*/
567    4,	/* start		*/
568    5,	/* run			*/
569    2,	/* sleep		*/
570    3,	/* stop			*/
571    1	/* zombie		*/
572};
573
574#ifdef ORDER
575
576/*
577 *  proc_compares - comparison functions for "qsort"
578 */
579
580/*
581 * First, the possible comparison keys.  These are defined in such a way
582 * that they can be merely listed in the source code to define the actual
583 * desired ordering.
584 */
585
586
587#define ORDERKEY_PCTCPU \
588	if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \
589           (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
590#define ORDERKEY_CPUTIME \
591	if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \
592		if ((result = PP(p2, p_rtime.tv_usec) - \
593		     PP(p1, p_rtime.tv_usec)) == 0)
594#define ORDERKEY_STATE \
595	if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \
596                      sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
597#define ORDERKEY_PRIO \
598	if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
599#define ORDERKEY_RSSIZE \
600	if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
601#define ORDERKEY_MEM \
602	if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
603
604
605/* compare_cpu - the comparison function for sorting by cpu percentage */
606
607int
608compare_cpu(v1, v2)
609
610const void *v1, *v2;
611
612{
613    register struct proc **pp1 = (struct proc **)v1;
614    register struct proc **pp2 = (struct proc **)v2;
615    register struct kinfo_proc *p1;
616    register struct kinfo_proc *p2;
617    register int result;
618    register pctcpu lresult;
619
620    /* remove one level of indirection */
621    p1 = *(struct kinfo_proc **) pp1;
622    p2 = *(struct kinfo_proc **) pp2;
623
624    ORDERKEY_PCTCPU
625    ORDERKEY_CPUTIME
626    ORDERKEY_STATE
627    ORDERKEY_PRIO
628    ORDERKEY_RSSIZE
629    ORDERKEY_MEM
630    ;
631    return(result);
632}
633
634/* compare_size - the comparison function for sorting by total memory usage */
635
636int
637compare_size(v1, v2)
638
639const void *v1, *v2;
640
641{
642    register struct proc **pp1 = (struct proc **)v1;
643    register struct proc **pp2 = (struct proc **)v2;
644    register struct kinfo_proc *p1;
645    register struct kinfo_proc *p2;
646    register int result;
647    register pctcpu lresult;
648
649    /* remove one level of indirection */
650    p1 = *(struct kinfo_proc **) pp1;
651    p2 = *(struct kinfo_proc **) pp2;
652
653    ORDERKEY_MEM
654    ORDERKEY_RSSIZE
655    ORDERKEY_PCTCPU
656    ORDERKEY_CPUTIME
657    ORDERKEY_STATE
658    ORDERKEY_PRIO
659    ;
660
661    return(result);
662}
663
664/* compare_res - the comparison function for sorting by resident set size */
665
666int
667compare_res(v1, v2)
668
669const void *v1, *v2;
670
671{
672    register struct proc **pp1 = (struct proc **)v1;
673    register struct proc **pp2 = (struct proc **)v2;
674    register struct kinfo_proc *p1;
675    register struct kinfo_proc *p2;
676    register int result;
677    register pctcpu lresult;
678
679    /* remove one level of indirection */
680    p1 = *(struct kinfo_proc **) pp1;
681    p2 = *(struct kinfo_proc **) pp2;
682
683    ORDERKEY_RSSIZE
684    ORDERKEY_MEM
685    ORDERKEY_PCTCPU
686    ORDERKEY_CPUTIME
687    ORDERKEY_STATE
688    ORDERKEY_PRIO
689    ;
690
691    return(result);
692}
693
694/* compare_time - the comparison function for sorting by CPU time */
695
696int
697compare_time(v1, v2)
698
699const void *v1, *v2;
700
701{
702    register struct proc **pp1 = (struct proc **)v1;
703    register struct proc **pp2 = (struct proc **)v2;
704    register struct kinfo_proc *p1;
705    register struct kinfo_proc *p2;
706    register int result;
707    register pctcpu lresult;
708
709    /* remove one level of indirection */
710    p1 = *(struct kinfo_proc **) pp1;
711    p2 = *(struct kinfo_proc **) pp2;
712
713    ORDERKEY_CPUTIME
714    ORDERKEY_PCTCPU
715    ORDERKEY_STATE
716    ORDERKEY_PRIO
717    ORDERKEY_MEM
718    ORDERKEY_RSSIZE
719    ;
720
721    return(result);
722}
723
724/* compare_prio - the comparison function for sorting by CPU time */
725
726int
727compare_prio(v1, v2)
728
729const void *v1, *v2;
730
731{
732    register struct proc **pp1 = (struct proc **)v1;
733    register struct proc **pp2 = (struct proc **)v2;
734    register struct kinfo_proc *p1;
735    register struct kinfo_proc *p2;
736    register int result;
737    register pctcpu lresult;
738
739    /* remove one level of indirection */
740    p1 = *(struct kinfo_proc **) pp1;
741    p2 = *(struct kinfo_proc **) pp2;
742
743    ORDERKEY_PRIO
744    ORDERKEY_PCTCPU
745    ORDERKEY_CPUTIME
746    ORDERKEY_STATE
747    ORDERKEY_RSSIZE
748    ORDERKEY_MEM
749    ;
750
751    return(result);
752}
753
754int (*proc_compares[])() = {
755    compare_cpu,
756    compare_size,
757    compare_res,
758    compare_time,
759    compare_prio,
760    NULL
761};
762#else
763/*
764 *  proc_compare - comparison function for "qsort"
765 *	Compares the resource consumption of two processes using five
766 *  	distinct keys.  The keys (in descending order of importance) are:
767 *  	percent cpu, cpu ticks, state, resident set size, total virtual
768 *  	memory usage.  The process states are ordered as follows (from least
769 *  	to most important):  zombie, sleep, stop, start, run.  The array
770 *  	declaration below maps a process state index into a number that
771 *  	reflects this ordering.
772 */
773
774int
775proc_compare(v1, v2)
776
777const void *v1, *v2;
778
779{
780    register struct proc **pp1 = (struct proc **)v1;
781    register struct proc **pp2 = (struct proc **)v2;
782    register struct kinfo_proc *p1;
783    register struct kinfo_proc *p2;
784    register int result;
785    register pctcpu lresult;
786
787    /* remove one level of indirection */
788    p1 = *(struct kinfo_proc **) pp1;
789    p2 = *(struct kinfo_proc **) pp2;
790
791    /* compare percent cpu (pctcpu) */
792    if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
793    {
794	/* use CPU usage to break the tie */
795	if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0)
796	{
797	    /* use process state to break the tie */
798	    if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
799			  sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
800	    {
801		/* use priority to break the tie */
802		if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
803		{
804		    /* use resident set size (rssize) to break the tie */
805		    if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
806		    {
807			/* use total memory to break the tie */
808			result = PROCSIZE(p2) - PROCSIZE(p1);
809		    }
810		}
811	    }
812	}
813    }
814    else
815    {
816	result = lresult < 0 ? -1 : 1;
817    }
818
819    return(result);
820}
821#endif
822
823/*
824 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
825 *		the process does not exist.
826 *		It is EXTREMLY IMPORTANT that this function work correctly.
827 *		If top runs setuid root (as in SVR4), then this function
828 *		is the only thing that stands in the way of a serious
829 *		security problem.  It validates requests for the "kill"
830 *		and "renice" commands.
831 */
832
833int proc_owner(pid)
834
835pid_t pid;
836
837{
838    register int cnt;
839    register struct kinfo_proc **prefp;
840    register struct kinfo_proc *pp;
841
842    prefp = pref;
843    cnt = pref_len;
844    while (--cnt >= 0)
845    {
846	pp = *prefp++;
847	if (PP(pp, p_pid) == pid)
848	{
849	    return((int)EP(pp, e_pcred.p_ruid));
850	}
851    }
852    return(-1);
853}
854
855#ifdef DOSWAP
856/*
857 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
858 * to be based on the new swapctl(2) system call.
859 */
860static int
861swapmode(used, total)
862int *used;
863int *total;
864{
865	int nswap, rnswap, i;
866	struct swapent *swdev;
867
868	nswap = swapctl(SWAP_NSWAP, 0, 0);
869	if (nswap == 0)
870		return 0;
871
872	swdev = malloc(nswap * sizeof(*swdev));
873	if(swdev == NULL)
874		return 0;
875
876	rnswap = swapctl(SWAP_STATS, swdev, nswap);
877	if(rnswap == -1)
878		return 0;
879
880	/* if rnswap != nswap, then what? */
881
882	/* Total things up */
883	*total = *used = 0;
884	for (i = 0; i < nswap; i++) {
885		if (swdev[i].se_flags & SWF_ENABLE) {
886			*used += (swdev[i].se_inuse / (1024/DEV_BSIZE));
887			*total += (swdev[i].se_nblks / (1024/DEV_BSIZE));
888		}
889	}
890
891	free (swdev);
892	return 1;
893}
894#endif
895