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