1/*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *
16 *     * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * top - a top users display for Unix
35 *
36 * SYNOPSIS:  For FreeBSD 5.x, 6.x, 7.x, 8.x
37 *
38 * DESCRIPTION:
39 * Originally written for BSD4.4 system by Christos Zoulas.
40 * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider
41 * Order support hacked in from top-3.5beta6/machine/m_aix41.c
42 *   by Monte Mitzelfelt
43 * Ported to FreeBSD 5.x and higher by William LeFebvre
44 *
45 * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
46 *          Steven Wallace  <swallace@freebsd.org>
47 *          Wolfram Schneider <wosch@FreeBSD.org>
48 */
49
50
51#include <sys/time.h>
52#include <sys/types.h>
53#include <sys/signal.h>
54#include <sys/param.h>
55
56#include "config.h"
57#include <stdio.h>
58#include <string.h>
59#include <nlist.h>
60#include <math.h>
61#include <kvm.h>
62#include <pwd.h>
63#include <sys/errno.h>
64#include <sys/sysctl.h>
65#include <sys/dkstat.h>
66#include <sys/file.h>
67#include <sys/time.h>
68#include <sys/proc.h>
69#include <sys/user.h>
70#include <sys/vmmeter.h>
71#include <sys/resource.h>
72#include <sys/rtprio.h>
73#ifdef HAVE_UNISTD_H
74#include <unistd.h>
75#endif
76
77/* Swap */
78#include <stdlib.h>
79#include <sys/conf.h>
80
81#include <osreldate.h> /* for changes in kernel structures */
82
83#include "top.h"
84#include "machine.h"
85#include "utils.h"
86#include "username.h"
87#include "hash.h"
88#include "display.h"
89
90extern char* printable __P((char *));
91int swapmode __P((int *retavail, int *retfree));
92static int smpmode;
93static int namelength;
94
95/*
96 * Versions prior to 5.x do not track threads in kinfo_proc, so we
97 * simply do not display any information about them.
98 * Versions 5.x, 6.x, and 7.x track threads but the data reported
99 * as runtime for each thread is actually per-process and is just
100 * duplicated across all threads.  It would be very wrong to show
101 * this data individually for each thread.  Therefore we will show
102 * a THR column (number of threads) but not provide any sort of
103 * per-thread display.  We distinguish between these three ways of
104 * handling threads as follows:  HAS_THREADS indicates that the
105 * system has and tracks kernel threads (a THR column will appear
106 * in the display).  HAS_SHOWTHREADS indicates that the system
107 * reports correct per-thread information and we will provide a
108 * per-thread display (the 'H' and 't' command) upon request.
109 * HAS_SHOWTHREADS implies HAS_THREADS.
110 */
111
112/* HAS_THREADS for anything 5.x and up */
113#if OSMAJOR >= 5
114#define HAS_THREADS
115#endif
116
117/* HAS_SHOWTHREADS for anything 8.x and up */
118#if OSMAJOR >=8
119#define HAS_SHOWTHREADS
120#endif
121
122/* get_process_info passes back a handle.  This is what it looks like: */
123
124struct handle
125{
126    struct kinfo_proc **next_proc;	/* points to next valid proc pointer */
127    int remaining;		/* number of pointers remaining */
128};
129
130/* declarations for load_avg */
131#include "loadavg.h"
132
133/*
134 * Macros to access process information:
135 * In versions 4.x and earlier the kinfo_proc structure was a collection of
136 * substructures (kp_proc and kp_eproc).  Starting with 5.0 kinfo_proc was
137 * redesigned and "flattene" so that most of the information was available
138 * in a single structure.  We use macros to access the various types of
139 * information and define these macros according to the OS revision.  The
140 * names PP, EP, and VP are due to the fact that information was originally
141 * contained in the different substructures.  We retain these names in the
142 * code for backward compatibility.  These macros use ANSI concatenation.
143 * PP: proc
144 * EP: extented proc
145 * VP: vm (virtual memory information)
146 * PRUID: Real uid
147 * RP: rusage
148 * PPCPU: where we store calculated cpu% data
149 * SPPTR: where we store pointer to extra calculated data
150 * SP: access to the extra calculated data pointed to by SPPTR
151 */
152#if OSMAJOR <= 4
153#define PP(pp, field) ((pp)->kp_proc . p_##field)
154#define EP(pp, field) ((pp)->kp_eproc . e_##field)
155#define VP(pp, field) ((pp)->kp_eproc.e_vm . vm_##field)
156#define PRUID(pp) ((pp)->kp_eproc.e_pcred.p_ruid)
157#else
158#define PP(pp, field) ((pp)->ki_##field)
159#define EP(pp, field) ((pp)->ki_##field)
160#define VP(pp, field) ((pp)->ki_##field)
161#define PRUID(pp) ((pp)->ki_ruid)
162#define RP(pp, field) ((pp)->ki_rusage.ru_##field)
163#define PPCPU(pp) ((pp)->ki_sparelongs[0])
164#define SPPTR(pp) ((pp)->ki_spareptrs[0])
165#define SP(pp, field) (((struct save_proc *)((pp)->ki_spareptrs[0]))->sp_##field)
166#endif
167
168/* what we consider to be process size: */
169#if OSMAJOR <= 4
170#define PROCSIZE(pp) (VP((pp), map.size) / 1024)
171#else
172#define PROCSIZE(pp) (((pp)->ki_size) / 1024)
173#endif
174
175/* calculate a per-second rate using milliseconds */
176#define per_second(n, msec)   (((n) * 1000) / (msec))
177
178/* process state names for the "STATE" column of the display */
179/* the extra nulls in the string "run" are for adding a slash and
180   the processor number when needed */
181
182char *state_abbrev[] =
183{
184    "?", "START", "RUN", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK"
185};
186#define NUM_STATES 8
187
188/* kernel access */
189static kvm_t *kd;
190
191/* these are for dealing with sysctl-based data */
192#define MAXMIBLEN 8
193struct sysctl_mib {
194    char *name;
195    int mib[MAXMIBLEN];
196    size_t miblen;
197};
198static struct sysctl_mib mibs[] = {
199    { "vm.stats.sys.v_swtch" },
200#define V_SWTCH 0
201    { "vm.stats.sys.v_trap" },
202#define V_TRAP 1
203    { "vm.stats.sys.v_intr" },
204#define V_INTR 2
205    { "vm.stats.sys.v_soft" },
206#define V_SOFT 3
207    { "vm.stats.vm.v_forks" },
208#define V_FORKS 4
209    { "vm.stats.vm.v_vforks" },
210#define V_VFORKS 5
211    { "vm.stats.vm.v_rforks" },
212#define V_RFORKS 6
213    { "vm.stats.vm.v_vm_faults" },
214#define V_VM_FAULTS 7
215    { "vm.stats.vm.v_swapin" },
216#define V_SWAPIN 8
217    { "vm.stats.vm.v_swapout" },
218#define V_SWAPOUT 9
219    { "vm.stats.vm.v_tfree" },
220#define V_TFREE 10
221    { "vm.stats.vm.v_vnodein" },
222#define V_VNODEIN 11
223    { "vm.stats.vm.v_vnodeout" },
224#define V_VNODEOUT 12
225    { "vm.stats.vm.v_active_count" },
226#define V_ACTIVE_COUNT 13
227    { "vm.stats.vm.v_inactive_count" },
228#define V_INACTIVE_COUNT 14
229    { "vm.stats.vm.v_wire_count" },
230#define V_WIRE_COUNT 15
231    { "vm.stats.vm.v_cache_count" },
232#define V_CACHE_COUNT 16
233    { "vm.stats.vm.v_free_count" },
234#define V_FREE_COUNT 17
235    { "vm.stats.vm.v_swappgsin" },
236#define V_SWAPPGSIN 18
237    { "vm.stats.vm.v_swappgsout" },
238#define V_SWAPPGSOUT 19
239    { "vfs.bufspace" },
240#define VFS_BUFSPACE 20
241    { "kern.cp_time" },
242#define K_CP_TIME 21
243#ifdef HAS_SHOWTHREADS
244    { "kern.proc.all" },
245#else
246    { "kern.proc.proc" },
247#endif
248#define K_PROC 22
249    { NULL }
250};
251
252
253/* these are for calculating cpu state percentages */
254
255static long cp_time[CPUSTATES];
256static long cp_old[CPUSTATES];
257static long cp_diff[CPUSTATES];
258
259/* these are for detailing the process states */
260
261int process_states[8];
262char *procstatenames[] = {
263    "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ",
264    " waiting, ", " locked, ",
265    NULL
266};
267
268/* these are for detailing the cpu states */
269
270int cpu_states[CPUSTATES];
271char *cpustatenames[] = {
272    "user", "nice", "system", "interrupt", "idle", NULL
273};
274
275/* these are for detailing the kernel information */
276
277int kernel_stats[9];
278char *kernelnames[] = {
279    " ctxsw, ", " trap, ", " intr, ", " soft, ", " fork, ",
280    " flt, ", " pgin, ", " pgout, ", " fr",
281    NULL
282};
283
284/* these are for detailing the memory statistics */
285
286long memory_stats[7];
287char *memorynames[] = {
288    "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
289    NULL
290};
291
292long swap_stats[7];
293char *swapnames[] = {
294/*   0           1            2           3            4       5 */
295    "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out",
296    NULL
297};
298
299
300/*
301 * pbase points to the array that holds the kinfo_proc structures.  pref
302 * (pronounced p-ref) points to an array of kinfo_proc pointers and is where
303 * we build up a list of processes we wish to display.  Both pbase and pref are
304 * potentially resized on every call to get_process_info.  psize is the number
305 * of procs for which we currently have space allocated.  pref_len is the number
306 * of valid pointers in pref (this is used by proc_owner).  We start psize off
307 * at -1 to ensure that space gets allocated on the first call to
308 * get_process_info.
309 */
310
311static int psize = -1;
312static int pref_len;
313static struct kinfo_proc *pbase = NULL;
314static struct kinfo_proc **pref = NULL;
315
316/* this structure retains information from the proc array between samples */
317struct save_proc {
318    pid_t sp_pid;
319    u_int64_t sp_runtime;
320    long sp_vcsw;
321    long sp_ivcsw;
322    long sp_inblock;
323    long sp_oublock;
324    long sp_majflt;
325    long sp_totalio;
326    long sp_old_nvcsw;
327    long sp_old_nivcsw;
328    long sp_old_inblock;
329    long sp_old_oublock;
330    long sp_old_majflt;
331};
332hash_table *procs;
333
334struct proc_field {
335    char *name;
336    int width;
337    int rjust;
338    int min_screenwidth;
339    int (*format)(char *, int, struct kinfo_proc *);
340};
341
342/* these are for getting the memory statistics */
343
344static int pagesize;		/* kept from getpagesize */
345static int pageshift;		/* log base 2 of the pagesize */
346
347/* define pagetok in terms of pageshift */
348
349#define pagetok(size) ((size) << pageshift)
350
351/* things that we track between updates */
352static u_int ctxsws = 0;
353static u_int traps = 0;
354static u_int intrs = 0;
355static u_int softs = 0;
356static u_int64_t forks = 0;
357static u_int pfaults;
358static u_int pagein;
359static u_int pageout;
360static u_int tfreed;
361static int swappgsin = -1;
362static int swappgsout = -1;
363extern struct timeval timeout;
364static struct timeval lasttime = { 0, 0 };
365static long elapsed_time;
366static long elapsed_msecs;
367
368/* things that we track during an update */
369static long total_io;
370static int show_fullcmd;
371static struct handle handle;
372static int username_length;
373static int show_usernames;
374static int display_mode;
375static int *display_fields;
376#ifdef HAS_SHOWTHREADS
377static int show_threads = 0;
378#endif
379
380
381/* sorting orders. first is default */
382char *ordernames[] = {
383    "cpu", "size", "res", "time", "pri", "io", "pid", NULL
384};
385
386/* compare routines */
387int proc_compare(), compare_size(), compare_res(), compare_time(),
388    compare_prio(), compare_io(), compare_pid();
389
390int (*proc_compares[])() = {
391    proc_compare,
392    compare_size,
393    compare_res,
394    compare_time,
395    compare_prio,
396    compare_io,
397    compare_pid,
398    NULL
399};
400
401/* swap related calculations */
402
403static int mib_swapinfo[16];
404static int *mib_swapinfo_idx;
405static int mib_swapinfo_size = 0;
406
407void
408swap_init()
409
410{
411    size_t m;
412
413    m = sizeof(mib_swapinfo) / sizeof(mib_swapinfo[0]);
414    if (sysctlnametomib("vm.swap_info", mib_swapinfo, &m) != -1)
415    {
416	mib_swapinfo_size = m + 1;
417	mib_swapinfo_idx = &(mib_swapinfo[m]);
418    }
419}
420
421int
422swap_getdata(long long *retavail, long long *retfree)
423
424{
425    int n;
426    size_t size;
427    long long total = 0;
428    long long used = 0;
429    struct xswdev xsw;
430
431    n = 0;
432    if (mib_swapinfo_size > 0)
433    {
434	*mib_swapinfo_idx = 0;
435	while (size = sizeof(xsw),
436	       sysctl(mib_swapinfo, mib_swapinfo_size, &xsw, &size, NULL, 0) != -1)
437	{
438	    dprintf("swap_getdata: swaparea %d: nblks %d, used %d\n",
439		    n, xsw.xsw_nblks, xsw.xsw_used);
440	    total += (long long)xsw.xsw_nblks;
441	    used += (long long)xsw.xsw_used;
442	    *mib_swapinfo_idx = ++n;
443	}
444
445	*retavail = pagetok(total);
446	*retfree = pagetok(total) - pagetok(used);
447
448	if (total > 0)
449	{
450	    n = (int)((double)used * 100.0 / (double)total);
451	}
452	else
453	{
454	    n = 0;
455	}
456    }
457    else
458    {
459	*retavail = 0;
460	*retfree = 0;
461    }
462
463    dprintf("swap_getdata: avail %lld, free %lld, %d%%\n",
464	    *retavail, *retfree, n);
465    return(n);
466}
467
468/*
469 *  getkval(offset, ptr, size) - get a value out of the kernel.
470 *	"offset" is the byte offset into the kernel for the desired value,
471 *  	"ptr" points to a buffer into which the value is retrieved,
472 *  	"size" is the size of the buffer (and the object to retrieve).
473 *      Return 0 on success, -1 on any kind of failure.
474 */
475
476static int
477getkval(unsigned long offset, int *ptr, int size)
478
479{
480    if (kd != NULL)
481    {
482	if (kvm_read(kd, offset, (char *) ptr, size) == size)
483	{
484	    return(0);
485	}
486    }
487    return(-1);
488}
489
490int
491get_sysctl_mibs()
492
493{
494    struct sysctl_mib *mp;
495    size_t len;
496
497    mp = mibs;
498    while (mp->name != NULL)
499    {
500	len = MAXMIBLEN;
501	if (sysctlnametomib(mp->name, mp->mib, &len) == -1)
502	{
503	    message_error(" sysctlnametomib: %s", strerror(errno));
504	    return -1;
505	}
506	mp->miblen = len;
507	mp++;
508    }
509    return 0;
510}
511
512int
513get_sysctl(int idx, void *v, size_t l)
514
515{
516    struct sysctl_mib *m;
517    size_t len;
518
519    m = &(mibs[idx]);
520    len = l;
521    if (sysctl(m->mib, m->miblen, v, &len, NULL, 0) == -1)
522    {
523	message_error(" sysctl: %s", strerror(errno));
524	return -1;
525    }
526    return len;
527}
528
529size_t
530get_sysctlsize(int idx)
531
532{
533    size_t len;
534    struct sysctl_mib *m;
535
536    m = &(mibs[idx]);
537    if (sysctl(m->mib, m->miblen, NULL, &len, NULL, 0) == -1)
538    {
539	message_error(" sysctl (size): %s", strerror(errno));
540	len = 0;
541    }
542    return len;
543}
544
545int
546fmt_pid(char *buf, int sz, struct kinfo_proc *pp)
547
548{
549    return snprintf(buf, sz, "%6d", PP(pp, pid));
550}
551
552int
553fmt_username(char *buf, int sz, struct kinfo_proc *pp)
554
555{
556    return snprintf(buf, sz, "%-*.*s",
557		    username_length, username_length, username(PRUID(pp)));
558}
559
560int
561fmt_uid(char *buf, int sz, struct kinfo_proc *pp)
562
563{
564    return snprintf(buf, sz, "%6d", PRUID(pp));
565}
566
567int
568fmt_thr(char *buf, int sz, struct kinfo_proc *pp)
569
570{
571    return snprintf(buf, sz, "%3d", PP(pp, numthreads));
572}
573
574int
575fmt_pri(char *buf, int sz, struct kinfo_proc *pp)
576
577{
578#if OSMAJOR <= 4
579    return snprintf(buf, sz, "%3d", PP(pp, priority));
580#else
581    return snprintf(buf, sz, "%3d", PP(pp, pri.pri_level));
582#endif
583}
584
585int
586fmt_nice(char *buf, int sz, struct kinfo_proc *pp)
587
588{
589    return snprintf(buf, sz, "%4d", PP(pp, nice) - NZERO);
590}
591
592int
593fmt_size(char *buf, int sz, struct kinfo_proc *pp)
594
595{
596    return snprintf(buf, sz, "%5s", format_k(PROCSIZE(pp)));
597}
598
599int
600fmt_res(char *buf, int sz, struct kinfo_proc *pp)
601
602{
603    return snprintf(buf, sz, "%5s", format_k(pagetok(VP(pp, rssize))));
604}
605
606int
607fmt_state(char *buf, int sz, struct kinfo_proc *pp)
608
609{
610    int state;
611    char status[16];
612
613    state = PP(pp, stat);
614    switch(state)
615    {
616    case SRUN:
617	if (smpmode && PP(pp, oncpu) != 0xff)
618	    sprintf(status, "CPU%d", PP(pp, oncpu));
619	else
620	    strcpy(status, "RUN");
621	break;
622
623    case SSLEEP:
624	if (EP(pp, wmesg) != NULL) {
625	    sprintf(status, "%.6s", EP(pp, wmesg));
626	    break;
627	}
628	/* fall through */
629    default:
630	if (state >= 0 && state < NUM_STATES)
631	    sprintf(status, "%.6s", state_abbrev[(unsigned char) state]);
632	else
633	    sprintf(status, "?%-5d", state);
634	break;
635    }
636
637    return snprintf(buf, sz, "%-6.6s", status);
638}
639
640int
641fmt_flags(char *buf, int sz, struct kinfo_proc *pp)
642
643{
644    long flag;
645    char chrs[12];
646    char *p;
647
648    flag = PP(pp, flag);
649    p = chrs;
650    if (PP(pp, nice) < NZERO)
651	*p++ = '<';
652    else if (PP(pp, nice) > NZERO)
653	*p++ = 'N';
654    if (flag & P_TRACED)
655	*p++ = 'X';
656    if (flag & P_WEXIT && PP(pp, stat) != SZOMB)
657	*p++ = 'E';
658    if (flag & P_PPWAIT)
659	*p++ = 'V';
660    if (flag & P_SYSTEM || PP(pp, lock) > 0)
661	*p++ = 'L';
662    if (PP(pp, kiflag) & KI_SLEADER)
663	*p++ = 's';
664    if (flag & P_CONTROLT)
665	*p++ = '+';
666    if (flag & P_JAILED)
667	*p++ = 'J';
668    *p = '\0';
669
670    return snprintf(buf, sz, "%-3.3s", chrs);
671}
672
673int
674fmt_c(char *buf, int sz, struct kinfo_proc *pp)
675
676{
677    return snprintf(buf, sz, "%1x", PP(pp, lastcpu));
678}
679
680int
681fmt_time(char *buf, int sz, struct kinfo_proc *pp)
682
683{
684    return snprintf(buf, sz, "%6s",
685		    format_time((PP(pp, runtime) + 500000) / 1000000));
686}
687
688int
689fmt_cpu(char *buf, int sz, struct kinfo_proc *pp)
690
691{
692    return snprintf(buf, sz, "%5.2f%%", (double)PPCPU(pp) / 100.0);
693}
694
695int
696fmt_command(char *buf, int sz, struct kinfo_proc *pp)
697
698{
699    int inmem;
700    char cmd[MAX_COLS];
701    char *bufp;
702    struct pargs pargs;
703    int len;
704
705#if OSMAJOR <= 4
706    inmem = (PP(pp, flag) & P_INMEM);
707#else
708    inmem = (PP(pp, sflag) & PS_INMEM);
709#endif
710
711    if (show_fullcmd && inmem)
712    {
713        /* get the pargs structure */
714        if (getkval((unsigned long)PP(pp, args), (int *)&pargs, sizeof(pargs)) != -1)
715        {
716            /* determine workable length */
717            if ((len = pargs.ar_length) >= MAX_COLS)
718            {
719                len = MAX_COLS - 1;
720            }
721
722            /* get the string from that */
723            if (len > 0 && getkval((unsigned long)PP(pp, args) +
724				   sizeof(pargs.ar_ref) +
725				   sizeof(pargs.ar_length),
726				   (int *)cmd, len) != -1)
727            {
728                /* successfull retrieval: now convert nulls in to spaces */
729                bufp = cmd;
730                while (len-- > 0)
731                {
732                    if (*bufp == '\0')
733                    {
734                        *bufp = ' ';
735                    }
736                    bufp++;
737                }
738
739                /* null terminate cmd */
740                *--bufp = '\0';
741
742		/* format cmd as our answer */
743		return snprintf(buf, sz, "%s", cmd);
744            }
745        }
746    }
747
748    /* for anything else we just display comm */
749    return snprintf(buf, sz, inmem ? "%s" : "<%s>", printable(PP(pp, comm)));
750}
751
752int
753fmt_vcsw(char *buf, int sz, struct kinfo_proc *pp)
754
755{
756    return snprintf(buf, sz, "%6ld", per_second(SP(pp, vcsw), elapsed_msecs));
757}
758
759int
760fmt_ivcsw(char *buf, int sz, struct kinfo_proc *pp)
761
762{
763    return snprintf(buf, sz, "%6ld", per_second(SP(pp, ivcsw), elapsed_msecs));
764}
765
766int
767fmt_read(char *buf, int sz, struct kinfo_proc *pp)
768
769{
770    return snprintf(buf, sz, "%6ld", per_second(SP(pp, inblock), elapsed_msecs));
771}
772
773int
774fmt_write(char *buf, int sz, struct kinfo_proc *pp)
775
776{
777    return snprintf(buf, sz, "%6ld", per_second(SP(pp, oublock), elapsed_msecs));
778}
779
780int
781fmt_fault(char *buf, int sz, struct kinfo_proc *pp)
782
783{
784    return snprintf(buf, sz, "%6ld", per_second(SP(pp, majflt), elapsed_msecs));
785}
786
787int
788fmt_iototal(char *buf, int sz, struct kinfo_proc *pp)
789
790{
791    return snprintf(buf, sz, "%6ld", per_second(SP(pp, totalio), elapsed_msecs));
792}
793
794int
795fmt_iopct(char *buf, int sz, struct kinfo_proc *pp)
796
797{
798    return snprintf(buf, sz, "%6.2f", (SP(pp, totalio) * 100.) / total_io);
799}
800
801
802struct proc_field proc_field[] = {
803    { "PID", 6, 1, 0, fmt_pid },
804    { "USERNAME", 8, 0, 0, fmt_username },
805#define FIELD_USERNAME 1
806    { "UID", 6, 1, 0, fmt_uid },
807#define FIELD_UID 2
808    { "THR", 3, 1, 0, fmt_thr },
809    { "PRI", 3, 1, 0, fmt_pri },
810    { "NICE", 4, 1, 0, fmt_nice },
811    { "SIZE", 5, 1, 0, fmt_size },
812    { "RES", 5, 1, 0, fmt_res },
813    { "STATE", 6, 0, 0, fmt_state },
814    { "FLG", 3, 0, 84, fmt_flags },
815    { "C", 1, 0, 0, fmt_c },
816    { "TIME", 6, 1, 0, fmt_time },
817    { "CPU", 6, 1, 0, fmt_cpu },
818    { "COMMAND", 7, 0, 0, fmt_command },
819    { "VCSW", 6, 1, 0, fmt_vcsw },
820    { "IVCSW", 6, 1, 0, fmt_ivcsw },
821    { "READ", 6, 1, 0, fmt_read },
822    { "WRITE", 6, 1, 0, fmt_write },
823    { "FAULT", 6, 1, 0, fmt_fault },
824    { "TOTAL", 6, 1, 0, fmt_iototal },
825    { "PERCENT", 7, 1, 0, fmt_iopct },
826    { NULL, 0, 0, 0, NULL }
827};
828#define MAX_FIELDS 24
829
830static int mode0_display[MAX_FIELDS];
831static int mode0thr_display[MAX_FIELDS];
832static int mode1_display[MAX_FIELDS];
833
834int
835field_index(char *col)
836
837{
838    struct proc_field *fp;
839    int i = 0;
840
841    fp = proc_field;
842    while (fp->name != NULL)
843    {
844	if (strcmp(col, fp->name) == 0)
845	{
846	    return i;
847	}
848	fp++;
849	i++;
850    }
851
852    return -1;
853}
854
855void
856field_subst(int *fp, int old, int new)
857
858{
859    while (*fp != -1)
860    {
861	if (*fp == old)
862	{
863	    *fp = new;
864	}
865	fp++;
866    }
867}
868
869int
870machine_init(struct statics *statics)
871
872{
873    int i = 0;
874    size_t len;
875    int *ip;
876
877    struct timeval boottime;
878
879    len = sizeof(smpmode);
880    if ((sysctlbyname("machdep.smp_active", &smpmode, &len, NULL, 0) < 0 &&
881         sysctlbyname("smp.smp_active", &smpmode, &len, NULL, 0) < 0) ||
882	len != sizeof(smpmode))
883    {
884	smpmode = 0;
885    }
886    smpmode = smpmode != 0;
887
888    /* kvm_open the active kernel: its okay if this fails */
889    kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
890
891    /* get boot time */
892    len = sizeof(boottime);
893    if (sysctlbyname("kern.boottime", &boottime, &len, NULL, 0) == -1)
894    {
895	/* we have no boottime to report */
896	boottime.tv_sec = -1;
897    }
898
899    pbase = NULL;
900    pref = NULL;
901
902    /* get the page size with "getpagesize" and calculate pageshift from it */
903    i = pagesize = getpagesize();
904    pageshift = 0;
905    while (i > 1)
906    {
907	pageshift++;
908	i >>= 1;
909    }
910
911    /* translate sysctl paths to mibs for faster access */
912    get_sysctl_mibs();
913
914    /* initialize swap stuff */
915    swap_init();
916
917    /* create the hash table that remembers proc data */
918    procs = hash_create(2039);
919
920    /* we only need the amount of log(2)1024 for our conversion */
921    pageshift -= LOG1024;
922
923    /* fill in the statics information */
924    statics->procstate_names = procstatenames;
925    statics->cpustate_names = cpustatenames;
926    statics->memory_names = memorynames;
927    statics->kernel_names = kernelnames;
928    statics->boottime = boottime.tv_sec;
929    statics->swap_names = swapnames;
930    statics->order_names = ordernames;
931    statics->flags.warmup = 1;
932    statics->modemax = 2;
933#ifdef HAS_SHOWTHREADS
934    statics->flags.threads = 1;
935#endif
936
937    /* we need kvm descriptor in order to show full commands */
938    statics->flags.fullcmds = kd != NULL;
939
940    /* set up the display indices for mode0 */
941    ip = mode0_display;
942    *ip++ = field_index("PID");
943    *ip++ = field_index("USERNAME");
944#ifdef HAS_THREADS
945    *ip++ = field_index("THR");
946#endif
947    *ip++ = field_index("PRI");
948    *ip++ = field_index("NICE");
949    *ip++ = field_index("SIZE");
950    *ip++ = field_index("RES");
951    *ip++ = field_index("STATE");
952    *ip++ = field_index("FLG");
953    if (smpmode)
954	*ip++ = field_index("C");
955    *ip++ = field_index("TIME");
956    *ip++ = field_index("CPU");
957    *ip++ = field_index("COMMAND");
958    *ip = -1;
959
960#ifdef HAS_SHOWTHREADS
961    /* set up the display indices for mode0 showing threads */
962    ip = mode0thr_display;
963    *ip++ = field_index("PID");
964    *ip++ = field_index("USERNAME");
965    *ip++ = field_index("PRI");
966    *ip++ = field_index("NICE");
967    *ip++ = field_index("SIZE");
968    *ip++ = field_index("RES");
969    *ip++ = field_index("STATE");
970    *ip++ = field_index("FLG");
971    if (smpmode)
972	*ip++ = field_index("C");
973    *ip++ = field_index("TIME");
974    *ip++ = field_index("CPU");
975    *ip++ = field_index("COMMAND");
976    *ip = -1;
977#endif
978
979    /* set up the display indices for mode1 */
980    ip = mode1_display;
981    *ip++ = field_index("PID");
982    *ip++ = field_index("USERNAME");
983    *ip++ = field_index("VCSW");
984    *ip++ = field_index("IVCSW");
985    *ip++ = field_index("READ");
986    *ip++ = field_index("WRITE");
987    *ip++ = field_index("FAULT");
988    *ip++ = field_index("TOTAL");
989    *ip++ = field_index("PERCENT");
990    *ip++ = field_index("COMMAND");
991    *ip = -1;
992
993    /* all done! */
994    return(0);
995}
996
997char *format_header(char *uname_field)
998
999{
1000    return "";
1001}
1002
1003void
1004get_vm_sum(struct vmmeter *sum)
1005
1006{
1007#define GET_VM_STAT(v, s)  (void)get_sysctl(v, &(sum->s), sizeof(sum->s))
1008
1009    GET_VM_STAT(V_SWTCH, v_swtch);
1010    GET_VM_STAT(V_TRAP, v_trap);
1011    GET_VM_STAT(V_INTR, v_intr);
1012    GET_VM_STAT(V_SOFT, v_soft);
1013    GET_VM_STAT(V_VFORKS, v_vforks);
1014    GET_VM_STAT(V_FORKS, v_forks);
1015    GET_VM_STAT(V_RFORKS, v_rforks);
1016    GET_VM_STAT(V_VM_FAULTS, v_vm_faults);
1017    GET_VM_STAT(V_SWAPIN, v_swapin);
1018    GET_VM_STAT(V_SWAPOUT, v_swapout);
1019    GET_VM_STAT(V_TFREE, v_tfree);
1020    GET_VM_STAT(V_VNODEIN, v_vnodein);
1021    GET_VM_STAT(V_VNODEOUT, v_vnodeout);
1022    GET_VM_STAT(V_ACTIVE_COUNT, v_active_count);
1023    GET_VM_STAT(V_INACTIVE_COUNT, v_inactive_count);
1024    GET_VM_STAT(V_WIRE_COUNT, v_wire_count);
1025    GET_VM_STAT(V_CACHE_COUNT, v_cache_count);
1026    GET_VM_STAT(V_FREE_COUNT, v_free_count);
1027    GET_VM_STAT(V_SWAPPGSIN, v_swappgsin);
1028    GET_VM_STAT(V_SWAPPGSOUT, v_swappgsout);
1029}
1030
1031void
1032get_system_info(struct system_info *si)
1033
1034{
1035    long total;
1036    struct timeval thistime;
1037    struct timeval timediff;
1038
1039    /* timestamp and time difference */
1040    gettimeofday(&thistime, 0);
1041    timersub(&thistime, &lasttime, &timediff);
1042    elapsed_time = timediff.tv_sec * 1000000 + timediff.tv_usec;
1043    elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000;
1044
1045    /* get the load averages */
1046    if (getloadavg(si->load_avg, NUM_AVERAGES) == -1)
1047    {
1048	/* failed: fill in with zeroes */
1049	(void) memset(si->load_avg, 0, sizeof(si->load_avg));
1050    }
1051
1052    /* get the cp_time array */
1053    (void)get_sysctl(K_CP_TIME, &cp_time, sizeof(cp_time));
1054
1055    /* convert cp_time counts to percentages */
1056    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
1057
1058    /* sum memory & swap statistics */
1059    {
1060	struct vmmeter sum;
1061	static unsigned int swap_delay = 0;
1062	static long long swapavail = 0;
1063	static long long swapfree = 0;
1064	static int bufspace = 0;
1065
1066	get_vm_sum(&sum);
1067
1068	/* get bufspace */
1069	bufspace = 0;
1070	(void) get_sysctl(VFS_BUFSPACE, &bufspace, sizeof(bufspace));
1071
1072	/* kernel stats */
1073	dprintf("kernel: swtch %d, trap %d, intr %d, soft %d, vforks %d\n",
1074		sum.v_swtch, sum.v_trap, sum.v_intr, sum.v_soft, sum.v_vforks);
1075	kernel_stats[0] = per_second(sum.v_swtch - ctxsws, elapsed_msecs);
1076	kernel_stats[1] = per_second(sum.v_trap - traps, elapsed_msecs);
1077	kernel_stats[2] = per_second(sum.v_intr - intrs, elapsed_msecs);
1078	kernel_stats[3] = per_second(sum.v_soft - softs, elapsed_msecs);
1079	kernel_stats[4] = per_second(sum.v_vforks + sum.v_forks +
1080				     sum.v_rforks - forks, elapsed_msecs);
1081	kernel_stats[5] = per_second(sum.v_vm_faults - pfaults, elapsed_msecs);
1082	kernel_stats[6] = per_second(sum.v_swapin + sum.v_vnodein - pagein, elapsed_msecs);
1083	kernel_stats[7] = per_second(sum.v_swapout + sum.v_vnodeout - pageout, elapsed_msecs);
1084	kernel_stats[8] = per_second(sum.v_tfree - tfreed, elapsed_msecs);
1085	ctxsws = sum.v_swtch;
1086	traps = sum.v_trap;
1087	intrs = sum.v_intr;
1088	softs = sum.v_soft;
1089	forks = (u_int64_t)sum.v_vforks + sum.v_forks + sum.v_rforks;
1090	pfaults = sum.v_vm_faults;
1091	pagein = sum.v_swapin + sum.v_vnodein;
1092	pageout = sum.v_swapout + sum.v_vnodeout;
1093	tfreed = sum.v_tfree;
1094
1095	/* convert memory stats to Kbytes */
1096	memory_stats[0] = pagetok(sum.v_active_count);
1097	memory_stats[1] = pagetok(sum.v_inactive_count);
1098	memory_stats[2] = pagetok(sum.v_wire_count);
1099	memory_stats[3] = pagetok(sum.v_cache_count);
1100	memory_stats[4] = bufspace / 1024;
1101	memory_stats[5] = pagetok(sum.v_free_count);
1102	memory_stats[6] = -1;
1103
1104	/* first interval */
1105        if (swappgsin < 0)
1106	{
1107	    swap_stats[4] = 0;
1108	    swap_stats[5] = 0;
1109	}
1110
1111	/* compute differences between old and new swap statistic */
1112	else
1113	{
1114	    swap_stats[4] = pagetok(sum.v_swappgsin - swappgsin);
1115	    swap_stats[5] = pagetok(sum.v_swappgsout - swappgsout);
1116	}
1117
1118        swappgsin = sum.v_swappgsin;
1119	swappgsout = sum.v_swappgsout;
1120
1121	/* call CPU heavy swap_getdata() only for changes */
1122        if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0)
1123	{
1124	    swap_stats[3] = swap_getdata(&swapavail, &swapfree);
1125	    swap_stats[0] = swapavail;
1126	    swap_stats[1] = swapavail - swapfree;
1127	    swap_stats[2] = swapfree;
1128	}
1129        swap_delay = 1;
1130	swap_stats[6] = -1;
1131    }
1132
1133    /* set arrays and strings */
1134    si->cpustates = cpu_states;
1135    si->kernel = kernel_stats;
1136    si->memory = memory_stats;
1137    si->swap = swap_stats;
1138
1139    si->last_pid = -1;
1140
1141    lasttime = thistime;
1142}
1143
1144caddr_t
1145get_process_info(struct system_info *si,
1146			 struct process_select *sel,
1147			 int compare_index)
1148
1149{
1150    int i;
1151    int total_procs;
1152    int active_procs;
1153    struct kinfo_proc **prefp;
1154    struct kinfo_proc *pp;
1155    struct kinfo_proc *prev_pp = NULL;
1156    struct save_proc *savep;
1157    long proc_io;
1158    pid_t pid;
1159    size_t size;
1160    int nproc;
1161
1162    /* these are copied out of sel for speed */
1163    int show_idle;
1164    int show_self;
1165    int show_system;
1166    int show_uid;
1167    char *show_command;
1168
1169    /* get proc table size and give it a boost */
1170    nproc = (int)get_sysctlsize(K_PROC) / sizeof(struct kinfo_proc);
1171    nproc += nproc >> 4;
1172    size = nproc * sizeof(struct kinfo_proc);
1173    dprintf("get_process_info: nproc %d, psize %d, size %d\n", nproc, psize, size);
1174
1175    /* make sure we have enough space allocated */
1176    if (nproc > psize)
1177    {
1178	/* reallocate both pbase and pref */
1179	pbase = (struct kinfo_proc *)realloc(pbase, size);
1180	pref  = (struct kinfo_proc **)realloc(pref,
1181		    sizeof(struct kinfo_proc *) * nproc);
1182	psize = nproc;
1183    }
1184
1185    /* make sure we got the space we asked for */
1186    if (pref == NULL || pbase == NULL)
1187    {
1188	/* abandon all hope */
1189	message_error(" Out of memory!");
1190	nproc = psize = 0;
1191	si->p_total = 0;
1192	si->p_active = 0;
1193	return NULL;
1194    }
1195
1196    /* get all process information (threads, too) */
1197    if (size > 0)
1198    {
1199	nproc = get_sysctl(K_PROC, pbase, size);
1200	if (nproc == -1)
1201	{
1202	    nproc = 0;
1203	}
1204	else
1205	{
1206	    nproc /= sizeof(struct kinfo_proc);
1207	}
1208    }
1209
1210    /* get a pointer to the states summary array */
1211    si->procstates = process_states;
1212
1213    /* set up flags which define what we are going to select */
1214    show_idle = sel->idle;
1215    show_self = 0;
1216    show_system = sel->system;
1217    show_uid = sel->uid != -1;
1218    show_fullcmd = sel->fullcmd;
1219    show_command = sel->command;
1220    show_usernames = sel->usernames;
1221    display_mode = sel->mode;
1222#ifdef HAS_SHOWTHREADS
1223    show_threads = sel->threads;
1224#endif
1225
1226    /* count up process states and get pointers to interesting procs */
1227    total_procs = 0;
1228    active_procs = 0;
1229    total_io = 0;
1230    memset((char *)process_states, 0, sizeof(process_states));
1231    prefp = pref;
1232    for (pp = pbase, i = 0; i < nproc; pp++, i++)
1233    {
1234	/*
1235	 *  Place pointers to each valid proc structure in pref[].
1236	 *  Process slots that are actually in use have a non-zero
1237	 *  status field.  Processes with P_SYSTEM set are system
1238	 *  processes---these get ignored unless show_sysprocs is set.
1239	 */
1240	pid = PP(pp, pid);
1241	if (PP(pp, stat) != 0)
1242	{
1243#ifdef HAS_SHOWTHREADS
1244	    int is_thread;
1245	    lwpid_t tid;
1246
1247	    /* get thread id */
1248	    tid = PP(pp, tid);
1249
1250	    /* is this just a thread? */
1251	    is_thread = (prev_pp != NULL && PP(prev_pp, pid) == pid);
1252
1253	    /* count this process and its state */
1254	    /* only count threads if we are showing them */
1255	    if (show_threads || !is_thread)
1256	    {
1257		total_procs++;
1258		process_states[(unsigned char) PP(pp, stat)]++;
1259	    }
1260
1261	    /* grab old data from hash */
1262	    if ((savep = hash_lookup_lwpid(procs, tid)) != NULL)
1263	    {
1264		/* verify that this is not a new or different thread */
1265		/* (freebsd reuses thread ids fairly quickly) */
1266		/* pids must match and time can't have gone backwards */
1267		if (pid != savep->sp_pid || PP(pp, runtime) < savep->sp_runtime)
1268		{
1269		    /* not the same thread -- reuse the save_proc structure */
1270		    memset(savep, 0, sizeof(struct save_proc));
1271		    savep->sp_pid = pid;
1272		}
1273	    }
1274	    else
1275	    {
1276		/* havent seen this one before */
1277		savep = (struct save_proc *)calloc(1, sizeof(struct save_proc));
1278		savep->sp_pid = pid;
1279		hash_add_lwpid(procs, tid, savep);
1280	    }
1281
1282#else /* !HAS_SHOWTHREADS */
1283	    total_procs++;
1284	    process_states[(unsigned char) PP(pp, stat)]++;
1285
1286	    /* grab old data from hash */
1287	    if ((savep = hash_lookup_pid(procs, pid)) == NULL)
1288	    {
1289		/* havent seen this one before */
1290		savep = (struct save_proc *)calloc(1, sizeof(struct save_proc));
1291		savep->sp_pid = pid;
1292		hash_add_pid(procs, pid, savep);
1293	    }
1294#endif
1295
1296	    /* save the pointer to the sp struct */
1297	    SPPTR(pp) = (void *)savep;
1298
1299	    /* calculate %cpu */
1300	    PPCPU(pp) = ((PP(pp, runtime) - savep->sp_runtime) * 10000) /
1301		elapsed_time;
1302	    dprintf("%d (%d): runtime %lld, saved_pid %d, saved_runtime %lld, elapsed_time %d, ppcpu %d\n",
1303		    pid, PP(pp, tid), PP(pp, runtime), savep->sp_pid, savep->sp_runtime,
1304		    elapsed_time, PPCPU(pp));
1305
1306	    /* calculate io differences */
1307	    proc_io = 0;
1308	    savep->sp_vcsw = (RP(pp, nvcsw) - savep->sp_old_nvcsw);
1309	    savep->sp_ivcsw = (RP(pp, nivcsw) - savep->sp_old_nivcsw);
1310	    proc_io += (savep->sp_inblock = (RP(pp, inblock) - savep->sp_old_inblock));
1311	    proc_io += (savep->sp_oublock = (RP(pp, oublock) - savep->sp_old_oublock));
1312	    proc_io += (savep->sp_majflt = (RP(pp, majflt) - savep->sp_old_majflt));
1313	    total_io += proc_io;
1314	    savep->sp_totalio = proc_io;
1315
1316	    /* save data for next time */
1317	    savep->sp_runtime = PP(pp, runtime);
1318	    savep->sp_old_nvcsw = RP(pp, nvcsw);
1319	    savep->sp_old_nivcsw = RP(pp, nivcsw);
1320	    savep->sp_old_inblock = RP(pp, inblock);
1321	    savep->sp_old_oublock = RP(pp, oublock);
1322	    savep->sp_old_majflt = RP(pp, majflt);
1323
1324	    /* is this one selected for viewing? */
1325	    if ((PP(pp, stat) != SZOMB) &&
1326		(show_system || ((PP(pp, flag) & P_SYSTEM) == 0)) &&
1327		(show_idle || (PP(pp, pctcpu) != 0) ||
1328		 (PP(pp, stat) == SRUN)) &&
1329		(!show_uid || PRUID(pp) == (uid_t)sel->uid) &&
1330		(show_command == NULL ||
1331		 strcasestr(PP(pp, comm), show_command) != NULL))
1332	    {
1333#ifdef HAS_SHOWTHREADS
1334		/* yes, but make sure it isn't just a thread */
1335		if (show_threads || !is_thread)
1336		{
1337		    /* we will be showing this thread */
1338		    *prefp++ = pp;
1339		    active_procs++;
1340		}
1341		else
1342		{
1343		    /* we will not be showing this thread, but we need to roll
1344		       up its cpu usage in to its process */
1345		    PP(prev_pp, pctcpu) += PP(pp, pctcpu);
1346		}
1347#else /* !HAS_SHOWTHREADS */
1348		/* we will be showing this process */
1349		*prefp++ = pp;
1350		active_procs++;
1351#endif
1352	    }
1353	    prev_pp = pp;
1354	}
1355    }
1356
1357    dprintf("total_io: %d\n", total_io);
1358    if (total_io == 0) total_io = 1;
1359
1360    /* if requested, sort the "interesting" processes */
1361    if (active_procs > 1)
1362    {
1363	qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *),
1364	      proc_compares[compare_index]);
1365    }
1366
1367    /* remember active and total counts */
1368    si->p_total = total_procs;
1369    si->p_active = pref_len = active_procs;
1370
1371    /* pass back a handle */
1372    handle.next_proc = pref;
1373    handle.remaining = active_procs;
1374    return((caddr_t)&handle);
1375}
1376
1377static char p_header[MAX_COLS];
1378
1379char *
1380format_process_header(struct process_select *sel, caddr_t handle, int count)
1381
1382{
1383    int cols;
1384    int n;
1385    int w;
1386    char *p;
1387    int *fi;
1388    struct kinfo_proc **kip;
1389    struct proc_field *fp;
1390
1391    /* check for null handle */
1392    if (handle == NULL)
1393    {
1394	return("");
1395    }
1396
1397    /* remember how many columns there are on the display */
1398    cols = display_columns();
1399
1400    /* mode & threads dictate format */
1401    fi = display_fields =
1402	sel->mode == 0 ?
1403	(sel->threads == 0 ? mode0_display : mode0thr_display) :
1404	mode1_display;
1405
1406    /* set username field correctly */
1407    if (!sel->usernames)
1408    {
1409	/* display uids */
1410	field_subst(fi, FIELD_USERNAME, FIELD_UID);
1411    }
1412    else
1413    {
1414	/* display usernames */
1415	field_subst(fi, FIELD_UID, FIELD_USERNAME);
1416
1417	/* we also need to determine the longest username for column width */
1418	/* calculate namelength from first "count" processes */
1419	kip = ((struct handle *)handle)->next_proc;
1420	n = ((struct handle *)handle)->remaining;
1421	if (n > count)
1422	    n = count;
1423	namelength = 0;
1424	while (n-- > 0)
1425	{
1426	    w = strlen(username(PRUID(*kip)));
1427	    if (w > namelength) namelength = w;
1428	    kip++;
1429	}
1430	dprintf("format_process_header: namelength %d\n", namelength);
1431
1432	/* place it in bounds */
1433	if (namelength < 8)
1434	{
1435	    namelength = 8;
1436	}
1437
1438	/* set the column width */
1439	proc_field[FIELD_USERNAME].width = username_length = namelength;
1440    }
1441
1442    /* walk thru fields and construct header */
1443    /* are we worried about overflow??? */
1444    p = p_header;
1445    while (*fi != -1)
1446    {
1447	fp = &(proc_field[*fi++]);
1448	if (fp->min_screenwidth <= cols)
1449	{
1450	    p += sprintf(p, fp->rjust ? "%*s" : "%-*s", fp->width, fp->name);
1451	    *p++ = ' ';
1452	}
1453    }
1454    *--p = '\0';
1455
1456    return p_header;
1457}
1458
1459static char fmt[MAX_COLS];		/* static area where result is built */
1460
1461char *
1462format_next_process(caddr_t handle, char *(*get_userid)(int))
1463
1464{
1465    struct kinfo_proc *pp;
1466    struct handle *hp;
1467    struct proc_field *fp;
1468    int *fi;
1469    int i;
1470    int cols;
1471    char *p;
1472    int len;
1473    int x;
1474
1475    /* find and remember the next proc structure */
1476    hp = (struct handle *)handle;
1477    pp = *(hp->next_proc++);
1478    hp->remaining--;
1479
1480    /* mode & threads dictate format */
1481    fi = display_fields;
1482
1483    /* screen width is a consideration, too */
1484    cols = display_columns();
1485
1486    /* build output by field */
1487    p = fmt;
1488    len = MAX_COLS;
1489    while ((i = *fi++) != -1)
1490    {
1491	fp = &(proc_field[i]);
1492	if (len > 0 && fp->min_screenwidth <= cols)
1493	{
1494	    x = (*(fp->format))(p, len, pp);
1495	    if (x >= len)
1496	    {
1497		dprintf("format_next_process: formatter overflow: x %d, len %d, p %08x => %08x, fmt %08x - %08x\n",
1498			x, len, p, p + len, fmt, fmt + sizeof(fmt));
1499		p += len;
1500		len = 0;
1501	    }
1502	    else
1503	    {
1504		p += x;
1505		*p++ = ' ';
1506		len -= x + 1;
1507	    }
1508	}
1509    }
1510    *--p = '\0';
1511
1512    /* return the result */
1513    return(fmt);
1514}
1515
1516/* comparison routines for qsort */
1517
1518/*
1519 *  proc_compare - comparison function for "qsort"
1520 *	Compares the resource consumption of two processes using five
1521 *  	distinct keys.  The keys (in descending order of importance) are:
1522 *  	percent cpu, cpu ticks, state, resident set size, total virtual
1523 *  	memory usage.  The process states are ordered as follows (from least
1524 *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
1525 *  	array declaration below maps a process state index into a number
1526 *  	that reflects this ordering.
1527 */
1528
1529static unsigned char sorted_state[] =
1530{
1531    0,	/* not used		*/
1532    3,	/* sleep		*/
1533    1,	/* ABANDONED (WAIT)	*/
1534    6,	/* run			*/
1535    5,	/* start		*/
1536    2,	/* zombie		*/
1537    4	/* stop			*/
1538};
1539
1540
1541#define ORDERKEY_PCTCPU \
1542  if (lresult = (long) PPCPU(p2) - (long) PPCPU(p1), \
1543     (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
1544
1545#define ORDERKEY_CPTICKS \
1546  if ((result = PP(p2, runtime) > PP(p1, runtime) ? 1 : \
1547                PP(p2, runtime) < PP(p1, runtime) ? -1 : 0) == 0)
1548
1549#define ORDERKEY_STATE \
1550  if ((result = sorted_state[(unsigned char) PP(p2, stat)] - \
1551                sorted_state[(unsigned char) PP(p1, stat)]) == 0)
1552
1553#if OSMAJOR <= 4
1554#define ORDERKEY_PRIO \
1555  if ((result = PP(p2, priority) - PP(p1, priority)) == 0)
1556#else
1557#define ORDERKEY_PRIO \
1558  if ((result = PP(p2, pri.pri_level) - PP(p1, pri.pri_level)) == 0)
1559#endif
1560
1561#define ORDERKEY_RSSIZE \
1562  if ((result = VP(p2, rssize) - VP(p1, rssize)) == 0)
1563
1564#define ORDERKEY_MEM \
1565  if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
1566
1567#define ORDERKEY_IO \
1568  if ( (result = SP(p2, totalio) - SP(p1, totalio)) == 0)
1569
1570#define ORDERKEY_PID \
1571  if ( (result = PP(p1, pid) - PP(p2, pid)) == 0)
1572
1573/* compare_cpu - the comparison function for sorting by cpu percentage */
1574
1575int
1576proc_compare(struct proc **pp1, struct proc **pp2)
1577
1578{
1579    struct kinfo_proc *p1;
1580    struct kinfo_proc *p2;
1581    int result;
1582    pctcpu lresult;
1583
1584    /* remove one level of indirection */
1585    p1 = *(struct kinfo_proc **) pp1;
1586    p2 = *(struct kinfo_proc **) pp2;
1587
1588    ORDERKEY_PCTCPU
1589    ORDERKEY_CPTICKS
1590    ORDERKEY_STATE
1591    ORDERKEY_PRIO
1592    ORDERKEY_RSSIZE
1593    ORDERKEY_MEM
1594    ;
1595
1596    return(result);
1597}
1598
1599/* compare_size - the comparison function for sorting by total memory usage */
1600
1601int
1602compare_size(struct proc **pp1, struct proc **pp2)
1603
1604{
1605    struct kinfo_proc *p1;
1606    struct kinfo_proc *p2;
1607    int result;
1608    pctcpu lresult;
1609
1610    /* remove one level of indirection */
1611    p1 = *(struct kinfo_proc **) pp1;
1612    p2 = *(struct kinfo_proc **) pp2;
1613
1614    ORDERKEY_MEM
1615    ORDERKEY_RSSIZE
1616    ORDERKEY_PCTCPU
1617    ORDERKEY_CPTICKS
1618    ORDERKEY_STATE
1619    ORDERKEY_PRIO
1620    ;
1621
1622    return(result);
1623}
1624
1625/* compare_res - the comparison function for sorting by resident set size */
1626
1627int
1628compare_res(struct proc **pp1, struct proc **pp2)
1629
1630{
1631    struct kinfo_proc *p1;
1632    struct kinfo_proc *p2;
1633    int result;
1634    pctcpu lresult;
1635
1636    /* remove one level of indirection */
1637    p1 = *(struct kinfo_proc **) pp1;
1638    p2 = *(struct kinfo_proc **) pp2;
1639
1640    ORDERKEY_RSSIZE
1641    ORDERKEY_MEM
1642    ORDERKEY_PCTCPU
1643    ORDERKEY_CPTICKS
1644    ORDERKEY_STATE
1645    ORDERKEY_PRIO
1646    ;
1647
1648    return(result);
1649}
1650
1651/* compare_time - the comparison function for sorting by total cpu time */
1652
1653int
1654compare_time(struct proc **pp1, struct proc **pp2)
1655
1656{
1657    struct kinfo_proc *p1;
1658    struct kinfo_proc *p2;
1659    int result;
1660    pctcpu lresult;
1661
1662    /* remove one level of indirection */
1663    p1 = *(struct kinfo_proc **) pp1;
1664    p2 = *(struct kinfo_proc **) pp2;
1665
1666    ORDERKEY_CPTICKS
1667    ORDERKEY_PCTCPU
1668    ORDERKEY_STATE
1669    ORDERKEY_PRIO
1670    ORDERKEY_RSSIZE
1671    ORDERKEY_MEM
1672    ;
1673
1674      return(result);
1675  }
1676
1677/* compare_prio - the comparison function for sorting by priority */
1678
1679int
1680compare_prio(struct proc **pp1, struct proc **pp2)
1681
1682{
1683    struct kinfo_proc *p1;
1684    struct kinfo_proc *p2;
1685    int result;
1686    pctcpu lresult;
1687
1688    /* remove one level of indirection */
1689    p1 = *(struct kinfo_proc **) pp1;
1690    p2 = *(struct kinfo_proc **) pp2;
1691
1692    ORDERKEY_PRIO
1693    ORDERKEY_CPTICKS
1694    ORDERKEY_PCTCPU
1695    ORDERKEY_STATE
1696    ORDERKEY_RSSIZE
1697    ORDERKEY_MEM
1698    ;
1699
1700    return(result);
1701}
1702
1703/* compare_io - the comparison function for sorting by io count */
1704
1705int
1706compare_io(struct proc **pp1, struct proc **pp2)
1707
1708{
1709    struct kinfo_proc *p1;
1710    struct kinfo_proc *p2;
1711    int result;
1712    pctcpu lresult;
1713
1714    /* remove one level of indirection */
1715    p1 = *(struct kinfo_proc **) pp1;
1716    p2 = *(struct kinfo_proc **) pp2;
1717
1718    ORDERKEY_IO
1719    ORDERKEY_PCTCPU
1720    ORDERKEY_CPTICKS
1721    ORDERKEY_STATE
1722    ORDERKEY_PRIO
1723    ORDERKEY_RSSIZE
1724    ORDERKEY_MEM
1725    ;
1726
1727    return(result);
1728}
1729
1730/* compare_pid - the comparison function for sorting by process id */
1731
1732int
1733compare_pid(struct proc **pp1, struct proc **pp2)
1734
1735{
1736    struct kinfo_proc *p1;
1737    struct kinfo_proc *p2;
1738    int result;
1739
1740    /* remove one level of indirection */
1741    p1 = *(struct kinfo_proc **) pp1;
1742    p2 = *(struct kinfo_proc **) pp2;
1743
1744    ORDERKEY_PID
1745    ;
1746
1747    return(result);
1748}
1749
1750/*
1751 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
1752 *		the process does not exist.
1753 *		It is EXTREMLY IMPORTANT that this function work correctly.
1754 *		If top runs setuid root (as in SVR4), then this function
1755 *		is the only thing that stands in the way of a serious
1756 *		security problem.  It validates requests for the "kill"
1757 *		and "renice" commands.
1758 */
1759
1760int
1761proc_owner(int pid)
1762
1763{
1764    int cnt;
1765    struct kinfo_proc **prefp;
1766    struct kinfo_proc *pp;
1767
1768    prefp = pref;
1769    cnt = pref_len;
1770    while (--cnt >= 0)
1771    {
1772	pp = *prefp++;
1773	if (PP(pp, pid) == (pid_t)pid)
1774	{
1775	    return((int)PRUID(pp));
1776	}
1777    }
1778    return(-1);
1779}
1780
1781