machine.c revision 1.29
1/*	$OpenBSD: machine.c,v 1.29 2003/06/12 22:30:23 pvalchev Exp $	*/
2
3/*-
4 * Copyright (c) 1994 Thorsten Lockert <tholo@sigmasoft.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
21 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * top - a top users display for Unix
32 *
33 * SYNOPSIS:  For an OpenBSD system
34 *
35 * DESCRIPTION:
36 * This is the machine-dependent module for OpenBSD
37 * Tested on:
38 *	i386
39 *
40 * TERMCAP: -ltermlib
41 *
42 * CFLAGS: -DHAVE_GETOPT -DORDER
43 *
44 * AUTHOR:  Thorsten Lockert <tholo@sigmasoft.com>
45 *          Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu>
46 *          Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no>
47 *	    Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com>
48 *	    Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org>
49 */
50
51#include <sys/types.h>
52#include <sys/signal.h>
53#include <sys/param.h>
54
55#define DOSWAP
56
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <limits.h>
61#include <err.h>
62#include <math.h>
63#include <unistd.h>
64#include <sys/errno.h>
65#include <sys/sysctl.h>
66#include <sys/dir.h>
67#include <sys/dkstat.h>
68#include <sys/file.h>
69#include <sys/time.h>
70#include <sys/resource.h>
71
72#ifdef DOSWAP
73#include <sys/swap.h>
74#include <err.h>
75#endif
76
77static int swapmode(int *, int *);
78
79#include "top.h"
80#include "display.h"
81#include "machine.h"
82#include "utils.h"
83
84/* get_process_info passes back a handle.  This is what it looks like: */
85
86struct handle {
87	struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
88	int     remaining;	/* number of pointers remaining */
89};
90
91/* declarations for load_avg */
92#include "loadavg.h"
93
94#define PP(pp, field) ((pp)->kp_proc . field)
95#define EP(pp, field) ((pp)->kp_eproc . field)
96#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
97
98/* what we consider to be process size: */
99#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
100
101/*
102 *  These definitions control the format of the per-process area
103 */
104static char header[] =
105"  PID X        PRI NICE  SIZE   RES STATE WAIT     TIME    CPU COMMAND";
106/* 0123456   -- field to fill in starts at header+6 */
107#define UNAME_START 6
108
109#define Proc_format \
110	"%5d %-8.8s %3d %4d %5s %5s %-5s %-6.6s %6s %5.2f%% %.14s"
111
112
113/* process state names for the "STATE" column of the display */
114/* the extra nulls in the string "run" are for adding a slash and
115   the processor number when needed */
116
117char *state_abbrev[] = {
118	"", "start", "run\0\0\0", "sleep", "stop", "zomb",
119};
120
121
122static int stathz;
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 */
130int     process_states[7];
131char   *procstatenames[] = {
132	"", " starting, ", " running, ", " idle, ", " stopped, ", " zombie, ",
133	NULL
134};
135
136/* these are for detailing the cpu states */
137int     cpu_states[CPUSTATES];
138char   *cpustatenames[] = {
139	"user", "nice", "system", "interrupt", "idle", NULL
140};
141
142/* these are for detailing the memory statistics */
143int     memory_stats[8];
144char   *memorynames[] = {
145	"Real: ", "K/", "K act/tot  ", "Free: ", "K  ",
146#ifdef DOSWAP
147	"Swap: ", "K/", "K used/tot",
148#endif
149	NULL
150};
151
152#ifdef ORDER
153/* these are names given to allowed sorting orders -- first is default */
154char   *ordernames[] = {"cpu", "size", "res", "time", "pri", NULL};
155#endif
156
157/* these are for keeping track of the proc array */
158static int nproc;
159static int onproc = -1;
160static int pref_len;
161static struct kinfo_proc *pbase;
162static struct kinfo_proc **pref;
163
164/* these are for getting the memory statistics */
165static int pageshift;		/* log base 2 of the pagesize */
166
167/* define pagetok in terms of pageshift */
168#define pagetok(size) ((size) << pageshift)
169
170int maxslp;
171
172int
173getstathz(void)
174{
175	struct clockinfo cinf;
176	size_t  size = sizeof(cinf);
177	int     mib[2];
178
179	mib[0] = CTL_KERN;
180	mib[1] = KERN_CLOCKRATE;
181	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
182		return (-1);
183	return (cinf.stathz);
184}
185
186int
187machine_init(struct statics *statics)
188{
189	int pagesize;
190
191	stathz = getstathz();
192	if (stathz == -1)
193		return (-1);
194
195	pbase = NULL;
196	pref = NULL;
197	onproc = -1;
198	nproc = 0;
199
200	/* get the page size with "getpagesize" and calculate pageshift from
201	 * it */
202	pagesize = getpagesize();
203	pageshift = 0;
204	while (pagesize > 1) {
205		pageshift++;
206		pagesize >>= 1;
207	}
208
209	/* we only need the amount of log(2)1024 for our conversion */
210	pageshift -= LOG1024;
211
212	/* fill in the statics information */
213	statics->procstate_names = procstatenames;
214	statics->cpustate_names = cpustatenames;
215	statics->memory_names = memorynames;
216#ifdef ORDER
217	statics->order_names = ordernames;
218#endif
219	return (0);
220}
221
222char *
223format_header(char *uname_field)
224{
225	char *ptr;
226
227	ptr = header + UNAME_START;
228	while (*uname_field != '\0') {
229		*ptr++ = *uname_field++;
230	}
231	return (header);
232}
233
234void
235get_system_info(si)
236	struct system_info *si;
237{
238	static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
239	static int vmtotal_mib[] = {CTL_VM, VM_METER};
240	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
241	struct loadavg sysload;
242	struct vmtotal vmtotal;
243	double *infoloadp;
244	int total, i;
245	size_t  size;
246
247	size = sizeof(cp_time);
248	if (sysctl(cp_time_mib, 2, &cp_time, &size, NULL, 0) < 0) {
249		warn("sysctl kern.cp_time failed");
250		total = 0;
251	}
252
253	size = sizeof(sysload);
254	if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) < 0) {
255		warn("sysctl failed");
256		total = 0;
257	}
258	infoloadp = si->load_avg;
259	for (i = 0; i < 3; i++)
260		*infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
261
262	/* convert cp_time counts to percentages */
263	total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
264
265	/* get total -- systemwide main memory usage structure */
266	size = sizeof(vmtotal);
267	if (sysctl(vmtotal_mib, 2, &vmtotal, &size, NULL, 0) < 0) {
268		warn("sysctl failed");
269		bzero(&vmtotal, sizeof(vmtotal));
270	}
271	/* convert memory stats to Kbytes */
272	memory_stats[0] = -1;
273	memory_stats[1] = pagetok(vmtotal.t_arm);
274	memory_stats[2] = pagetok(vmtotal.t_rm);
275	memory_stats[3] = -1;
276	memory_stats[4] = pagetok(vmtotal.t_free);
277	memory_stats[5] = -1;
278#ifdef DOSWAP
279	if (!swapmode(&memory_stats[6], &memory_stats[7])) {
280		memory_stats[6] = 0;
281		memory_stats[7] = 0;
282	}
283#endif
284
285	/* set arrays and strings */
286	si->cpustates = cpu_states;
287	si->memory = memory_stats;
288	si->last_pid = -1;
289}
290
291static struct handle handle;
292
293struct kinfo_proc *
294getprocs(int op, int arg, int *cnt)
295{
296	size_t size = sizeof(int);
297	int mib[4] = {CTL_KERN, KERN_PROC, op, arg};
298	int smib[2] = {CTL_KERN, KERN_NPROCS};
299	static int maxslp_mib[] = {CTL_VM, VM_MAXSLP};
300	static struct kinfo_proc *procbase;
301	int st;
302
303	size = sizeof(maxslp);
304	if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) < 0) {
305		warn("sysctl vm.maxslp failed");
306		return (0);
307	}
308
309	st = sysctl(smib, 2, cnt, &size, NULL, 0);
310	if (st == -1) {
311		/* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
312		return (0);
313	}
314	if (procbase)
315		free(procbase);
316	size = (6 * (*cnt) * sizeof(struct kinfo_proc)) / 5;
317	procbase = (struct kinfo_proc *)malloc(size);
318	if (procbase == NULL)
319		return (0);
320	st = sysctl(mib, 4, procbase, &size, NULL, 0);
321	if (st == -1) {
322		/* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
323		return (0);
324	}
325	if (size % sizeof(struct kinfo_proc) != 0) {
326		/* _kvm_err(kd, kd->program,
327		    "proc size mismatch (%d total, %d chunks)",
328		    size, sizeof(struct kinfo_proc)); */
329		return (0);
330	}
331	return (procbase);
332}
333
334caddr_t
335get_process_info(struct system_info *si, struct process_select *sel,
336    int (*compare)(const void *, const void *))
337{
338	int show_idle, show_system, show_uid, show_command;
339	int total_procs, active_procs, i;
340	struct kinfo_proc **prefp, *pp;
341
342	if ((pbase = getprocs(KERN_PROC_KTHREAD, 0, &nproc)) == NULL) {
343		/* warnx("%s", kvm_geterr(kd)); */
344		quit(23);
345	}
346	if (nproc > onproc)
347		pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
348		    * (onproc = nproc));
349	if (pref == NULL) {
350		warnx("Out of memory.");
351		quit(23);
352	}
353	/* get a pointer to the states summary array */
354	si->procstates = process_states;
355
356	/* set up flags which define what we are going to select */
357	show_idle = sel->idle;
358	show_system = sel->system;
359	show_uid = sel->uid != -1;
360	show_command = sel->command != NULL;
361
362	/* count up process states and get pointers to interesting procs */
363	total_procs = 0;
364	active_procs = 0;
365	memset((char *) process_states, 0, sizeof(process_states));
366	prefp = pref;
367	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
368		/*
369		 *  Place pointers to each valid proc structure in pref[].
370		 *  Process slots that are actually in use have a non-zero
371		 *  status field.  Processes with SSYS set are system
372		 *  processes---these get ignored unless show_sysprocs is set.
373		 */
374		if (PP(pp, p_stat) != 0 &&
375		    (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0))) {
376			total_procs++;
377			process_states[(unsigned char) PP(pp, p_stat)]++;
378			if ((PP(pp, p_stat) != SZOMB) &&
379			    (show_idle || (PP(pp, p_pctcpu) != 0) ||
380				(PP(pp, p_stat) == SRUN)) &&
381			    (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t) sel->uid)) {
382				*prefp++ = pp;
383				active_procs++;
384			}
385		}
386	}
387
388	/* if requested, sort the "interesting" processes */
389	if (compare != NULL) {
390		qsort((char *) pref, active_procs, sizeof(struct kinfo_proc *), compare);
391	}
392	/* remember active and total counts */
393	si->p_total = total_procs;
394	si->p_active = pref_len = active_procs;
395
396	/* pass back a handle */
397	handle.next_proc = pref;
398	handle.remaining = active_procs;
399	return ((caddr_t) & handle);
400}
401
402char    fmt[MAX_COLS];		/* static area where result is built */
403
404char *
405format_next_process(caddr_t handle, char *(*get_userid)())
406{
407	char waddr[sizeof(void *) * 2 + 3];	/* Hexify void pointer */
408	struct kinfo_proc *pp;
409	struct handle *hp;
410	char *p_wait;
411	int cputime;
412	double pct;
413
414	/* find and remember the next proc structure */
415	hp = (struct handle *) handle;
416	pp = *(hp->next_proc++);
417	hp->remaining--;
418
419	/* get the process's user struct and set cputime */
420	if ((PP(pp, p_flag) & P_INMEM) == 0) {
421		/*
422		 * Print swapped processes as <pname>
423		 */
424		char   *comm = PP(pp, p_comm);
425#define COMSIZ sizeof(PP(pp, p_comm))
426		char    buf[COMSIZ];
427		(void) strncpy(buf, comm, COMSIZ);
428		comm[0] = '<';
429		(void) strncpy(&comm[1], buf, COMSIZ - 2);
430		comm[COMSIZ - 2] = '\0';
431		(void) strncat(comm, ">", COMSIZ - 1);
432		comm[COMSIZ - 1] = '\0';
433	}
434	cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz;
435
436	/* calculate the base for cpu percentages */
437	pct = pctdouble(PP(pp, p_pctcpu));
438
439	if (PP(pp, p_wchan))
440		if (PP(pp, p_wmesg))
441			p_wait = EP(pp, e_wmesg);
442		else {
443			snprintf(waddr, sizeof(waddr), "%lx",
444			    (unsigned long) (PP(pp, p_wchan)) & ~KERNBASE);
445			p_wait = waddr;
446		}
447	else
448		p_wait = "-";
449
450	/* format this entry */
451	snprintf(fmt, MAX_COLS,
452	    Proc_format,
453	    PP(pp, p_pid),
454	    (*get_userid) (EP(pp, e_pcred.p_ruid)),
455	    PP(pp, p_priority) - PZERO,
456	    PP(pp, p_nice) - NZERO,
457	    format_k(pagetok(PROCSIZE(pp))),
458	    format_k(pagetok(VP(pp, vm_rssize))),
459	    (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > maxslp)
460	    ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)],
461	    p_wait,
462	    format_time(cputime),
463	    100.0 * pct,
464	    printable(PP(pp, p_comm)));
465
466	/* return the result */
467	return (fmt);
468}
469
470/* comparison routine for qsort */
471static unsigned char sorted_state[] =
472{
473	0,			/* not used		 */
474	4,			/* start		 */
475	5,			/* run			 */
476	2,			/* sleep		 */
477	3,			/* stop			 */
478	1			/* zombie		 */
479};
480#ifdef ORDER
481
482/*
483 *  proc_compares - comparison functions for "qsort"
484 */
485
486/*
487 * First, the possible comparison keys.  These are defined in such a way
488 * that they can be merely listed in the source code to define the actual
489 * desired ordering.
490 */
491
492
493#define ORDERKEY_PCTCPU \
494	if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \
495	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
496#define ORDERKEY_CPUTIME \
497	if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \
498		if ((result = PP(p2, p_rtime.tv_usec) - \
499		     PP(p1, p_rtime.tv_usec)) == 0)
500#define ORDERKEY_STATE \
501	if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \
502	    sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
503#define ORDERKEY_PRIO \
504	if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
505#define ORDERKEY_RSSIZE \
506	if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
507#define ORDERKEY_MEM \
508	if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
509
510
511/* compare_cpu - the comparison function for sorting by cpu percentage */
512int
513compare_cpu(const void *v1, const void *v2)
514{
515	struct proc **pp1 = (struct proc **) v1;
516	struct proc **pp2 = (struct proc **) v2;
517	struct kinfo_proc *p1;
518	struct kinfo_proc *p2;
519	int result;
520	pctcpu lresult;
521
522	/* remove one level of indirection */
523	p1 = *(struct kinfo_proc **) pp1;
524	p2 = *(struct kinfo_proc **) pp2;
525
526	ORDERKEY_PCTCPU
527	    ORDERKEY_CPUTIME
528	    ORDERKEY_STATE
529	    ORDERKEY_PRIO
530	    ORDERKEY_RSSIZE
531	    ORDERKEY_MEM
532	    ;
533	return (result);
534}
535
536/* compare_size - the comparison function for sorting by total memory usage */
537int
538compare_size(const void *v1, const void *v2)
539{
540	struct proc **pp1 = (struct proc **) v1;
541	struct proc **pp2 = (struct proc **) v2;
542	struct kinfo_proc *p1;
543	struct kinfo_proc *p2;
544	int result;
545	pctcpu lresult;
546
547	/* remove one level of indirection */
548	p1 = *(struct kinfo_proc **) pp1;
549	p2 = *(struct kinfo_proc **) pp2;
550
551	ORDERKEY_MEM
552	    ORDERKEY_RSSIZE
553	    ORDERKEY_PCTCPU
554	    ORDERKEY_CPUTIME
555	    ORDERKEY_STATE
556	    ORDERKEY_PRIO
557	    ;
558	return (result);
559}
560
561/* compare_res - the comparison function for sorting by resident set size */
562int
563compare_res(const void *v1, const void *v2)
564{
565	struct proc **pp1 = (struct proc **) v1;
566	struct proc **pp2 = (struct proc **) v2;
567	struct kinfo_proc *p1;
568	struct kinfo_proc *p2;
569	int result;
570	pctcpu lresult;
571
572	/* remove one level of indirection */
573	p1 = *(struct kinfo_proc **) pp1;
574	p2 = *(struct kinfo_proc **) pp2;
575
576	ORDERKEY_RSSIZE
577	    ORDERKEY_MEM
578	    ORDERKEY_PCTCPU
579	    ORDERKEY_CPUTIME
580	    ORDERKEY_STATE
581	    ORDERKEY_PRIO
582	    ;
583	return (result);
584}
585
586/* compare_time - the comparison function for sorting by CPU time */
587int
588compare_time(const void *v1, const void *v2)
589{
590	struct proc **pp1 = (struct proc **) v1;
591	struct proc **pp2 = (struct proc **) v2;
592	struct kinfo_proc *p1;
593	struct kinfo_proc *p2;
594	int result;
595	pctcpu lresult;
596
597	/* remove one level of indirection */
598	p1 = *(struct kinfo_proc **) pp1;
599	p2 = *(struct kinfo_proc **) pp2;
600
601	ORDERKEY_CPUTIME
602	    ORDERKEY_PCTCPU
603	    ORDERKEY_STATE
604	    ORDERKEY_PRIO
605	    ORDERKEY_MEM
606	    ORDERKEY_RSSIZE
607	    ;
608	return (result);
609}
610
611/* compare_prio - the comparison function for sorting by CPU time */
612int
613compare_prio(const void *v1, const void *v2)
614{
615	struct proc **pp1 = (struct proc **) v1;
616	struct proc **pp2 = (struct proc **) v2;
617	struct kinfo_proc *p1;
618	struct kinfo_proc *p2;
619	int result;
620	pctcpu lresult;
621
622	/* remove one level of indirection */
623	p1 = *(struct kinfo_proc **) pp1;
624	p2 = *(struct kinfo_proc **) pp2;
625
626	ORDERKEY_PRIO
627	    ORDERKEY_PCTCPU
628	    ORDERKEY_CPUTIME
629	    ORDERKEY_STATE
630	    ORDERKEY_RSSIZE
631	    ORDERKEY_MEM
632	    ;
633	return (result);
634}
635
636int     (*proc_compares[]) () = {
637	compare_cpu,
638	compare_size,
639	compare_res,
640	compare_time,
641	compare_prio,
642	NULL
643};
644#else
645/*
646 *  proc_compare - comparison function for "qsort"
647 *	Compares the resource consumption of two processes using five
648 *  	distinct keys.  The keys (in descending order of importance) are:
649 *  	percent cpu, cpu ticks, state, resident set size, total virtual
650 *  	memory usage.  The process states are ordered as follows (from least
651 *  	to most important):  zombie, sleep, stop, start, run.  The array
652 *  	declaration below maps a process state index into a number that
653 *  	reflects this ordering.
654 */
655int
656proc_compare(const void *v1, const void *v2)
657{
658	struct proc **pp1 = (struct proc **) v1;
659	struct proc **pp2 = (struct proc **) v2;
660	struct kinfo_proc *p1;
661	struct kinfo_proc *p2;
662	int result;
663	pctcpu lresult;
664
665	/* remove one level of indirection */
666	p1 = *(struct kinfo_proc **) pp1;
667	p2 = *(struct kinfo_proc **) pp2;
668
669	/* compare percent cpu (pctcpu) */
670	if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0) {
671		/* use CPU usage to break the tie */
672		if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0) {
673			/* use process state to break the tie */
674			if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
675				sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) {
676				/* use priority to break the tie */
677				if ((result = PP(p2, p_priority) -
678				    PP(p1, p_priority)) == 0) {
679					/* use resident set size (rssize) to
680					 * break the tie */
681					if ((result = VP(p2, vm_rssize) -
682					    VP(p1, vm_rssize)) == 0) {
683						/* use total memory to break
684						 * the tie */
685						result = PROCSIZE(p2) - PROCSIZE(p1);
686					}
687				}
688			}
689		}
690	} else {
691		result = lresult < 0 ? -1 : 1;
692	}
693	return (result);
694}
695#endif
696
697/*
698 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
699 *		the process does not exist.
700 *		It is EXTREMLY IMPORTANT that this function work correctly.
701 *		If top runs setuid root (as in SVR4), then this function
702 *		is the only thing that stands in the way of a serious
703 *		security problem.  It validates requests for the "kill"
704 *		and "renice" commands.
705 */
706int
707proc_owner(pid_t pid)
708{
709	struct kinfo_proc **prefp, *pp;
710	int cnt;
711
712	prefp = pref;
713	cnt = pref_len;
714	while (--cnt >= 0) {
715		pp = *prefp++;
716		if (PP(pp, p_pid) == pid) {
717			return ((int) EP(pp, e_pcred.p_ruid));
718		}
719	}
720	return (-1);
721}
722#ifdef DOSWAP
723/*
724 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
725 * to be based on the new swapctl(2) system call.
726 */
727static int
728swapmode(int *used, int *total)
729{
730	int     nswap, rnswap, i;
731	struct swapent *swdev;
732
733	nswap = swapctl(SWAP_NSWAP, 0, 0);
734	if (nswap == 0)
735		return 0;
736
737	swdev = malloc(nswap * sizeof(*swdev));
738	if (swdev == NULL)
739		return 0;
740
741	rnswap = swapctl(SWAP_STATS, swdev, nswap);
742	if (rnswap == -1)
743		return 0;
744
745	/* if rnswap != nswap, then what? */
746
747	/* Total things up */
748	*total = *used = 0;
749	for (i = 0; i < nswap; i++) {
750		if (swdev[i].se_flags & SWF_ENABLE) {
751			*used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
752			*total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
753		}
754	}
755
756	free(swdev);
757	return 1;
758}
759#endif
760