Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / machine / m_freebsd.c
blobe26bca7688bf5a27bbce721ec641e5ec7e35acb6
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.
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.
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.
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.
34 * top - a top users display for Unix
36 * SYNOPSIS: For FreeBSD 5.x, 6.x, 7.x, 8.x
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
45 * AUTHOR: Christos Zoulas <christos@ee.cornell.edu>
46 * Steven Wallace <swallace@freebsd.org>
47 * Wolfram Schneider <wosch@FreeBSD.org>
51 #include <sys/time.h>
52 #include <sys/types.h>
53 #include <sys/signal.h>
54 #include <sys/param.h>
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
77 /* Swap */
78 #include <stdlib.h>
79 #include <sys/conf.h>
81 #include <osreldate.h> /* for changes in kernel structures */
83 #include "top.h"
84 #include "machine.h"
85 #include "utils.h"
86 #include "username.h"
87 #include "hash.h"
88 #include "display.h"
90 extern char* printable __P((char *));
91 int swapmode __P((int *retavail, int *retfree));
92 static int smpmode;
93 static int namelength;
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.
112 /* HAS_THREADS for anything 5.x and up */
113 #if OSMAJOR >= 5
114 #define HAS_THREADS
115 #endif
117 /* HAS_SHOWTHREADS for anything 8.x and up */
118 #if OSMAJOR >=8
119 #define HAS_SHOWTHREADS
120 #endif
122 /* get_process_info passes back a handle. This is what it looks like: */
124 struct handle
126 struct kinfo_proc **next_proc; /* points to next valid proc pointer */
127 int remaining; /* number of pointers remaining */
130 /* declarations for load_avg */
131 #include "loadavg.h"
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
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
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
175 /* calculate a per-second rate using milliseconds */
176 #define per_second(n, msec) (((n) * 1000) / (msec))
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 */
182 char *state_abbrev[] =
184 "?", "START", "RUN", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK"
186 #define NUM_STATES 8
188 /* kernel access */
189 static kvm_t *kd;
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;
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 }
253 /* these are for calculating cpu state percentages */
255 static long cp_time[CPUSTATES];
256 static long cp_old[CPUSTATES];
257 static long cp_diff[CPUSTATES];
259 /* these are for detailing the process states */
261 int process_states[8];
262 char *procstatenames[] = {
263 "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ",
264 " waiting, ", " locked, ",
265 NULL
268 /* these are for detailing the cpu states */
270 int cpu_states[CPUSTATES];
271 char *cpustatenames[] = {
272 "user", "nice", "system", "interrupt", "idle", NULL
275 /* these are for detailing the kernel information */
277 int kernel_stats[9];
278 char *kernelnames[] = {
279 " ctxsw, ", " trap, ", " intr, ", " soft, ", " fork, ",
280 " flt, ", " pgin, ", " pgout, ", " fr",
281 NULL
284 /* these are for detailing the memory statistics */
286 long memory_stats[7];
287 char *memorynames[] = {
288 "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free",
289 NULL
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
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.
311 static int psize = -1;
312 static int pref_len;
313 static struct kinfo_proc *pbase = NULL;
314 static struct kinfo_proc **pref = NULL;
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;
332 hash_table *procs;
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 *);
342 /* these are for getting the memory statistics */
344 static int pagesize; /* kept from getpagesize */
345 static int pageshift; /* log base 2 of the pagesize */
347 /* define pagetok in terms of pageshift */
349 #define pagetok(size) ((size) << pageshift)
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;
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
381 /* sorting orders. first is default */
382 char *ordernames[] = {
383 "cpu", "size", "res", "time", "pri", "io", "pid", NULL
386 /* compare routines */
387 int proc_compare(), compare_size(), compare_res(), compare_time(),
388 compare_prio(), compare_io(), compare_pid();
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
401 /* swap related calculations */
403 static int mib_swapinfo[16];
404 static int *mib_swapinfo_idx;
405 static int mib_swapinfo_size = 0;
407 void
408 swap_init()
411 size_t m;
413 m = sizeof(mib_swapinfo) / sizeof(mib_swapinfo[0]);
414 if (sysctlnametomib("vm.swap_info", mib_swapinfo, &m) != -1)
416 mib_swapinfo_size = m + 1;
417 mib_swapinfo_idx = &(mib_swapinfo[m]);
422 swap_getdata(long long *retavail, long long *retfree)
425 int n;
426 size_t size;
427 long long total = 0;
428 long long used = 0;
429 struct xswdev xsw;
431 n = 0;
432 if (mib_swapinfo_size > 0)
434 *mib_swapinfo_idx = 0;
435 while (size = sizeof(xsw),
436 sysctl(mib_swapinfo, mib_swapinfo_size, &xsw, &size, NULL, 0) != -1)
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;
445 *retavail = pagetok(total);
446 *retfree = pagetok(total) - pagetok(used);
448 if (total > 0)
450 n = (int)((double)used * 100.0 / (double)total);
452 else
454 n = 0;
457 else
459 *retavail = 0;
460 *retfree = 0;
463 dprintf("swap_getdata: avail %lld, free %lld, %d%%\n",
464 *retavail, *retfree, n);
465 return(n);
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.
476 static int
477 getkval(unsigned long offset, int *ptr, int size)
480 if (kd != NULL)
482 if (kvm_read(kd, offset, (char *) ptr, size) == size)
484 return(0);
487 return(-1);
491 get_sysctl_mibs()
494 struct sysctl_mib *mp;
495 size_t len;
497 mp = mibs;
498 while (mp->name != NULL)
500 len = MAXMIBLEN;
501 if (sysctlnametomib(mp->name, mp->mib, &len) == -1)
503 message_error(" sysctlnametomib: %s", strerror(errno));
504 return -1;
506 mp->miblen = len;
507 mp++;
509 return 0;
513 get_sysctl(int idx, void *v, size_t l)
516 struct sysctl_mib *m;
517 size_t len;
519 m = &(mibs[idx]);
520 len = l;
521 if (sysctl(m->mib, m->miblen, v, &len, NULL, 0) == -1)
523 message_error(" sysctl: %s", strerror(errno));
524 return -1;
526 return len;
529 size_t
530 get_sysctlsize(int idx)
533 size_t len;
534 struct sysctl_mib *m;
536 m = &(mibs[idx]);
537 if (sysctl(m->mib, m->miblen, NULL, &len, NULL, 0) == -1)
539 message_error(" sysctl (size): %s", strerror(errno));
540 len = 0;
542 return len;
546 fmt_pid(char *buf, int sz, struct kinfo_proc *pp)
549 return snprintf(buf, sz, "%6d", PP(pp, pid));
553 fmt_username(char *buf, int sz, struct kinfo_proc *pp)
556 return snprintf(buf, sz, "%-*.*s",
557 username_length, username_length, username(PRUID(pp)));
561 fmt_uid(char *buf, int sz, struct kinfo_proc *pp)
564 return snprintf(buf, sz, "%6d", PRUID(pp));
568 fmt_thr(char *buf, int sz, struct kinfo_proc *pp)
571 return snprintf(buf, sz, "%3d", PP(pp, numthreads));
575 fmt_pri(char *buf, int sz, struct kinfo_proc *pp)
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
586 fmt_nice(char *buf, int sz, struct kinfo_proc *pp)
589 return snprintf(buf, sz, "%4d", PP(pp, nice) - NZERO);
593 fmt_size(char *buf, int sz, struct kinfo_proc *pp)
596 return snprintf(buf, sz, "%5s", format_k(PROCSIZE(pp)));
600 fmt_res(char *buf, int sz, struct kinfo_proc *pp)
603 return snprintf(buf, sz, "%5s", format_k(pagetok(VP(pp, rssize))));
607 fmt_state(char *buf, int sz, struct kinfo_proc *pp)
610 int state;
611 char status[16];
613 state = PP(pp, stat);
614 switch(state)
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;
623 case SSLEEP:
624 if (EP(pp, wmesg) != NULL) {
625 sprintf(status, "%.6s", EP(pp, wmesg));
626 break;
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;
637 return snprintf(buf, sz, "%-6.6s", status);
641 fmt_flags(char *buf, int sz, struct kinfo_proc *pp)
644 long flag;
645 char chrs[12];
646 char *p;
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';
670 return snprintf(buf, sz, "%-3.3s", chrs);
674 fmt_c(char *buf, int sz, struct kinfo_proc *pp)
677 return snprintf(buf, sz, "%1x", PP(pp, lastcpu));
681 fmt_time(char *buf, int sz, struct kinfo_proc *pp)
684 return snprintf(buf, sz, "%6s",
685 format_time((PP(pp, runtime) + 500000) / 1000000));
689 fmt_cpu(char *buf, int sz, struct kinfo_proc *pp)
692 return snprintf(buf, sz, "%5.2f%%", (double)PPCPU(pp) / 100.0);
696 fmt_command(char *buf, int sz, struct kinfo_proc *pp)
699 int inmem;
700 char cmd[MAX_COLS];
701 char *bufp;
702 struct pargs pargs;
703 int len;
705 #if OSMAJOR <= 4
706 inmem = (PP(pp, flag) & P_INMEM);
707 #else
708 inmem = (PP(pp, sflag) & PS_INMEM);
709 #endif
711 if (show_fullcmd && inmem)
713 /* get the pargs structure */
714 if (getkval((unsigned long)PP(pp, args), (int *)&pargs, sizeof(pargs)) != -1)
716 /* determine workable length */
717 if ((len = pargs.ar_length) >= MAX_COLS)
719 len = MAX_COLS - 1;
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)
728 /* successfull retrieval: now convert nulls in to spaces */
729 bufp = cmd;
730 while (len-- > 0)
732 if (*bufp == '\0')
734 *bufp = ' ';
736 bufp++;
739 /* null terminate cmd */
740 *--bufp = '\0';
742 /* format cmd as our answer */
743 return snprintf(buf, sz, "%s", cmd);
748 /* for anything else we just display comm */
749 return snprintf(buf, sz, inmem ? "%s" : "<%s>", printable(PP(pp, comm)));
753 fmt_vcsw(char *buf, int sz, struct kinfo_proc *pp)
756 return snprintf(buf, sz, "%6ld", per_second(SP(pp, vcsw), elapsed_msecs));
760 fmt_ivcsw(char *buf, int sz, struct kinfo_proc *pp)
763 return snprintf(buf, sz, "%6ld", per_second(SP(pp, ivcsw), elapsed_msecs));
767 fmt_read(char *buf, int sz, struct kinfo_proc *pp)
770 return snprintf(buf, sz, "%6ld", per_second(SP(pp, inblock), elapsed_msecs));
774 fmt_write(char *buf, int sz, struct kinfo_proc *pp)
777 return snprintf(buf, sz, "%6ld", per_second(SP(pp, oublock), elapsed_msecs));
781 fmt_fault(char *buf, int sz, struct kinfo_proc *pp)
784 return snprintf(buf, sz, "%6ld", per_second(SP(pp, majflt), elapsed_msecs));
788 fmt_iototal(char *buf, int sz, struct kinfo_proc *pp)
791 return snprintf(buf, sz, "%6ld", per_second(SP(pp, totalio), elapsed_msecs));
795 fmt_iopct(char *buf, int sz, struct kinfo_proc *pp)
798 return snprintf(buf, sz, "%6.2f", (SP(pp, totalio) * 100.) / total_io);
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 }
828 #define MAX_FIELDS 24
830 static int mode0_display[MAX_FIELDS];
831 static int mode0thr_display[MAX_FIELDS];
832 static int mode1_display[MAX_FIELDS];
835 field_index(char *col)
838 struct proc_field *fp;
839 int i = 0;
841 fp = proc_field;
842 while (fp->name != NULL)
844 if (strcmp(col, fp->name) == 0)
846 return i;
848 fp++;
849 i++;
852 return -1;
855 void
856 field_subst(int *fp, int old, int new)
859 while (*fp != -1)
861 if (*fp == old)
863 *fp = new;
865 fp++;
870 machine_init(struct statics *statics)
873 int i = 0;
874 size_t len;
875 int *ip;
877 struct timeval boottime;
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))
884 smpmode = 0;
886 smpmode = smpmode != 0;
888 /* kvm_open the active kernel: its okay if this fails */
889 kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);
891 /* get boot time */
892 len = sizeof(boottime);
893 if (sysctlbyname("kern.boottime", &boottime, &len, NULL, 0) == -1)
895 /* we have no boottime to report */
896 boottime.tv_sec = -1;
899 pbase = NULL;
900 pref = NULL;
902 /* get the page size with "getpagesize" and calculate pageshift from it */
903 i = pagesize = getpagesize();
904 pageshift = 0;
905 while (i > 1)
907 pageshift++;
908 i >>= 1;
911 /* translate sysctl paths to mibs for faster access */
912 get_sysctl_mibs();
914 /* initialize swap stuff */
915 swap_init();
917 /* create the hash table that remembers proc data */
918 procs = hash_create(2039);
920 /* we only need the amount of log(2)1024 for our conversion */
921 pageshift -= LOG1024;
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
937 /* we need kvm descriptor in order to show full commands */
938 statics->flags.fullcmds = kd != NULL;
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;
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
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;
993 /* all done! */
994 return(0);
997 char *format_header(char *uname_field)
1000 return "";
1003 void
1004 get_vm_sum(struct vmmeter *sum)
1007 #define GET_VM_STAT(v, s) (void)get_sysctl(v, &(sum->s), sizeof(sum->s))
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);
1031 void
1032 get_system_info(struct system_info *si)
1035 long total;
1036 struct timeval thistime;
1037 struct timeval timediff;
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;
1045 /* get the load averages */
1046 if (getloadavg(si->load_avg, NUM_AVERAGES) == -1)
1048 /* failed: fill in with zeroes */
1049 (void) memset(si->load_avg, 0, sizeof(si->load_avg));
1052 /* get the cp_time array */
1053 (void)get_sysctl(K_CP_TIME, &cp_time, sizeof(cp_time));
1055 /* convert cp_time counts to percentages */
1056 total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
1058 /* sum memory & swap statistics */
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;
1066 get_vm_sum(&sum);
1068 /* get bufspace */
1069 bufspace = 0;
1070 (void) get_sysctl(VFS_BUFSPACE, &bufspace, sizeof(bufspace));
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;
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;
1104 /* first interval */
1105 if (swappgsin < 0)
1107 swap_stats[4] = 0;
1108 swap_stats[5] = 0;
1111 /* compute differences between old and new swap statistic */
1112 else
1114 swap_stats[4] = pagetok(sum.v_swappgsin - swappgsin);
1115 swap_stats[5] = pagetok(sum.v_swappgsout - swappgsout);
1118 swappgsin = sum.v_swappgsin;
1119 swappgsout = sum.v_swappgsout;
1121 /* call CPU heavy swap_getdata() only for changes */
1122 if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0)
1124 swap_stats[3] = swap_getdata(&swapavail, &swapfree);
1125 swap_stats[0] = swapavail;
1126 swap_stats[1] = swapavail - swapfree;
1127 swap_stats[2] = swapfree;
1129 swap_delay = 1;
1130 swap_stats[6] = -1;
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;
1139 si->last_pid = -1;
1141 lasttime = thistime;
1144 caddr_t
1145 get_process_info(struct system_info *si,
1146 struct process_select *sel,
1147 int compare_index)
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;
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;
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);
1175 /* make sure we have enough space allocated */
1176 if (nproc > psize)
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;
1185 /* make sure we got the space we asked for */
1186 if (pref == NULL || pbase == NULL)
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;
1196 /* get all process information (threads, too) */
1197 if (size > 0)
1199 nproc = get_sysctl(K_PROC, pbase, size);
1200 if (nproc == -1)
1202 nproc = 0;
1204 else
1206 nproc /= sizeof(struct kinfo_proc);
1210 /* get a pointer to the states summary array */
1211 si->procstates = process_states;
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
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++)
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.
1240 pid = PP(pp, pid);
1241 if (PP(pp, stat) != 0)
1243 #ifdef HAS_SHOWTHREADS
1244 int is_thread;
1245 lwpid_t tid;
1247 /* get thread id */
1248 tid = PP(pp, tid);
1250 /* is this just a thread? */
1251 is_thread = (prev_pp != NULL && PP(prev_pp, pid) == pid);
1253 /* count this process and its state */
1254 /* only count threads if we are showing them */
1255 if (show_threads || !is_thread)
1257 total_procs++;
1258 process_states[(unsigned char) PP(pp, stat)]++;
1261 /* grab old data from hash */
1262 if ((savep = hash_lookup_lwpid(procs, tid)) != NULL)
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)
1269 /* not the same thread -- reuse the save_proc structure */
1270 memset(savep, 0, sizeof(struct save_proc));
1271 savep->sp_pid = pid;
1274 else
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);
1282 #else /* !HAS_SHOWTHREADS */
1283 total_procs++;
1284 process_states[(unsigned char) PP(pp, stat)]++;
1286 /* grab old data from hash */
1287 if ((savep = hash_lookup_pid(procs, pid)) == NULL)
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);
1294 #endif
1296 /* save the pointer to the sp struct */
1297 SPPTR(pp) = (void *)savep;
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));
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;
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);
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))
1333 #ifdef HAS_SHOWTHREADS
1334 /* yes, but make sure it isn't just a thread */
1335 if (show_threads || !is_thread)
1337 /* we will be showing this thread */
1338 *prefp++ = pp;
1339 active_procs++;
1341 else
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);
1347 #else /* !HAS_SHOWTHREADS */
1348 /* we will be showing this process */
1349 *prefp++ = pp;
1350 active_procs++;
1351 #endif
1353 prev_pp = pp;
1357 dprintf("total_io: %d\n", total_io);
1358 if (total_io == 0) total_io = 1;
1360 /* if requested, sort the "interesting" processes */
1361 if (active_procs > 1)
1363 qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *),
1364 proc_compares[compare_index]);
1367 /* remember active and total counts */
1368 si->p_total = total_procs;
1369 si->p_active = pref_len = active_procs;
1371 /* pass back a handle */
1372 handle.next_proc = pref;
1373 handle.remaining = active_procs;
1374 return((caddr_t)&handle);
1377 static char p_header[MAX_COLS];
1379 char *
1380 format_process_header(struct process_select *sel, caddr_t handle, int count)
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;
1391 /* check for null handle */
1392 if (handle == NULL)
1394 return("");
1397 /* remember how many columns there are on the display */
1398 cols = display_columns();
1400 /* mode & threads dictate format */
1401 fi = display_fields =
1402 sel->mode == 0 ?
1403 (sel->threads == 0 ? mode0_display : mode0thr_display) :
1404 mode1_display;
1406 /* set username field correctly */
1407 if (!sel->usernames)
1409 /* display uids */
1410 field_subst(fi, FIELD_USERNAME, FIELD_UID);
1412 else
1414 /* display usernames */
1415 field_subst(fi, FIELD_UID, FIELD_USERNAME);
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)
1426 w = strlen(username(PRUID(*kip)));
1427 if (w > namelength) namelength = w;
1428 kip++;
1430 dprintf("format_process_header: namelength %d\n", namelength);
1432 /* place it in bounds */
1433 if (namelength < 8)
1435 namelength = 8;
1438 /* set the column width */
1439 proc_field[FIELD_USERNAME].width = username_length = namelength;
1442 /* walk thru fields and construct header */
1443 /* are we worried about overflow??? */
1444 p = p_header;
1445 while (*fi != -1)
1447 fp = &(proc_field[*fi++]);
1448 if (fp->min_screenwidth <= cols)
1450 p += sprintf(p, fp->rjust ? "%*s" : "%-*s", fp->width, fp->name);
1451 *p++ = ' ';
1454 *--p = '\0';
1456 return p_header;
1459 static char fmt[MAX_COLS]; /* static area where result is built */
1461 char *
1462 format_next_process(caddr_t handle, char *(*get_userid)(int))
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;
1475 /* find and remember the next proc structure */
1476 hp = (struct handle *)handle;
1477 pp = *(hp->next_proc++);
1478 hp->remaining--;
1480 /* mode & threads dictate format */
1481 fi = display_fields;
1483 /* screen width is a consideration, too */
1484 cols = display_columns();
1486 /* build output by field */
1487 p = fmt;
1488 len = MAX_COLS;
1489 while ((i = *fi++) != -1)
1491 fp = &(proc_field[i]);
1492 if (len > 0 && fp->min_screenwidth <= cols)
1494 x = (*(fp->format))(p, len, pp);
1495 if (x >= len)
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;
1502 else
1504 p += x;
1505 *p++ = ' ';
1506 len -= x + 1;
1510 *--p = '\0';
1512 /* return the result */
1513 return(fmt);
1516 /* comparison routines for qsort */
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.
1529 static unsigned char sorted_state[] =
1531 0, /* not used */
1532 3, /* sleep */
1533 1, /* ABANDONED (WAIT) */
1534 6, /* run */
1535 5, /* start */
1536 2, /* zombie */
1537 4 /* stop */
1541 #define ORDERKEY_PCTCPU \
1542 if (lresult = (long) PPCPU(p2) - (long) PPCPU(p1), \
1543 (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
1545 #define ORDERKEY_CPTICKS \
1546 if ((result = PP(p2, runtime) > PP(p1, runtime) ? 1 : \
1547 PP(p2, runtime) < PP(p1, runtime) ? -1 : 0) == 0)
1549 #define ORDERKEY_STATE \
1550 if ((result = sorted_state[(unsigned char) PP(p2, stat)] - \
1551 sorted_state[(unsigned char) PP(p1, stat)]) == 0)
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
1561 #define ORDERKEY_RSSIZE \
1562 if ((result = VP(p2, rssize) - VP(p1, rssize)) == 0)
1564 #define ORDERKEY_MEM \
1565 if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 )
1567 #define ORDERKEY_IO \
1568 if ( (result = SP(p2, totalio) - SP(p1, totalio)) == 0)
1570 #define ORDERKEY_PID \
1571 if ( (result = PP(p1, pid) - PP(p2, pid)) == 0)
1573 /* compare_cpu - the comparison function for sorting by cpu percentage */
1576 proc_compare(struct proc **pp1, struct proc **pp2)
1579 struct kinfo_proc *p1;
1580 struct kinfo_proc *p2;
1581 int result;
1582 pctcpu lresult;
1584 /* remove one level of indirection */
1585 p1 = *(struct kinfo_proc **) pp1;
1586 p2 = *(struct kinfo_proc **) pp2;
1588 ORDERKEY_PCTCPU
1589 ORDERKEY_CPTICKS
1590 ORDERKEY_STATE
1591 ORDERKEY_PRIO
1592 ORDERKEY_RSSIZE
1593 ORDERKEY_MEM
1596 return(result);
1599 /* compare_size - the comparison function for sorting by total memory usage */
1602 compare_size(struct proc **pp1, struct proc **pp2)
1605 struct kinfo_proc *p1;
1606 struct kinfo_proc *p2;
1607 int result;
1608 pctcpu lresult;
1610 /* remove one level of indirection */
1611 p1 = *(struct kinfo_proc **) pp1;
1612 p2 = *(struct kinfo_proc **) pp2;
1614 ORDERKEY_MEM
1615 ORDERKEY_RSSIZE
1616 ORDERKEY_PCTCPU
1617 ORDERKEY_CPTICKS
1618 ORDERKEY_STATE
1619 ORDERKEY_PRIO
1622 return(result);
1625 /* compare_res - the comparison function for sorting by resident set size */
1628 compare_res(struct proc **pp1, struct proc **pp2)
1631 struct kinfo_proc *p1;
1632 struct kinfo_proc *p2;
1633 int result;
1634 pctcpu lresult;
1636 /* remove one level of indirection */
1637 p1 = *(struct kinfo_proc **) pp1;
1638 p2 = *(struct kinfo_proc **) pp2;
1640 ORDERKEY_RSSIZE
1641 ORDERKEY_MEM
1642 ORDERKEY_PCTCPU
1643 ORDERKEY_CPTICKS
1644 ORDERKEY_STATE
1645 ORDERKEY_PRIO
1648 return(result);
1651 /* compare_time - the comparison function for sorting by total cpu time */
1654 compare_time(struct proc **pp1, struct proc **pp2)
1657 struct kinfo_proc *p1;
1658 struct kinfo_proc *p2;
1659 int result;
1660 pctcpu lresult;
1662 /* remove one level of indirection */
1663 p1 = *(struct kinfo_proc **) pp1;
1664 p2 = *(struct kinfo_proc **) pp2;
1666 ORDERKEY_CPTICKS
1667 ORDERKEY_PCTCPU
1668 ORDERKEY_STATE
1669 ORDERKEY_PRIO
1670 ORDERKEY_RSSIZE
1671 ORDERKEY_MEM
1674 return(result);
1677 /* compare_prio - the comparison function for sorting by priority */
1680 compare_prio(struct proc **pp1, struct proc **pp2)
1683 struct kinfo_proc *p1;
1684 struct kinfo_proc *p2;
1685 int result;
1686 pctcpu lresult;
1688 /* remove one level of indirection */
1689 p1 = *(struct kinfo_proc **) pp1;
1690 p2 = *(struct kinfo_proc **) pp2;
1692 ORDERKEY_PRIO
1693 ORDERKEY_CPTICKS
1694 ORDERKEY_PCTCPU
1695 ORDERKEY_STATE
1696 ORDERKEY_RSSIZE
1697 ORDERKEY_MEM
1700 return(result);
1703 /* compare_io - the comparison function for sorting by io count */
1706 compare_io(struct proc **pp1, struct proc **pp2)
1709 struct kinfo_proc *p1;
1710 struct kinfo_proc *p2;
1711 int result;
1712 pctcpu lresult;
1714 /* remove one level of indirection */
1715 p1 = *(struct kinfo_proc **) pp1;
1716 p2 = *(struct kinfo_proc **) pp2;
1718 ORDERKEY_IO
1719 ORDERKEY_PCTCPU
1720 ORDERKEY_CPTICKS
1721 ORDERKEY_STATE
1722 ORDERKEY_PRIO
1723 ORDERKEY_RSSIZE
1724 ORDERKEY_MEM
1727 return(result);
1730 /* compare_pid - the comparison function for sorting by process id */
1733 compare_pid(struct proc **pp1, struct proc **pp2)
1736 struct kinfo_proc *p1;
1737 struct kinfo_proc *p2;
1738 int result;
1740 /* remove one level of indirection */
1741 p1 = *(struct kinfo_proc **) pp1;
1742 p2 = *(struct kinfo_proc **) pp2;
1744 ORDERKEY_PID
1747 return(result);
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.
1761 proc_owner(int pid)
1764 int cnt;
1765 struct kinfo_proc **prefp;
1766 struct kinfo_proc *pp;
1768 prefp = pref;
1769 cnt = pref_len;
1770 while (--cnt >= 0)
1772 pp = *prefp++;
1773 if (PP(pp, pid) == (pid_t)pid)
1775 return((int)PRUID(pp));
1778 return(-1);