machine.c revision 1.28
1/*	$OpenBSD: machine.c,v 1.28 2002/07/02 03:05:47 tholo 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()
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(statics)
188	struct statics *statics;
189{
190	int pagesize;
191
192	stathz = getstathz();
193	if (stathz == -1)
194		return (-1);
195
196	pbase = NULL;
197	pref = NULL;
198	onproc = -1;
199	nproc = 0;
200
201	/* get the page size with "getpagesize" and calculate pageshift from
202	 * it */
203	pagesize = getpagesize();
204	pageshift = 0;
205	while (pagesize > 1) {
206		pageshift++;
207		pagesize >>= 1;
208	}
209
210	/* we only need the amount of log(2)1024 for our conversion */
211	pageshift -= LOG1024;
212
213	/* fill in the statics information */
214	statics->procstate_names = procstatenames;
215	statics->cpustate_names = cpustatenames;
216	statics->memory_names = memorynames;
217#ifdef ORDER
218	statics->order_names = ordernames;
219#endif
220	return (0);
221}
222
223char *
224format_header(uname_field)
225	char   *uname_field;
226{
227	char *ptr;
228
229	ptr = header + UNAME_START;
230	while (*uname_field != '\0') {
231		*ptr++ = *uname_field++;
232	}
233	return (header);
234}
235
236void
237get_system_info(si)
238	struct system_info *si;
239{
240	static int sysload_mib[] = {CTL_VM, VM_LOADAVG};
241	static int vmtotal_mib[] = {CTL_VM, VM_METER};
242	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
243	struct loadavg sysload;
244	struct vmtotal vmtotal;
245	double *infoloadp;
246	int total, i;
247	size_t  size;
248
249	size = sizeof(cp_time);
250	if (sysctl(cp_time_mib, 2, &cp_time, &size, NULL, 0) < 0) {
251		warn("sysctl kern.cp_time failed");
252		total = 0;
253	}
254
255	size = sizeof(sysload);
256	if (sysctl(sysload_mib, 2, &sysload, &size, NULL, 0) < 0) {
257		warn("sysctl failed");
258		total = 0;
259	}
260	infoloadp = si->load_avg;
261	for (i = 0; i < 3; i++)
262		*infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
263
264	/* convert cp_time counts to percentages */
265	total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
266
267	/* get total -- systemwide main memory usage structure */
268	size = sizeof(vmtotal);
269	if (sysctl(vmtotal_mib, 2, &vmtotal, &size, NULL, 0) < 0) {
270		warn("sysctl failed");
271		bzero(&vmtotal, sizeof(vmtotal));
272	}
273	/* convert memory stats to Kbytes */
274	memory_stats[0] = -1;
275	memory_stats[1] = pagetok(vmtotal.t_arm);
276	memory_stats[2] = pagetok(vmtotal.t_rm);
277	memory_stats[3] = -1;
278	memory_stats[4] = pagetok(vmtotal.t_free);
279	memory_stats[5] = -1;
280#ifdef DOSWAP
281	if (!swapmode(&memory_stats[6], &memory_stats[7])) {
282		memory_stats[6] = 0;
283		memory_stats[7] = 0;
284	}
285#endif
286
287	/* set arrays and strings */
288	si->cpustates = cpu_states;
289	si->memory = memory_stats;
290	si->last_pid = -1;
291}
292
293static struct handle handle;
294
295struct kinfo_proc *
296getprocs(op, arg, cnt)
297	int op, arg;
298	int *cnt;
299{
300	size_t size = sizeof(int);
301	int mib[4] = {CTL_KERN, KERN_PROC, op, arg};
302	int smib[2] = {CTL_KERN, KERN_NPROCS};
303	static int maxslp_mib[] = {CTL_VM, VM_MAXSLP};
304	static struct kinfo_proc *procbase;
305	int st;
306
307	size = sizeof(maxslp);
308	if (sysctl(maxslp_mib, 2, &maxslp, &size, NULL, 0) < 0) {
309		warn("sysctl vm.maxslp failed");
310		return (0);
311	}
312
313	st = sysctl(smib, 2, cnt, &size, NULL, 0);
314	if (st == -1) {
315		/* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
316		return (0);
317	}
318	if (procbase)
319		free(procbase);
320	size = (6 * (*cnt) * sizeof(struct kinfo_proc)) / 5;
321	procbase = (struct kinfo_proc *)malloc(size);
322	if (procbase == NULL)
323		return (0);
324	st = sysctl(mib, 4, procbase, &size, NULL, 0);
325	if (st == -1) {
326		/* _kvm_syserr(kd, kd->program, "kvm_getprocs"); */
327		return (0);
328	}
329	if (size % sizeof(struct kinfo_proc) != 0) {
330		/* _kvm_err(kd, kd->program,
331		    "proc size mismatch (%d total, %d chunks)",
332		    size, sizeof(struct kinfo_proc)); */
333		return (0);
334	}
335	return (procbase);
336}
337
338caddr_t
339get_process_info(si, sel, compare)
340	struct system_info *si;
341	struct process_select *sel;
342	int (*compare)(const void *, const void *);
343
344{
345	int show_idle, show_system, show_uid, show_command;
346	int total_procs, active_procs, i;
347	struct kinfo_proc **prefp, *pp;
348
349	if ((pbase = getprocs(KERN_PROC_KTHREAD, 0, &nproc)) == NULL) {
350		/* warnx("%s", kvm_geterr(kd)); */
351		quit(23);
352	}
353	if (nproc > onproc)
354		pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
355		    * (onproc = nproc));
356	if (pref == NULL) {
357		warnx("Out of memory.");
358		quit(23);
359	}
360	/* get a pointer to the states summary array */
361	si->procstates = process_states;
362
363	/* set up flags which define what we are going to select */
364	show_idle = sel->idle;
365	show_system = sel->system;
366	show_uid = sel->uid != -1;
367	show_command = sel->command != NULL;
368
369	/* count up process states and get pointers to interesting procs */
370	total_procs = 0;
371	active_procs = 0;
372	memset((char *) process_states, 0, sizeof(process_states));
373	prefp = pref;
374	for (pp = pbase, i = 0; i < nproc; pp++, i++) {
375		/*
376		 *  Place pointers to each valid proc structure in pref[].
377		 *  Process slots that are actually in use have a non-zero
378		 *  status field.  Processes with SSYS set are system
379		 *  processes---these get ignored unless show_sysprocs is set.
380		 */
381		if (PP(pp, p_stat) != 0 &&
382		    (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0))) {
383			total_procs++;
384			process_states[(unsigned char) PP(pp, p_stat)]++;
385			if ((PP(pp, p_stat) != SZOMB) &&
386			    (show_idle || (PP(pp, p_pctcpu) != 0) ||
387				(PP(pp, p_stat) == SRUN)) &&
388			    (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t) sel->uid)) {
389				*prefp++ = pp;
390				active_procs++;
391			}
392		}
393	}
394
395	/* if requested, sort the "interesting" processes */
396	if (compare != NULL) {
397		qsort((char *) pref, active_procs, sizeof(struct kinfo_proc *), compare);
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 *
412format_next_process(handle, get_userid)
413	caddr_t handle;
414	char *(*get_userid)();
415
416{
417	char waddr[sizeof(void *) * 2 + 3];	/* Hexify void pointer */
418	struct kinfo_proc *pp;
419	struct handle *hp;
420	char *p_wait;
421	int cputime;
422	double pct;
423
424	/* find and remember the next proc structure */
425	hp = (struct handle *) handle;
426	pp = *(hp->next_proc++);
427	hp->remaining--;
428
429	/* get the process's user struct and set cputime */
430	if ((PP(pp, p_flag) & P_INMEM) == 0) {
431		/*
432		 * Print swapped processes as <pname>
433		 */
434		char   *comm = PP(pp, p_comm);
435#define COMSIZ sizeof(PP(pp, p_comm))
436		char    buf[COMSIZ];
437		(void) strncpy(buf, comm, COMSIZ);
438		comm[0] = '<';
439		(void) strncpy(&comm[1], buf, COMSIZ - 2);
440		comm[COMSIZ - 2] = '\0';
441		(void) strncat(comm, ">", COMSIZ - 1);
442		comm[COMSIZ - 1] = '\0';
443	}
444	cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz;
445
446	/* calculate the base for cpu percentages */
447	pct = pctdouble(PP(pp, p_pctcpu));
448
449	if (PP(pp, p_wchan))
450		if (PP(pp, p_wmesg))
451			p_wait = EP(pp, e_wmesg);
452		else {
453			snprintf(waddr, sizeof(waddr), "%lx",
454			    (unsigned long) (PP(pp, p_wchan)) & ~KERNBASE);
455			p_wait = waddr;
456		}
457	else
458		p_wait = "-";
459
460	/* format this entry */
461	snprintf(fmt, MAX_COLS,
462	    Proc_format,
463	    PP(pp, p_pid),
464	    (*get_userid) (EP(pp, e_pcred.p_ruid)),
465	    PP(pp, p_priority) - PZERO,
466	    PP(pp, p_nice) - NZERO,
467	    format_k(pagetok(PROCSIZE(pp))),
468	    format_k(pagetok(VP(pp, vm_rssize))),
469	    (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > maxslp)
470	    ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)],
471	    p_wait,
472	    format_time(cputime),
473	    100.0 * pct,
474	    printable(PP(pp, p_comm)));
475
476	/* return the result */
477	return (fmt);
478}
479
480/* comparison routine for qsort */
481static unsigned char sorted_state[] =
482{
483	0,			/* not used		 */
484	4,			/* start		 */
485	5,			/* run			 */
486	2,			/* sleep		 */
487	3,			/* stop			 */
488	1			/* zombie		 */
489};
490#ifdef ORDER
491
492/*
493 *  proc_compares - comparison functions for "qsort"
494 */
495
496/*
497 * First, the possible comparison keys.  These are defined in such a way
498 * that they can be merely listed in the source code to define the actual
499 * desired ordering.
500 */
501
502
503#define ORDERKEY_PCTCPU \
504	if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \
505	    (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
506#define ORDERKEY_CPUTIME \
507	if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \
508		if ((result = PP(p2, p_rtime.tv_usec) - \
509		     PP(p1, p_rtime.tv_usec)) == 0)
510#define ORDERKEY_STATE \
511	if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \
512	    sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
513#define ORDERKEY_PRIO \
514	if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
515#define ORDERKEY_RSSIZE \
516	if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
517#define ORDERKEY_MEM \
518	if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
519
520
521/* compare_cpu - the comparison function for sorting by cpu percentage */
522int
523compare_cpu(v1, v2)
524	const void *v1, *v2;
525{
526	struct proc **pp1 = (struct proc **) v1;
527	struct proc **pp2 = (struct proc **) v2;
528	struct kinfo_proc *p1;
529	struct kinfo_proc *p2;
530	int result;
531	pctcpu lresult;
532
533	/* remove one level of indirection */
534	p1 = *(struct kinfo_proc **) pp1;
535	p2 = *(struct kinfo_proc **) pp2;
536
537	ORDERKEY_PCTCPU
538	    ORDERKEY_CPUTIME
539	    ORDERKEY_STATE
540	    ORDERKEY_PRIO
541	    ORDERKEY_RSSIZE
542	    ORDERKEY_MEM
543	    ;
544	return (result);
545}
546
547/* compare_size - the comparison function for sorting by total memory usage */
548int
549compare_size(v1, v2)
550	const void *v1, *v2;
551{
552	struct proc **pp1 = (struct proc **) v1;
553	struct proc **pp2 = (struct proc **) v2;
554	struct kinfo_proc *p1;
555	struct kinfo_proc *p2;
556	int result;
557	pctcpu lresult;
558
559	/* remove one level of indirection */
560	p1 = *(struct kinfo_proc **) pp1;
561	p2 = *(struct kinfo_proc **) pp2;
562
563	ORDERKEY_MEM
564	    ORDERKEY_RSSIZE
565	    ORDERKEY_PCTCPU
566	    ORDERKEY_CPUTIME
567	    ORDERKEY_STATE
568	    ORDERKEY_PRIO
569	    ;
570	return (result);
571}
572
573/* compare_res - the comparison function for sorting by resident set size */
574int
575compare_res(v1, v2)
576	const void *v1, *v2;
577{
578	struct proc **pp1 = (struct proc **) v1;
579	struct proc **pp2 = (struct proc **) v2;
580	struct kinfo_proc *p1;
581	struct kinfo_proc *p2;
582	int result;
583	pctcpu lresult;
584
585	/* remove one level of indirection */
586	p1 = *(struct kinfo_proc **) pp1;
587	p2 = *(struct kinfo_proc **) pp2;
588
589	ORDERKEY_RSSIZE
590	    ORDERKEY_MEM
591	    ORDERKEY_PCTCPU
592	    ORDERKEY_CPUTIME
593	    ORDERKEY_STATE
594	    ORDERKEY_PRIO
595	    ;
596	return (result);
597}
598
599/* compare_time - the comparison function for sorting by CPU time */
600int
601compare_time(v1, v2)
602	const void *v1, *v2;
603{
604	struct proc **pp1 = (struct proc **) v1;
605	struct proc **pp2 = (struct proc **) v2;
606	struct kinfo_proc *p1;
607	struct kinfo_proc *p2;
608	int result;
609	pctcpu lresult;
610
611	/* remove one level of indirection */
612	p1 = *(struct kinfo_proc **) pp1;
613	p2 = *(struct kinfo_proc **) pp2;
614
615	ORDERKEY_CPUTIME
616	    ORDERKEY_PCTCPU
617	    ORDERKEY_STATE
618	    ORDERKEY_PRIO
619	    ORDERKEY_MEM
620	    ORDERKEY_RSSIZE
621	    ;
622	return (result);
623}
624
625/* compare_prio - the comparison function for sorting by CPU time */
626int
627compare_prio(v1, v2)
628	const void *v1, *v2;
629{
630	struct proc **pp1 = (struct proc **) v1;
631	struct proc **pp2 = (struct proc **) v2;
632	struct kinfo_proc *p1;
633	struct kinfo_proc *p2;
634	int result;
635	pctcpu lresult;
636
637	/* remove one level of indirection */
638	p1 = *(struct kinfo_proc **) pp1;
639	p2 = *(struct kinfo_proc **) pp2;
640
641	ORDERKEY_PRIO
642	    ORDERKEY_PCTCPU
643	    ORDERKEY_CPUTIME
644	    ORDERKEY_STATE
645	    ORDERKEY_RSSIZE
646	    ORDERKEY_MEM
647	    ;
648	return (result);
649}
650
651int     (*proc_compares[]) () = {
652	compare_cpu,
653	compare_size,
654	compare_res,
655	compare_time,
656	compare_prio,
657	NULL
658};
659#else
660/*
661 *  proc_compare - comparison function for "qsort"
662 *	Compares the resource consumption of two processes using five
663 *  	distinct keys.  The keys (in descending order of importance) are:
664 *  	percent cpu, cpu ticks, state, resident set size, total virtual
665 *  	memory usage.  The process states are ordered as follows (from least
666 *  	to most important):  zombie, sleep, stop, start, run.  The array
667 *  	declaration below maps a process state index into a number that
668 *  	reflects this ordering.
669 */
670int
671proc_compare(v1, v2)
672	const void *v1, *v2;
673{
674	struct proc **pp1 = (struct proc **) v1;
675	struct proc **pp2 = (struct proc **) v2;
676	struct kinfo_proc *p1;
677	struct kinfo_proc *p2;
678	int result;
679	pctcpu lresult;
680
681	/* remove one level of indirection */
682	p1 = *(struct kinfo_proc **) pp1;
683	p2 = *(struct kinfo_proc **) pp2;
684
685	/* compare percent cpu (pctcpu) */
686	if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0) {
687		/* use CPU usage to break the tie */
688		if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0) {
689			/* use process state to break the tie */
690			if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
691				sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) {
692				/* use priority to break the tie */
693				if ((result = PP(p2, p_priority) -
694				    PP(p1, p_priority)) == 0) {
695					/* use resident set size (rssize) to
696					 * break the tie */
697					if ((result = VP(p2, vm_rssize) -
698					    VP(p1, vm_rssize)) == 0) {
699						/* use total memory to break
700						 * the tie */
701						result = PROCSIZE(p2) - PROCSIZE(p1);
702					}
703				}
704			}
705		}
706	} else {
707		result = lresult < 0 ? -1 : 1;
708	}
709	return (result);
710}
711#endif
712
713/*
714 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
715 *		the process does not exist.
716 *		It is EXTREMLY IMPORTANT that this function work correctly.
717 *		If top runs setuid root (as in SVR4), then this function
718 *		is the only thing that stands in the way of a serious
719 *		security problem.  It validates requests for the "kill"
720 *		and "renice" commands.
721 */
722int
723proc_owner(pid)
724	pid_t   pid;
725{
726	struct kinfo_proc **prefp, *pp;
727	int cnt;
728
729	prefp = pref;
730	cnt = pref_len;
731	while (--cnt >= 0) {
732		pp = *prefp++;
733		if (PP(pp, p_pid) == pid) {
734			return ((int) EP(pp, e_pcred.p_ruid));
735		}
736	}
737	return (-1);
738}
739#ifdef DOSWAP
740/*
741 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
742 * to be based on the new swapctl(2) system call.
743 */
744static int
745swapmode(used, total)
746	int    *used;
747	int    *total;
748{
749	int     nswap, rnswap, i;
750	struct swapent *swdev;
751
752	nswap = swapctl(SWAP_NSWAP, 0, 0);
753	if (nswap == 0)
754		return 0;
755
756	swdev = malloc(nswap * sizeof(*swdev));
757	if (swdev == NULL)
758		return 0;
759
760	rnswap = swapctl(SWAP_STATS, swdev, nswap);
761	if (rnswap == -1)
762		return 0;
763
764	/* if rnswap != nswap, then what? */
765
766	/* Total things up */
767	*total = *used = 0;
768	for (i = 0; i < nswap; i++) {
769		if (swdev[i].se_flags & SWF_ENABLE) {
770			*used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
771			*total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
772		}
773	}
774
775	free(swdev);
776	return 1;
777}
778#endif
779