xref: /minix/external/bsd/top/dist/machine/m_freebsd.c (revision 08cbf5a0)
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 
90 extern char* printable __P((char *));
91 int swapmode __P((int *retavail, int *retfree));
92 static int smpmode;
93 static 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 
124 struct 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 
182 char *state_abbrev[] =
183 {
184     "?", "START", "RUN", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK"
185 };
186 #define NUM_STATES 8
187 
188 /* kernel access */
189 static kvm_t *kd;
190 
191 /* these are for dealing with sysctl-based data */
192 #define MAXMIBLEN 8
193 struct sysctl_mib {
194     char *name;
195     int mib[MAXMIBLEN];
196     size_t miblen;
197 };
198 static 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 
255 static long cp_time[CPUSTATES];
256 static long cp_old[CPUSTATES];
257 static long cp_diff[CPUSTATES];
258 
259 /* these are for detailing the process states */
260 
261 int process_states[8];
262 char *procstatenames[] = {
263     "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ",
264     " waiting, ", " locked, ",
265     NULL
266 };
267 
268 /* these are for detailing the cpu states */
269 
270 int cpu_states[CPUSTATES];
271 char *cpustatenames[] = {
272     "user", "nice", "system", "interrupt", "idle", NULL
273 };
274 
275 /* these are for detailing the kernel information */
276 
277 int kernel_stats[9];
278 char *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 
286 long memory_stats[7];
287 char *memorynames[] = {
288     "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
289     NULL
290 };
291 
292 long swap_stats[7];
293 char *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 
311 static int psize = -1;
312 static int pref_len;
313 static struct kinfo_proc *pbase = NULL;
314 static struct kinfo_proc **pref = NULL;
315 
316 /* this structure retains information from the proc array between samples */
317 struct 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 };
332 hash_table *procs;
333 
334 struct 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 
344 static int pagesize;		/* kept from getpagesize */
345 static 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 */
352 static u_int ctxsws = 0;
353 static u_int traps = 0;
354 static u_int intrs = 0;
355 static u_int softs = 0;
356 static u_int64_t forks = 0;
357 static u_int pfaults;
358 static u_int pagein;
359 static u_int pageout;
360 static u_int tfreed;
361 static int swappgsin = -1;
362 static int swappgsout = -1;
363 extern struct timeval timeout;
364 static struct timeval lasttime = { 0, 0 };
365 static long elapsed_time;
366 static long elapsed_msecs;
367 
368 /* things that we track during an update */
369 static long total_io;
370 static int show_fullcmd;
371 static struct handle handle;
372 static int username_length;
373 static int show_usernames;
374 static int display_mode;
375 static int *display_fields;
376 #ifdef HAS_SHOWTHREADS
377 static int show_threads = 0;
378 #endif
379 
380 
381 /* sorting orders. first is default */
382 char *ordernames[] = {
383     "cpu", "size", "res", "time", "pri", "io", "pid", NULL
384 };
385 
386 /* compare routines */
387 int proc_compare(), compare_size(), compare_res(), compare_time(),
388     compare_prio(), compare_io(), compare_pid();
389 
390 int (*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 
403 static int mib_swapinfo[16];
404 static int *mib_swapinfo_idx;
405 static int mib_swapinfo_size = 0;
406 
407 void
408 swap_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 
421 int
422 swap_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 
476 static int
477 getkval(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 
490 int
491 get_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 
512 int
513 get_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 
529 size_t
530 get_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 
545 int
546 fmt_pid(char *buf, int sz, struct kinfo_proc *pp)
547 
548 {
549     return snprintf(buf, sz, "%6d", PP(pp, pid));
550 }
551 
552 int
553 fmt_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 
560 int
561 fmt_uid(char *buf, int sz, struct kinfo_proc *pp)
562 
563 {
564     return snprintf(buf, sz, "%6d", PRUID(pp));
565 }
566 
567 int
568 fmt_thr(char *buf, int sz, struct kinfo_proc *pp)
569 
570 {
571     return snprintf(buf, sz, "%3d", PP(pp, numthreads));
572 }
573 
574 int
575 fmt_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 
585 int
586 fmt_nice(char *buf, int sz, struct kinfo_proc *pp)
587 
588 {
589     return snprintf(buf, sz, "%4d", PP(pp, nice) - NZERO);
590 }
591 
592 int
593 fmt_size(char *buf, int sz, struct kinfo_proc *pp)
594 
595 {
596     return snprintf(buf, sz, "%5s", format_k(PROCSIZE(pp)));
597 }
598 
599 int
600 fmt_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 
606 int
607 fmt_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 
640 int
641 fmt_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 
673 int
674 fmt_c(char *buf, int sz, struct kinfo_proc *pp)
675 
676 {
677     return snprintf(buf, sz, "%1x", PP(pp, lastcpu));
678 }
679 
680 int
681 fmt_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 
688 int
689 fmt_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 
695 int
696 fmt_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 
752 int
753 fmt_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 
759 int
760 fmt_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 
766 int
767 fmt_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 
773 int
774 fmt_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 
780 int
781 fmt_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 
787 int
788 fmt_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 
794 int
795 fmt_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 
802 struct 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 
830 static int mode0_display[MAX_FIELDS];
831 static int mode0thr_display[MAX_FIELDS];
832 static int mode1_display[MAX_FIELDS];
833 
834 int
835 field_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 
855 void
856 field_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 
869 int
870 machine_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 
997 char *format_header(char *uname_field)
998 
999 {
1000     return "";
1001 }
1002 
1003 void
1004 get_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 
1031 void
1032 get_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 
1144 caddr_t
1145 get_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 
1377 static char p_header[MAX_COLS];
1378 
1379 char *
1380 format_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 
1459 static char fmt[MAX_COLS];		/* static area where result is built */
1460 
1461 char *
1462 format_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 
1529 static 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 
1575 int
1576 proc_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 
1601 int
1602 compare_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 
1627 int
1628 compare_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 
1653 int
1654 compare_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 
1679 int
1680 compare_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 
1705 int
1706 compare_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 
1732 int
1733 compare_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 
1760 int
1761 proc_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