diff options
Diffstat (limited to 'm_freebsd.c')
-rw-r--r-- | m_freebsd.c | 1780 |
1 files changed, 1780 insertions, 0 deletions
diff --git a/m_freebsd.c b/m_freebsd.c new file mode 100644 index 000000000000..e26bca7688bf --- /dev/null +++ b/m_freebsd.c @@ -0,0 +1,1780 @@ +/* + * Copyright (c) 1984 through 2008, William LeFebvre + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of William LeFebvre nor the names of other + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * top - a top users display for Unix + * + * SYNOPSIS: For FreeBSD 5.x, 6.x, 7.x, 8.x + * + * DESCRIPTION: + * Originally written for BSD4.4 system by Christos Zoulas. + * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider + * Order support hacked in from top-3.5beta6/machine/m_aix41.c + * by Monte Mitzelfelt + * Ported to FreeBSD 5.x and higher by William LeFebvre + * + * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> + * Steven Wallace <swallace@freebsd.org> + * Wolfram Schneider <wosch@FreeBSD.org> + */ + + +#include <sys/time.h> +#include <sys/types.h> +#include <sys/signal.h> +#include <sys/param.h> + +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <nlist.h> +#include <math.h> +#include <kvm.h> +#include <pwd.h> +#include <sys/errno.h> +#include <sys/sysctl.h> +#include <sys/dkstat.h> +#include <sys/file.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/vmmeter.h> +#include <sys/resource.h> +#include <sys/rtprio.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* Swap */ +#include <stdlib.h> +#include <sys/conf.h> + +#include <osreldate.h> /* for changes in kernel structures */ + +#include "top.h" +#include "machine.h" +#include "utils.h" +#include "username.h" +#include "hash.h" +#include "display.h" + +extern char* printable __P((char *)); +int swapmode __P((int *retavail, int *retfree)); +static int smpmode; +static int namelength; + +/* + * Versions prior to 5.x do not track threads in kinfo_proc, so we + * simply do not display any information about them. + * Versions 5.x, 6.x, and 7.x track threads but the data reported + * as runtime for each thread is actually per-process and is just + * duplicated across all threads. It would be very wrong to show + * this data individually for each thread. Therefore we will show + * a THR column (number of threads) but not provide any sort of + * per-thread display. We distinguish between these three ways of + * handling threads as follows: HAS_THREADS indicates that the + * system has and tracks kernel threads (a THR column will appear + * in the display). HAS_SHOWTHREADS indicates that the system + * reports correct per-thread information and we will provide a + * per-thread display (the 'H' and 't' command) upon request. + * HAS_SHOWTHREADS implies HAS_THREADS. + */ + +/* HAS_THREADS for anything 5.x and up */ +#if OSMAJOR >= 5 +#define HAS_THREADS +#endif + +/* HAS_SHOWTHREADS for anything 8.x and up */ +#if OSMAJOR >=8 +#define HAS_SHOWTHREADS +#endif + +/* get_process_info passes back a handle. This is what it looks like: */ + +struct handle +{ + struct kinfo_proc **next_proc; /* points to next valid proc pointer */ + int remaining; /* number of pointers remaining */ +}; + +/* declarations for load_avg */ +#include "loadavg.h" + +/* + * Macros to access process information: + * In versions 4.x and earlier the kinfo_proc structure was a collection of + * substructures (kp_proc and kp_eproc). Starting with 5.0 kinfo_proc was + * redesigned and "flattene" so that most of the information was available + * in a single structure. We use macros to access the various types of + * information and define these macros according to the OS revision. The + * names PP, EP, and VP are due to the fact that information was originally + * contained in the different substructures. We retain these names in the + * code for backward compatibility. These macros use ANSI concatenation. + * PP: proc + * EP: extented proc + * VP: vm (virtual memory information) + * PRUID: Real uid + * RP: rusage + * PPCPU: where we store calculated cpu% data + * SPPTR: where we store pointer to extra calculated data + * SP: access to the extra calculated data pointed to by SPPTR + */ +#if OSMAJOR <= 4 +#define PP(pp, field) ((pp)->kp_proc . p_##field) +#define EP(pp, field) ((pp)->kp_eproc . e_##field) +#define VP(pp, field) ((pp)->kp_eproc.e_vm . vm_##field) +#define PRUID(pp) ((pp)->kp_eproc.e_pcred.p_ruid) +#else +#define PP(pp, field) ((pp)->ki_##field) +#define EP(pp, field) ((pp)->ki_##field) +#define VP(pp, field) ((pp)->ki_##field) +#define PRUID(pp) ((pp)->ki_ruid) +#define RP(pp, field) ((pp)->ki_rusage.ru_##field) +#define PPCPU(pp) ((pp)->ki_sparelongs[0]) +#define SPPTR(pp) ((pp)->ki_spareptrs[0]) +#define SP(pp, field) (((struct save_proc *)((pp)->ki_spareptrs[0]))->sp_##field) +#endif + +/* what we consider to be process size: */ +#if OSMAJOR <= 4 +#define PROCSIZE(pp) (VP((pp), map.size) / 1024) +#else +#define PROCSIZE(pp) (((pp)->ki_size) / 1024) +#endif + +/* calculate a per-second rate using milliseconds */ +#define per_second(n, msec) (((n) * 1000) / (msec)) + +/* process state names for the "STATE" column of the display */ +/* the extra nulls in the string "run" are for adding a slash and + the processor number when needed */ + +char *state_abbrev[] = +{ + "?", "START", "RUN", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" +}; +#define NUM_STATES 8 + +/* kernel access */ +static kvm_t *kd; + +/* these are for dealing with sysctl-based data */ +#define MAXMIBLEN 8 +struct sysctl_mib { + char *name; + int mib[MAXMIBLEN]; + size_t miblen; +}; +static struct sysctl_mib mibs[] = { + { "vm.stats.sys.v_swtch" }, +#define V_SWTCH 0 + { "vm.stats.sys.v_trap" }, +#define V_TRAP 1 + { "vm.stats.sys.v_intr" }, +#define V_INTR 2 + { "vm.stats.sys.v_soft" }, +#define V_SOFT 3 + { "vm.stats.vm.v_forks" }, +#define V_FORKS 4 + { "vm.stats.vm.v_vforks" }, +#define V_VFORKS 5 + { "vm.stats.vm.v_rforks" }, +#define V_RFORKS 6 + { "vm.stats.vm.v_vm_faults" }, +#define V_VM_FAULTS 7 + { "vm.stats.vm.v_swapin" }, +#define V_SWAPIN 8 + { "vm.stats.vm.v_swapout" }, +#define V_SWAPOUT 9 + { "vm.stats.vm.v_tfree" }, +#define V_TFREE 10 + { "vm.stats.vm.v_vnodein" }, +#define V_VNODEIN 11 + { "vm.stats.vm.v_vnodeout" }, +#define V_VNODEOUT 12 + { "vm.stats.vm.v_active_count" }, +#define V_ACTIVE_COUNT 13 + { "vm.stats.vm.v_inactive_count" }, +#define V_INACTIVE_COUNT 14 + { "vm.stats.vm.v_wire_count" }, +#define V_WIRE_COUNT 15 + { "vm.stats.vm.v_cache_count" }, +#define V_CACHE_COUNT 16 + { "vm.stats.vm.v_free_count" }, +#define V_FREE_COUNT 17 + { "vm.stats.vm.v_swappgsin" }, +#define V_SWAPPGSIN 18 + { "vm.stats.vm.v_swappgsout" }, +#define V_SWAPPGSOUT 19 + { "vfs.bufspace" }, +#define VFS_BUFSPACE 20 + { "kern.cp_time" }, +#define K_CP_TIME 21 +#ifdef HAS_SHOWTHREADS + { "kern.proc.all" }, +#else + { "kern.proc.proc" }, +#endif +#define K_PROC 22 + { NULL } +}; + + +/* these are for calculating cpu state percentages */ + +static long cp_time[CPUSTATES]; +static long cp_old[CPUSTATES]; +static long cp_diff[CPUSTATES]; + +/* these are for detailing the process states */ + +int process_states[8]; +char *procstatenames[] = { + "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ", + " waiting, ", " locked, ", + NULL +}; + +/* these are for detailing the cpu states */ + +int cpu_states[CPUSTATES]; +char *cpustatenames[] = { + "user", "nice", "system", "interrupt", "idle", NULL +}; + +/* these are for detailing the kernel information */ + +int kernel_stats[9]; +char *kernelnames[] = { + " ctxsw, ", " trap, ", " intr, ", " soft, ", " fork, ", + " flt, ", " pgin, ", " pgout, ", " fr", + NULL +}; + +/* these are for detailing the memory statistics */ + +long memory_stats[7]; +char *memorynames[] = { + "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", + NULL +}; + +long swap_stats[7]; +char *swapnames[] = { +/* 0 1 2 3 4 5 */ + "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", + NULL +}; + + +/* + * pbase points to the array that holds the kinfo_proc structures. pref + * (pronounced p-ref) points to an array of kinfo_proc pointers and is where + * we build up a list of processes we wish to display. Both pbase and pref are + * potentially resized on every call to get_process_info. psize is the number + * of procs for which we currently have space allocated. pref_len is the number + * of valid pointers in pref (this is used by proc_owner). We start psize off + * at -1 to ensure that space gets allocated on the first call to + * get_process_info. + */ + +static int psize = -1; +static int pref_len; +static struct kinfo_proc *pbase = NULL; +static struct kinfo_proc **pref = NULL; + +/* this structure retains information from the proc array between samples */ +struct save_proc { + pid_t sp_pid; + u_int64_t sp_runtime; + long sp_vcsw; + long sp_ivcsw; + long sp_inblock; + long sp_oublock; + long sp_majflt; + long sp_totalio; + long sp_old_nvcsw; + long sp_old_nivcsw; + long sp_old_inblock; + long sp_old_oublock; + long sp_old_majflt; +}; +hash_table *procs; + +struct proc_field { + char *name; + int width; + int rjust; + int min_screenwidth; + int (*format)(char *, int, struct kinfo_proc *); +}; + +/* these are for getting the memory statistics */ + +static int pagesize; /* kept from getpagesize */ +static int pageshift; /* log base 2 of the pagesize */ + +/* define pagetok in terms of pageshift */ + +#define pagetok(size) ((size) << pageshift) + +/* things that we track between updates */ +static u_int ctxsws = 0; +static u_int traps = 0; +static u_int intrs = 0; +static u_int softs = 0; +static u_int64_t forks = 0; +static u_int pfaults; +static u_int pagein; +static u_int pageout; +static u_int tfreed; +static int swappgsin = -1; +static int swappgsout = -1; +extern struct timeval timeout; +static struct timeval lasttime = { 0, 0 }; +static long elapsed_time; +static long elapsed_msecs; + +/* things that we track during an update */ +static long total_io; +static int show_fullcmd; +static struct handle handle; +static int username_length; +static int show_usernames; +static int display_mode; +static int *display_fields; +#ifdef HAS_SHOWTHREADS +static int show_threads = 0; +#endif + + +/* sorting orders. first is default */ +char *ordernames[] = { + "cpu", "size", "res", "time", "pri", "io", "pid", NULL +}; + +/* compare routines */ +int proc_compare(), compare_size(), compare_res(), compare_time(), + compare_prio(), compare_io(), compare_pid(); + +int (*proc_compares[])() = { + proc_compare, + compare_size, + compare_res, + compare_time, + compare_prio, + compare_io, + compare_pid, + NULL +}; + +/* swap related calculations */ + +static int mib_swapinfo[16]; +static int *mib_swapinfo_idx; +static int mib_swapinfo_size = 0; + +void +swap_init() + +{ + size_t m; + + m = sizeof(mib_swapinfo) / sizeof(mib_swapinfo[0]); + if (sysctlnametomib("vm.swap_info", mib_swapinfo, &m) != -1) + { + mib_swapinfo_size = m + 1; + mib_swapinfo_idx = &(mib_swapinfo[m]); + } +} + +int +swap_getdata(long long *retavail, long long *retfree) + +{ + int n; + size_t size; + long long total = 0; + long long used = 0; + struct xswdev xsw; + + n = 0; + if (mib_swapinfo_size > 0) + { + *mib_swapinfo_idx = 0; + while (size = sizeof(xsw), + sysctl(mib_swapinfo, mib_swapinfo_size, &xsw, &size, NULL, 0) != -1) + { + dprintf("swap_getdata: swaparea %d: nblks %d, used %d\n", + n, xsw.xsw_nblks, xsw.xsw_used); + total += (long long)xsw.xsw_nblks; + used += (long long)xsw.xsw_used; + *mib_swapinfo_idx = ++n; + } + + *retavail = pagetok(total); + *retfree = pagetok(total) - pagetok(used); + + if (total > 0) + { + n = (int)((double)used * 100.0 / (double)total); + } + else + { + n = 0; + } + } + else + { + *retavail = 0; + *retfree = 0; + } + + dprintf("swap_getdata: avail %lld, free %lld, %d%%\n", + *retavail, *retfree, n); + return(n); +} + +/* + * getkval(offset, ptr, size) - get a value out of the kernel. + * "offset" is the byte offset into the kernel for the desired value, + * "ptr" points to a buffer into which the value is retrieved, + * "size" is the size of the buffer (and the object to retrieve). + * Return 0 on success, -1 on any kind of failure. + */ + +static int +getkval(unsigned long offset, int *ptr, int size) + +{ + if (kd != NULL) + { + if (kvm_read(kd, offset, (char *) ptr, size) == size) + { + return(0); + } + } + return(-1); +} + +int +get_sysctl_mibs() + +{ + struct sysctl_mib *mp; + size_t len; + + mp = mibs; + while (mp->name != NULL) + { + len = MAXMIBLEN; + if (sysctlnametomib(mp->name, mp->mib, &len) == -1) + { + message_error(" sysctlnametomib: %s", strerror(errno)); + return -1; + } + mp->miblen = len; + mp++; + } + return 0; +} + +int +get_sysctl(int idx, void *v, size_t l) + +{ + struct sysctl_mib *m; + size_t len; + + m = &(mibs[idx]); + len = l; + if (sysctl(m->mib, m->miblen, v, &len, NULL, 0) == -1) + { + message_error(" sysctl: %s", strerror(errno)); + return -1; + } + return len; +} + +size_t +get_sysctlsize(int idx) + +{ + size_t len; + struct sysctl_mib *m; + + m = &(mibs[idx]); + if (sysctl(m->mib, m->miblen, NULL, &len, NULL, 0) == -1) + { + message_error(" sysctl (size): %s", strerror(errno)); + len = 0; + } + return len; +} + +int +fmt_pid(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6d", PP(pp, pid)); +} + +int +fmt_username(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%-*.*s", + username_length, username_length, username(PRUID(pp))); +} + +int +fmt_uid(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6d", PRUID(pp)); +} + +int +fmt_thr(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%3d", PP(pp, numthreads)); +} + +int +fmt_pri(char *buf, int sz, struct kinfo_proc *pp) + +{ +#if OSMAJOR <= 4 + return snprintf(buf, sz, "%3d", PP(pp, priority)); +#else + return snprintf(buf, sz, "%3d", PP(pp, pri.pri_level)); +#endif +} + +int +fmt_nice(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%4d", PP(pp, nice) - NZERO); +} + +int +fmt_size(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%5s", format_k(PROCSIZE(pp))); +} + +int +fmt_res(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%5s", format_k(pagetok(VP(pp, rssize)))); +} + +int +fmt_state(char *buf, int sz, struct kinfo_proc *pp) + +{ + int state; + char status[16]; + + state = PP(pp, stat); + switch(state) + { + case SRUN: + if (smpmode && PP(pp, oncpu) != 0xff) + sprintf(status, "CPU%d", PP(pp, oncpu)); + else + strcpy(status, "RUN"); + break; + + case SSLEEP: + if (EP(pp, wmesg) != NULL) { + sprintf(status, "%.6s", EP(pp, wmesg)); + break; + } + /* fall through */ + default: + if (state >= 0 && state < NUM_STATES) + sprintf(status, "%.6s", state_abbrev[(unsigned char) state]); + else + sprintf(status, "?%-5d", state); + break; + } + + return snprintf(buf, sz, "%-6.6s", status); +} + +int +fmt_flags(char *buf, int sz, struct kinfo_proc *pp) + +{ + long flag; + char chrs[12]; + char *p; + + flag = PP(pp, flag); + p = chrs; + if (PP(pp, nice) < NZERO) + *p++ = '<'; + else if (PP(pp, nice) > NZERO) + *p++ = 'N'; + if (flag & P_TRACED) + *p++ = 'X'; + if (flag & P_WEXIT && PP(pp, stat) != SZOMB) + *p++ = 'E'; + if (flag & P_PPWAIT) + *p++ = 'V'; + if (flag & P_SYSTEM || PP(pp, lock) > 0) + *p++ = 'L'; + if (PP(pp, kiflag) & KI_SLEADER) + *p++ = 's'; + if (flag & P_CONTROLT) + *p++ = '+'; + if (flag & P_JAILED) + *p++ = 'J'; + *p = '\0'; + + return snprintf(buf, sz, "%-3.3s", chrs); +} + +int +fmt_c(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%1x", PP(pp, lastcpu)); +} + +int +fmt_time(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6s", + format_time((PP(pp, runtime) + 500000) / 1000000)); +} + +int +fmt_cpu(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%5.2f%%", (double)PPCPU(pp) / 100.0); +} + +int +fmt_command(char *buf, int sz, struct kinfo_proc *pp) + +{ + int inmem; + char cmd[MAX_COLS]; + char *bufp; + struct pargs pargs; + int len; + +#if OSMAJOR <= 4 + inmem = (PP(pp, flag) & P_INMEM); +#else + inmem = (PP(pp, sflag) & PS_INMEM); +#endif + + if (show_fullcmd && inmem) + { + /* get the pargs structure */ + if (getkval((unsigned long)PP(pp, args), (int *)&pargs, sizeof(pargs)) != -1) + { + /* determine workable length */ + if ((len = pargs.ar_length) >= MAX_COLS) + { + len = MAX_COLS - 1; + } + + /* get the string from that */ + if (len > 0 && getkval((unsigned long)PP(pp, args) + + sizeof(pargs.ar_ref) + + sizeof(pargs.ar_length), + (int *)cmd, len) != -1) + { + /* successfull retrieval: now convert nulls in to spaces */ + bufp = cmd; + while (len-- > 0) + { + if (*bufp == '\0') + { + *bufp = ' '; + } + bufp++; + } + + /* null terminate cmd */ + *--bufp = '\0'; + + /* format cmd as our answer */ + return snprintf(buf, sz, "%s", cmd); + } + } + } + + /* for anything else we just display comm */ + return snprintf(buf, sz, inmem ? "%s" : "<%s>", printable(PP(pp, comm))); +} + +int +fmt_vcsw(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6ld", per_second(SP(pp, vcsw), elapsed_msecs)); +} + +int +fmt_ivcsw(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6ld", per_second(SP(pp, ivcsw), elapsed_msecs)); +} + +int +fmt_read(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6ld", per_second(SP(pp, inblock), elapsed_msecs)); +} + +int +fmt_write(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6ld", per_second(SP(pp, oublock), elapsed_msecs)); +} + +int +fmt_fault(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6ld", per_second(SP(pp, majflt), elapsed_msecs)); +} + +int +fmt_iototal(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6ld", per_second(SP(pp, totalio), elapsed_msecs)); +} + +int +fmt_iopct(char *buf, int sz, struct kinfo_proc *pp) + +{ + return snprintf(buf, sz, "%6.2f", (SP(pp, totalio) * 100.) / total_io); +} + + +struct proc_field proc_field[] = { + { "PID", 6, 1, 0, fmt_pid }, + { "USERNAME", 8, 0, 0, fmt_username }, +#define FIELD_USERNAME 1 + { "UID", 6, 1, 0, fmt_uid }, +#define FIELD_UID 2 + { "THR", 3, 1, 0, fmt_thr }, + { "PRI", 3, 1, 0, fmt_pri }, + { "NICE", 4, 1, 0, fmt_nice }, + { "SIZE", 5, 1, 0, fmt_size }, + { "RES", 5, 1, 0, fmt_res }, + { "STATE", 6, 0, 0, fmt_state }, + { "FLG", 3, 0, 84, fmt_flags }, + { "C", 1, 0, 0, fmt_c }, + { "TIME", 6, 1, 0, fmt_time }, + { "CPU", 6, 1, 0, fmt_cpu }, + { "COMMAND", 7, 0, 0, fmt_command }, + { "VCSW", 6, 1, 0, fmt_vcsw }, + { "IVCSW", 6, 1, 0, fmt_ivcsw }, + { "READ", 6, 1, 0, fmt_read }, + { "WRITE", 6, 1, 0, fmt_write }, + { "FAULT", 6, 1, 0, fmt_fault }, + { "TOTAL", 6, 1, 0, fmt_iototal }, + { "PERCENT", 7, 1, 0, fmt_iopct }, + { NULL, 0, 0, 0, NULL } +}; +#define MAX_FIELDS 24 + +static int mode0_display[MAX_FIELDS]; +static int mode0thr_display[MAX_FIELDS]; +static int mode1_display[MAX_FIELDS]; + +int +field_index(char *col) + +{ + struct proc_field *fp; + int i = 0; + + fp = proc_field; + while (fp->name != NULL) + { + if (strcmp(col, fp->name) == 0) + { + return i; + } + fp++; + i++; + } + + return -1; +} + +void +field_subst(int *fp, int old, int new) + +{ + while (*fp != -1) + { + if (*fp == old) + { + *fp = new; + } + fp++; + } +} + +int +machine_init(struct statics *statics) + +{ + int i = 0; + size_t len; + int *ip; + + struct timeval boottime; + + len = sizeof(smpmode); + if ((sysctlbyname("machdep.smp_active", &smpmode, &len, NULL, 0) < 0 && + sysctlbyname("smp.smp_active", &smpmode, &len, NULL, 0) < 0) || + len != sizeof(smpmode)) + { + smpmode = 0; + } + smpmode = smpmode != 0; + + /* kvm_open the active kernel: its okay if this fails */ + kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); + + /* get boot time */ + len = sizeof(boottime); + if (sysctlbyname("kern.boottime", &boottime, &len, NULL, 0) == -1) + { + /* we have no boottime to report */ + boottime.tv_sec = -1; + } + + pbase = NULL; + pref = NULL; + + /* get the page size with "getpagesize" and calculate pageshift from it */ + i = pagesize = getpagesize(); + pageshift = 0; + while (i > 1) + { + pageshift++; + i >>= 1; + } + + /* translate sysctl paths to mibs for faster access */ + get_sysctl_mibs(); + + /* initialize swap stuff */ + swap_init(); + + /* create the hash table that remembers proc data */ + procs = hash_create(2039); + + /* we only need the amount of log(2)1024 for our conversion */ + pageshift -= LOG1024; + + /* fill in the statics information */ + statics->procstate_names = procstatenames; + statics->cpustate_names = cpustatenames; + statics->memory_names = memorynames; + statics->kernel_names = kernelnames; + statics->boottime = boottime.tv_sec; + statics->swap_names = swapnames; + statics->order_names = ordernames; + statics->flags.warmup = 1; + statics->modemax = 2; +#ifdef HAS_SHOWTHREADS + statics->flags.threads = 1; +#endif + + /* we need kvm descriptor in order to show full commands */ + statics->flags.fullcmds = kd != NULL; + + /* set up the display indices for mode0 */ + ip = mode0_display; + *ip++ = field_index("PID"); + *ip++ = field_index("USERNAME"); +#ifdef HAS_THREADS + *ip++ = field_index("THR"); +#endif + *ip++ = field_index("PRI"); + *ip++ = field_index("NICE"); + *ip++ = field_index("SIZE"); + *ip++ = field_index("RES"); + *ip++ = field_index("STATE"); + *ip++ = field_index("FLG"); + if (smpmode) + *ip++ = field_index("C"); + *ip++ = field_index("TIME"); + *ip++ = field_index("CPU"); + *ip++ = field_index("COMMAND"); + *ip = -1; + +#ifdef HAS_SHOWTHREADS + /* set up the display indices for mode0 showing threads */ + ip = mode0thr_display; + *ip++ = field_index("PID"); + *ip++ = field_index("USERNAME"); + *ip++ = field_index("PRI"); + *ip++ = field_index("NICE"); + *ip++ = field_index("SIZE"); + *ip++ = field_index("RES"); + *ip++ = field_index("STATE"); + *ip++ = field_index("FLG"); + if (smpmode) + *ip++ = field_index("C"); + *ip++ = field_index("TIME"); + *ip++ = field_index("CPU"); + *ip++ = field_index("COMMAND"); + *ip = -1; +#endif + + /* set up the display indices for mode1 */ + ip = mode1_display; + *ip++ = field_index("PID"); + *ip++ = field_index("USERNAME"); + *ip++ = field_index("VCSW"); + *ip++ = field_index("IVCSW"); + *ip++ = field_index("READ"); + *ip++ = field_index("WRITE"); + *ip++ = field_index("FAULT"); + *ip++ = field_index("TOTAL"); + *ip++ = field_index("PERCENT"); + *ip++ = field_index("COMMAND"); + *ip = -1; + + /* all done! */ + return(0); +} + +char *format_header(char *uname_field) + +{ + return ""; +} + +void +get_vm_sum(struct vmmeter *sum) + +{ +#define GET_VM_STAT(v, s) (void)get_sysctl(v, &(sum->s), sizeof(sum->s)) + + GET_VM_STAT(V_SWTCH, v_swtch); + GET_VM_STAT(V_TRAP, v_trap); + GET_VM_STAT(V_INTR, v_intr); + GET_VM_STAT(V_SOFT, v_soft); + GET_VM_STAT(V_VFORKS, v_vforks); + GET_VM_STAT(V_FORKS, v_forks); + GET_VM_STAT(V_RFORKS, v_rforks); + GET_VM_STAT(V_VM_FAULTS, v_vm_faults); + GET_VM_STAT(V_SWAPIN, v_swapin); + GET_VM_STAT(V_SWAPOUT, v_swapout); + GET_VM_STAT(V_TFREE, v_tfree); + GET_VM_STAT(V_VNODEIN, v_vnodein); + GET_VM_STAT(V_VNODEOUT, v_vnodeout); + GET_VM_STAT(V_ACTIVE_COUNT, v_active_count); + GET_VM_STAT(V_INACTIVE_COUNT, v_inactive_count); + GET_VM_STAT(V_WIRE_COUNT, v_wire_count); + GET_VM_STAT(V_CACHE_COUNT, v_cache_count); + GET_VM_STAT(V_FREE_COUNT, v_free_count); + GET_VM_STAT(V_SWAPPGSIN, v_swappgsin); + GET_VM_STAT(V_SWAPPGSOUT, v_swappgsout); +} + +void +get_system_info(struct system_info *si) + +{ + long total; + struct timeval thistime; + struct timeval timediff; + + /* timestamp and time difference */ + gettimeofday(&thistime, 0); + timersub(&thistime, &lasttime, &timediff); + elapsed_time = timediff.tv_sec * 1000000 + timediff.tv_usec; + elapsed_msecs = timediff.tv_sec * 1000 + timediff.tv_usec / 1000; + + /* get the load averages */ + if (getloadavg(si->load_avg, NUM_AVERAGES) == -1) + { + /* failed: fill in with zeroes */ + (void) memset(si->load_avg, 0, sizeof(si->load_avg)); + } + + /* get the cp_time array */ + (void)get_sysctl(K_CP_TIME, &cp_time, sizeof(cp_time)); + + /* convert cp_time counts to percentages */ + total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); + + /* sum memory & swap statistics */ + { + struct vmmeter sum; + static unsigned int swap_delay = 0; + static long long swapavail = 0; + static long long swapfree = 0; + static int bufspace = 0; + + get_vm_sum(&sum); + + /* get bufspace */ + bufspace = 0; + (void) get_sysctl(VFS_BUFSPACE, &bufspace, sizeof(bufspace)); + + /* kernel stats */ + dprintf("kernel: swtch %d, trap %d, intr %d, soft %d, vforks %d\n", + sum.v_swtch, sum.v_trap, sum.v_intr, sum.v_soft, sum.v_vforks); + kernel_stats[0] = per_second(sum.v_swtch - ctxsws, elapsed_msecs); + kernel_stats[1] = per_second(sum.v_trap - traps, elapsed_msecs); + kernel_stats[2] = per_second(sum.v_intr - intrs, elapsed_msecs); + kernel_stats[3] = per_second(sum.v_soft - softs, elapsed_msecs); + kernel_stats[4] = per_second(sum.v_vforks + sum.v_forks + + sum.v_rforks - forks, elapsed_msecs); + kernel_stats[5] = per_second(sum.v_vm_faults - pfaults, elapsed_msecs); + kernel_stats[6] = per_second(sum.v_swapin + sum.v_vnodein - pagein, elapsed_msecs); + kernel_stats[7] = per_second(sum.v_swapout + sum.v_vnodeout - pageout, elapsed_msecs); + kernel_stats[8] = per_second(sum.v_tfree - tfreed, elapsed_msecs); + ctxsws = sum.v_swtch; + traps = sum.v_trap; + intrs = sum.v_intr; + softs = sum.v_soft; + forks = (u_int64_t)sum.v_vforks + sum.v_forks + sum.v_rforks; + pfaults = sum.v_vm_faults; + pagein = sum.v_swapin + sum.v_vnodein; + pageout = sum.v_swapout + sum.v_vnodeout; + tfreed = sum.v_tfree; + + /* convert memory stats to Kbytes */ + memory_stats[0] = pagetok(sum.v_active_count); + memory_stats[1] = pagetok(sum.v_inactive_count); + memory_stats[2] = pagetok(sum.v_wire_count); + memory_stats[3] = pagetok(sum.v_cache_count); + memory_stats[4] = bufspace / 1024; + memory_stats[5] = pagetok(sum.v_free_count); + memory_stats[6] = -1; + + /* first interval */ + if (swappgsin < 0) + { + swap_stats[4] = 0; + swap_stats[5] = 0; + } + + /* compute differences between old and new swap statistic */ + else + { + swap_stats[4] = pagetok(sum.v_swappgsin - swappgsin); + swap_stats[5] = pagetok(sum.v_swappgsout - swappgsout); + } + + swappgsin = sum.v_swappgsin; + swappgsout = sum.v_swappgsout; + + /* call CPU heavy swap_getdata() only for changes */ + if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) + { + swap_stats[3] = swap_getdata(&swapavail, &swapfree); + swap_stats[0] = swapavail; + swap_stats[1] = swapavail - swapfree; + swap_stats[2] = swapfree; + } + swap_delay = 1; + swap_stats[6] = -1; + } + + /* set arrays and strings */ + si->cpustates = cpu_states; + si->kernel = kernel_stats; + si->memory = memory_stats; + si->swap = swap_stats; + + si->last_pid = -1; + + lasttime = thistime; +} + +caddr_t +get_process_info(struct system_info *si, + struct process_select *sel, + int compare_index) + +{ + int i; + int total_procs; + int active_procs; + struct kinfo_proc **prefp; + struct kinfo_proc *pp; + struct kinfo_proc *prev_pp = NULL; + struct save_proc *savep; + long proc_io; + pid_t pid; + size_t size; + int nproc; + + /* these are copied out of sel for speed */ + int show_idle; + int show_self; + int show_system; + int show_uid; + char *show_command; + + /* get proc table size and give it a boost */ + nproc = (int)get_sysctlsize(K_PROC) / sizeof(struct kinfo_proc); + nproc += nproc >> 4; + size = nproc * sizeof(struct kinfo_proc); + dprintf("get_process_info: nproc %d, psize %d, size %d\n", nproc, psize, size); + + /* make sure we have enough space allocated */ + if (nproc > psize) + { + /* reallocate both pbase and pref */ + pbase = (struct kinfo_proc *)realloc(pbase, size); + pref = (struct kinfo_proc **)realloc(pref, + sizeof(struct kinfo_proc *) * nproc); + psize = nproc; + } + + /* make sure we got the space we asked for */ + if (pref == NULL || pbase == NULL) + { + /* abandon all hope */ + message_error(" Out of memory!"); + nproc = psize = 0; + si->p_total = 0; + si->p_active = 0; + return NULL; + } + + /* get all process information (threads, too) */ + if (size > 0) + { + nproc = get_sysctl(K_PROC, pbase, size); + if (nproc == -1) + { + nproc = 0; + } + else + { + nproc /= sizeof(struct kinfo_proc); + } + } + + /* get a pointer to the states summary array */ + si->procstates = process_states; + + /* set up flags which define what we are going to select */ + show_idle = sel->idle; + show_self = 0; + show_system = sel->system; + show_uid = sel->uid != -1; + show_fullcmd = sel->fullcmd; + show_command = sel->command; + show_usernames = sel->usernames; + display_mode = sel->mode; +#ifdef HAS_SHOWTHREADS + show_threads = sel->threads; +#endif + + /* count up process states and get pointers to interesting procs */ + total_procs = 0; + active_procs = 0; + total_io = 0; + memset((char *)process_states, 0, sizeof(process_states)); + prefp = pref; + for (pp = pbase, i = 0; i < nproc; pp++, i++) + { + /* + * Place pointers to each valid proc structure in pref[]. + * Process slots that are actually in use have a non-zero + * status field. Processes with P_SYSTEM set are system + * processes---these get ignored unless show_sysprocs is set. + */ + pid = PP(pp, pid); + if (PP(pp, stat) != 0) + { +#ifdef HAS_SHOWTHREADS + int is_thread; + lwpid_t tid; + + /* get thread id */ + tid = PP(pp, tid); + + /* is this just a thread? */ + is_thread = (prev_pp != NULL && PP(prev_pp, pid) == pid); + + /* count this process and its state */ + /* only count threads if we are showing them */ + if (show_threads || !is_thread) + { + total_procs++; + process_states[(unsigned char) PP(pp, stat)]++; + } + + /* grab old data from hash */ + if ((savep = hash_lookup_lwpid(procs, tid)) != NULL) + { + /* verify that this is not a new or different thread */ + /* (freebsd reuses thread ids fairly quickly) */ + /* pids must match and time can't have gone backwards */ + if (pid != savep->sp_pid || PP(pp, runtime) < savep->sp_runtime) + { + /* not the same thread -- reuse the save_proc structure */ + memset(savep, 0, sizeof(struct save_proc)); + savep->sp_pid = pid; + } + } + else + { + /* havent seen this one before */ + savep = (struct save_proc *)calloc(1, sizeof(struct save_proc)); + savep->sp_pid = pid; + hash_add_lwpid(procs, tid, savep); + } + +#else /* !HAS_SHOWTHREADS */ + total_procs++; + process_states[(unsigned char) PP(pp, stat)]++; + + /* grab old data from hash */ + if ((savep = hash_lookup_pid(procs, pid)) == NULL) + { + /* havent seen this one before */ + savep = (struct save_proc *)calloc(1, sizeof(struct save_proc)); + savep->sp_pid = pid; + hash_add_pid(procs, pid, savep); + } +#endif + + /* save the pointer to the sp struct */ + SPPTR(pp) = (void *)savep; + + /* calculate %cpu */ + PPCPU(pp) = ((PP(pp, runtime) - savep->sp_runtime) * 10000) / + elapsed_time; + dprintf("%d (%d): runtime %lld, saved_pid %d, saved_runtime %lld, elapsed_time %d, ppcpu %d\n", + pid, PP(pp, tid), PP(pp, runtime), savep->sp_pid, savep->sp_runtime, + elapsed_time, PPCPU(pp)); + + /* calculate io differences */ + proc_io = 0; + savep->sp_vcsw = (RP(pp, nvcsw) - savep->sp_old_nvcsw); + savep->sp_ivcsw = (RP(pp, nivcsw) - savep->sp_old_nivcsw); + proc_io += (savep->sp_inblock = (RP(pp, inblock) - savep->sp_old_inblock)); + proc_io += (savep->sp_oublock = (RP(pp, oublock) - savep->sp_old_oublock)); + proc_io += (savep->sp_majflt = (RP(pp, majflt) - savep->sp_old_majflt)); + total_io += proc_io; + savep->sp_totalio = proc_io; + + /* save data for next time */ + savep->sp_runtime = PP(pp, runtime); + savep->sp_old_nvcsw = RP(pp, nvcsw); + savep->sp_old_nivcsw = RP(pp, nivcsw); + savep->sp_old_inblock = RP(pp, inblock); + savep->sp_old_oublock = RP(pp, oublock); + savep->sp_old_majflt = RP(pp, majflt); + + /* is this one selected for viewing? */ + if ((PP(pp, stat) != SZOMB) && + (show_system || ((PP(pp, flag) & P_SYSTEM) == 0)) && + (show_idle || (PP(pp, pctcpu) != 0) || + (PP(pp, stat) == SRUN)) && + (!show_uid || PRUID(pp) == (uid_t)sel->uid) && + (show_command == NULL || + strcasestr(PP(pp, comm), show_command) != NULL)) + { +#ifdef HAS_SHOWTHREADS + /* yes, but make sure it isn't just a thread */ + if (show_threads || !is_thread) + { + /* we will be showing this thread */ + *prefp++ = pp; + active_procs++; + } + else + { + /* we will not be showing this thread, but we need to roll + up its cpu usage in to its process */ + PP(prev_pp, pctcpu) += PP(pp, pctcpu); + } +#else /* !HAS_SHOWTHREADS */ + /* we will be showing this process */ + *prefp++ = pp; + active_procs++; +#endif + } + prev_pp = pp; + } + } + + dprintf("total_io: %d\n", total_io); + if (total_io == 0) total_io = 1; + + /* if requested, sort the "interesting" processes */ + if (active_procs > 1) + { + qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), + proc_compares[compare_index]); + } + + /* remember active and total counts */ + si->p_total = total_procs; + si->p_active = pref_len = active_procs; + + /* pass back a handle */ + handle.next_proc = pref; + handle.remaining = active_procs; + return((caddr_t)&handle); +} + +static char p_header[MAX_COLS]; + +char * +format_process_header(struct process_select *sel, caddr_t handle, int count) + +{ + int cols; + int n; + int w; + char *p; + int *fi; + struct kinfo_proc **kip; + struct proc_field *fp; + + /* check for null handle */ + if (handle == NULL) + { + return(""); + } + + /* remember how many columns there are on the display */ + cols = display_columns(); + + /* mode & threads dictate format */ + fi = display_fields = + sel->mode == 0 ? + (sel->threads == 0 ? mode0_display : mode0thr_display) : + mode1_display; + + /* set username field correctly */ + if (!sel->usernames) + { + /* display uids */ + field_subst(fi, FIELD_USERNAME, FIELD_UID); + } + else + { + /* display usernames */ + field_subst(fi, FIELD_UID, FIELD_USERNAME); + + /* we also need to determine the longest username for column width */ + /* calculate namelength from first "count" processes */ + kip = ((struct handle *)handle)->next_proc; + n = ((struct handle *)handle)->remaining; + if (n > count) + n = count; + namelength = 0; + while (n-- > 0) + { + w = strlen(username(PRUID(*kip))); + if (w > namelength) namelength = w; + kip++; + } + dprintf("format_process_header: namelength %d\n", namelength); + + /* place it in bounds */ + if (namelength < 8) + { + namelength = 8; + } + + /* set the column width */ + proc_field[FIELD_USERNAME].width = username_length = namelength; + } + + /* walk thru fields and construct header */ + /* are we worried about overflow??? */ + p = p_header; + while (*fi != -1) + { + fp = &(proc_field[*fi++]); + if (fp->min_screenwidth <= cols) + { + p += sprintf(p, fp->rjust ? "%*s" : "%-*s", fp->width, fp->name); + *p++ = ' '; + } + } + *--p = '\0'; + + return p_header; +} + +static char fmt[MAX_COLS]; /* static area where result is built */ + +char * +format_next_process(caddr_t handle, char *(*get_userid)(int)) + +{ + struct kinfo_proc *pp; + struct handle *hp; + struct proc_field *fp; + int *fi; + int i; + int cols; + char *p; + int len; + int x; + + /* find and remember the next proc structure */ + hp = (struct handle *)handle; + pp = *(hp->next_proc++); + hp->remaining--; + + /* mode & threads dictate format */ + fi = display_fields; + + /* screen width is a consideration, too */ + cols = display_columns(); + + /* build output by field */ + p = fmt; + len = MAX_COLS; + while ((i = *fi++) != -1) + { + fp = &(proc_field[i]); + if (len > 0 && fp->min_screenwidth <= cols) + { + x = (*(fp->format))(p, len, pp); + if (x >= len) + { + dprintf("format_next_process: formatter overflow: x %d, len %d, p %08x => %08x, fmt %08x - %08x\n", + x, len, p, p + len, fmt, fmt + sizeof(fmt)); + p += len; + len = 0; + } + else + { + p += x; + *p++ = ' '; + len -= x + 1; + } + } + } + *--p = '\0'; + + /* return the result */ + return(fmt); +} + +/* comparison routines for qsort */ + +/* + * proc_compare - comparison function for "qsort" + * Compares the resource consumption of two processes using five + * distinct keys. The keys (in descending order of importance) are: + * percent cpu, cpu ticks, state, resident set size, total virtual + * memory usage. The process states are ordered as follows (from least + * to most important): WAIT, zombie, sleep, stop, start, run. The + * array declaration below maps a process state index into a number + * that reflects this ordering. + */ + +static unsigned char sorted_state[] = +{ + 0, /* not used */ + 3, /* sleep */ + 1, /* ABANDONED (WAIT) */ + 6, /* run */ + 5, /* start */ + 2, /* zombie */ + 4 /* stop */ +}; + + +#define ORDERKEY_PCTCPU \ + if (lresult = (long) PPCPU(p2) - (long) PPCPU(p1), \ + (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) + +#define ORDERKEY_CPTICKS \ + if ((result = PP(p2, runtime) > PP(p1, runtime) ? 1 : \ + PP(p2, runtime) < PP(p1, runtime) ? -1 : 0) == 0) + +#define ORDERKEY_STATE \ + if ((result = sorted_state[(unsigned char) PP(p2, stat)] - \ + sorted_state[(unsigned char) PP(p1, stat)]) == 0) + +#if OSMAJOR <= 4 +#define ORDERKEY_PRIO \ + if ((result = PP(p2, priority) - PP(p1, priority)) == 0) +#else +#define ORDERKEY_PRIO \ + if ((result = PP(p2, pri.pri_level) - PP(p1, pri.pri_level)) == 0) +#endif + +#define ORDERKEY_RSSIZE \ + if ((result = VP(p2, rssize) - VP(p1, rssize)) == 0) + +#define ORDERKEY_MEM \ + if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 ) + +#define ORDERKEY_IO \ + if ( (result = SP(p2, totalio) - SP(p1, totalio)) == 0) + +#define ORDERKEY_PID \ + if ( (result = PP(p1, pid) - PP(p2, pid)) == 0) + +/* compare_cpu - the comparison function for sorting by cpu percentage */ + +int +proc_compare(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + pctcpu lresult; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_PCTCPU + ORDERKEY_CPTICKS + ORDERKEY_STATE + ORDERKEY_PRIO + ORDERKEY_RSSIZE + ORDERKEY_MEM + ; + + return(result); +} + +/* compare_size - the comparison function for sorting by total memory usage */ + +int +compare_size(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + pctcpu lresult; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_MEM + ORDERKEY_RSSIZE + ORDERKEY_PCTCPU + ORDERKEY_CPTICKS + ORDERKEY_STATE + ORDERKEY_PRIO + ; + + return(result); +} + +/* compare_res - the comparison function for sorting by resident set size */ + +int +compare_res(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + pctcpu lresult; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_RSSIZE + ORDERKEY_MEM + ORDERKEY_PCTCPU + ORDERKEY_CPTICKS + ORDERKEY_STATE + ORDERKEY_PRIO + ; + + return(result); +} + +/* compare_time - the comparison function for sorting by total cpu time */ + +int +compare_time(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + pctcpu lresult; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_CPTICKS + ORDERKEY_PCTCPU + ORDERKEY_STATE + ORDERKEY_PRIO + ORDERKEY_RSSIZE + ORDERKEY_MEM + ; + + return(result); + } + +/* compare_prio - the comparison function for sorting by priority */ + +int +compare_prio(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + pctcpu lresult; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_PRIO + ORDERKEY_CPTICKS + ORDERKEY_PCTCPU + ORDERKEY_STATE + ORDERKEY_RSSIZE + ORDERKEY_MEM + ; + + return(result); +} + +/* compare_io - the comparison function for sorting by io count */ + +int +compare_io(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + pctcpu lresult; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_IO + ORDERKEY_PCTCPU + ORDERKEY_CPTICKS + ORDERKEY_STATE + ORDERKEY_PRIO + ORDERKEY_RSSIZE + ORDERKEY_MEM + ; + + return(result); +} + +/* compare_pid - the comparison function for sorting by process id */ + +int +compare_pid(struct proc **pp1, struct proc **pp2) + +{ + struct kinfo_proc *p1; + struct kinfo_proc *p2; + int result; + + /* remove one level of indirection */ + p1 = *(struct kinfo_proc **) pp1; + p2 = *(struct kinfo_proc **) pp2; + + ORDERKEY_PID + ; + + return(result); +} + +/* + * proc_owner(pid) - returns the uid that owns process "pid", or -1 if + * the process does not exist. + * It is EXTREMLY IMPORTANT that this function work correctly. + * If top runs setuid root (as in SVR4), then this function + * is the only thing that stands in the way of a serious + * security problem. It validates requests for the "kill" + * and "renice" commands. + */ + +int +proc_owner(int pid) + +{ + int cnt; + struct kinfo_proc **prefp; + struct kinfo_proc *pp; + + prefp = pref; + cnt = pref_len; + while (--cnt >= 0) + { + pp = *prefp++; + if (PP(pp, pid) == (pid_t)pid) + { + return((int)PRUID(pp)); + } + } + return(-1); +} + |