/* * top - a top users display for Unix * * SYNOPSIS: For FreeBSD-2.x and later * * 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 (for latest top see http://www.groupsys.com/topinfo/) * * This is the machine-dependent module for FreeBSD 2.2 * Works for: * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x * * LIBS: -lkvm * * AUTHOR: Christos Zoulas * Steven Wallace * Wolfram Schneider * Thomas Moestl * * $FreeBSD: head/usr.bin/top/machine.c 131623 2004-07-05 13:12:16Z des $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "top.h" #include "machine.h" #include "screen.h" #include "utils.h" static void getsysctl(char *, void *, size_t); #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) extern char* printable(char *); int swapmode(int *retavail, int *retfree); static int smpmode; enum displaymodes displaymode; static int namelength; static int cmdlengthdelta; /* Prototypes for top internals */ void quit(int); int compare_pid(const void *a, const void *b); /* 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" /* define what weighted cpu is. */ #define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) /* what we consider to be process size: */ #define PROCSIZE(pp) ((pp)->ki_size / 1024) #define RU(pp) (&(pp)->ki_rusage) #define RUTOT(pp) \ (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) /* definitions for indices in the nlist array */ /* * These definitions control the format of the per-process area */ static char io_header[] = " PID %-*.*s READ WRITE FAULT TOTAL PERCENT COMMAND"; #define io_Proc_format \ "%5d %-*.*s %6d %6d %6d %6d %6.2f%% %.*s" static char smp_header[] = " PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND"; #define smp_Proc_format \ "%5d %-*.*s %3d %4d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s" static char up_header[] = " PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; #define up_Proc_format \ "%5d %-*.*s %3d %4d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s" /* 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\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" }; static kvm_t *kd; /* values that we stash away in _init and use in later routines */ static double logcpu; /* these are retrieved from the kernel in _init */ static load_avg ccpu; /* these are used in the get_ functions */ static int lastpid; /* 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, ", " lock, ", 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 memory statistics */ int memory_stats[7]; char *memorynames[] = { /* 0 1 2 3 4 5 */ "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", NULL }; int swap_stats[7]; char *swapnames[] = { /* 0 1 2 3 4 5 */ "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", NULL }; /* these are for keeping track of the proc array */ static int nproc; static int onproc = -1; static int pref_len; static struct kinfo_proc *pbase; static struct kinfo_proc **pref; static struct kinfo_proc *previous_procs; static struct kinfo_proc **previous_pref; static int previous_proc_count = 0; static int previous_proc_count_max = 0; /* total number of io operations */ static long total_inblock; static long total_oublock; static long total_majflt; /* these are for getting the memory statistics */ static int pageshift; /* log base 2 of the pagesize */ /* define pagetok in terms of pageshift */ #define pagetok(size) ((size) << pageshift) /* useful externals */ long percentages(); #ifdef ORDER /* sorting orders. first is default */ char *ordernames[] = { "cpu", "size", "res", "time", "pri", NULL }; #endif int machine_init(struct statics *statics) { int pagesize; size_t modelen; struct passwd *pw; modelen = sizeof(smpmode); if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 && sysctlbyname("kern.smp.active", &smpmode, &modelen, NULL, 0) < 0) || modelen != sizeof(smpmode)) smpmode = 0; while ((pw = getpwent()) != NULL) { if (strlen(pw->pw_name) > namelength) namelength = strlen(pw->pw_name); } if (namelength < 8) namelength = 8; if (smpmode && namelength > 13) namelength = 13; else if (namelength > 15) namelength = 15; if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null", O_RDONLY, "kvm_open")) == NULL) return -1; GETSYSCTL("kern.ccpu", ccpu); /* this is used in calculating WCPU -- calculate it ahead of time */ logcpu = log(loaddouble(ccpu)); pbase = NULL; pref = NULL; nproc = 0; onproc = -1; /* get the page size with "getpagesize" and calculate pageshift from it */ pagesize = getpagesize(); pageshift = 0; while (pagesize > 1) { pageshift++; pagesize >>= 1; } /* 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->swap_names = swapnames; #ifdef ORDER statics->order_names = ordernames; #endif /* all done! */ return (0); } char * format_header(char *uname_field) { static char Header[128]; const char *prehead; switch (displaymode) { case DISP_CPU: prehead = smpmode ? smp_header : up_header; break; case DISP_IO: prehead = io_header; break; } snprintf(Header, sizeof(Header), prehead, namelength, namelength, uname_field); cmdlengthdelta = strlen(Header) - 7; return (Header); } static int swappgsin = -1; static int swappgsout = -1; extern struct timeval timeout; void get_system_info(struct system_info *si) { long total; struct loadavg sysload; int mib[2]; struct timeval boottime; size_t bt_size; /* get the cp_time array */ GETSYSCTL("kern.cp_time", cp_time); GETSYSCTL("vm.loadavg", sysload); GETSYSCTL("kern.lastpid", lastpid); /* convert load averages to doubles */ { int i; double *infoloadp; infoloadp = si->load_avg; for (i = 0; i < 3; i++) { #ifdef notyet *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; #endif *infoloadp++ = loaddouble(sysload.ldavg[i]); } } /* convert cp_time counts to percentages */ total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); /* sum memory & swap statistics */ { static unsigned int swap_delay = 0; static int swapavail = 0; static int swapfree = 0; static int bufspace = 0; static int nspgsin, nspgsout; GETSYSCTL("vfs.bufspace", bufspace); GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); /* convert memory stats to Kbytes */ memory_stats[0] = pagetok(memory_stats[0]); memory_stats[1] = pagetok(memory_stats[1]); memory_stats[2] = pagetok(memory_stats[2]); memory_stats[3] = pagetok(memory_stats[3]); memory_stats[4] = bufspace / 1024; memory_stats[5] = pagetok(memory_stats[5]); 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(((nspgsin - swappgsin))); swap_stats[5] = pagetok(((nspgsout - swappgsout))); } swappgsin = nspgsin; swappgsout = nspgsout; /* call CPU heavy swapmode() only for changes */ if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { swap_stats[3] = swapmode(&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->memory = memory_stats; si->swap = swap_stats; if (lastpid > 0) { si->last_pid = lastpid; } else { si->last_pid = -1; } /* * Print how long system has been up. * (Found by looking getting "boottime" from the kernel) */ mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; bt_size = sizeof(boottime); if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && boottime.tv_sec != 0) { si->boottime = boottime; } else { si->boottime.tv_sec = -1; } } const struct kinfo_proc * get_old_proc(struct kinfo_proc *pp) { struct kinfo_proc **oldpp, *oldp; if (previous_proc_count == 0) return (NULL); oldpp = bsearch(&pp, previous_pref, previous_proc_count, sizeof(struct kinfo_proc *), compare_pid); if (oldpp == NULL) return (NULL); oldp = *oldpp; if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) return (NULL); return (oldp); } long get_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp) { const struct kinfo_proc *oldp; static struct kinfo_proc dummy; long ret; oldp = get_old_proc(pp); if (oldp == NULL) { bzero(&dummy, sizeof(dummy)); oldp = &dummy; } *inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; *oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; *flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; ret = (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) + (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) + (RU(pp)->ru_majflt - RU(oldp)->ru_majflt); return (ret); } long get_io_total(struct kinfo_proc *pp) { long dummy; return (get_io_stats(pp, &dummy, &dummy, &dummy)); } static struct handle handle; caddr_t get_process_info(struct system_info *si, struct process_select *sel, int (*compare)()) { int i; int total_procs; long p_io; long p_inblock, p_oublock, p_majflt; int active_procs; struct kinfo_proc **prefp; struct kinfo_proc *pp; struct kinfo_proc *prev_pp = NULL; /* these are copied out of sel for speed */ int show_idle; int show_self; int show_system; int show_uid; int show_command; /* * Save the previous process info. */ if (previous_proc_count_max < nproc) { free(previous_procs); previous_procs = malloc(nproc * sizeof(struct kinfo_proc)); free(previous_pref); previous_pref = malloc(nproc * sizeof(struct kinfo_proc *)); if (previous_procs == NULL || previous_pref == NULL) { (void) fprintf(stderr, "top: Out of memory.\n"); quit(23); } previous_proc_count_max = nproc; } if (nproc) { for (i = 0; i < nproc; i++) previous_pref[i] = &previous_procs[i]; bcopy(pbase, previous_procs, nproc * sizeof(struct kinfo_proc)); qsort(previous_pref, nproc, sizeof(struct kinfo_proc *), compare_pid); } previous_proc_count = nproc; pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); if (nproc > onproc) pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) * (onproc = nproc)); if (pref == NULL || pbase == NULL) { (void) fprintf(stderr, "top: Out of memory.\n"); quit(23); } /* 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 = sel->self; show_system = sel->system; show_uid = sel->uid != -1; show_command = sel->command != NULL; /* count up process states and get pointers to interesting procs */ total_procs = 0; active_procs = 0; total_inblock = 0; total_oublock = 0; total_majflt = 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[]. */ if (pp->ki_stat == 0) /* not in use */ continue; if (!show_self && pp->ki_pid == sel->self) /* skip self */ continue; if (!show_system && (pp->ki_flag & P_SYSTEM)) /* skip system process */ continue; p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt); total_inblock += p_inblock; total_oublock += p_oublock; total_majflt += p_majflt; total_procs++; process_states[(unsigned char) pp->ki_stat]++; if (pp->ki_stat == SZOMB) /* skip zombies */ continue; if (displaymode == DISP_CPU && !show_idle && (pp->ki_pctcpu == 0 || pp->ki_stat != SRUN)) /* skip idle or non-running processes */ continue; if (displaymode == DISP_IO && !show_idle && p_io == 0) /* skip processes that aren't doing I/O */ continue; if (show_uid && pp->ki_ruid != (uid_t)sel->uid) /* skip processes which don't belong to the selected UID */ continue; /* * When not showing threads, take the first thread * for output and add the fields that we can from * the rest of the process's threads rather than * using the system's mostly-broken KERN_PROC_PROC. */ if (sel->thread || prev_pp == NULL || prev_pp->ki_pid != pp->ki_pid) { *prefp++ = pp; active_procs++; prev_pp = pp; } else { prev_pp->ki_pctcpu += pp->ki_pctcpu; } } /* if requested, sort the "interesting" processes */ if (compare != NULL) { qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare); } /* 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); } char fmt[128]; /* static area where result is built */ char * format_next_process(caddr_t handle, char *(*get_userid)()) { struct kinfo_proc *pp; const struct kinfo_proc *oldp; long cputime; double pct; struct handle *hp; char status[16]; int state; struct rusage ru, *rup; long p_tot, s_tot; /* find and remember the next proc structure */ hp = (struct handle *)handle; pp = *(hp->next_proc++); hp->remaining--; /* get the process's command name */ if ((pp->ki_sflag & PS_INMEM) == 0) { /* * Print swapped processes as */ char *comm = pp->ki_comm; #define COMSIZ sizeof(pp->ki_comm) char buf[COMSIZ]; (void) strncpy(buf, comm, COMSIZ); comm[0] = '<'; (void) strncpy(&comm[1], buf, COMSIZ - 2); comm[COMSIZ - 2] = '\0'; (void) strncat(comm, ">", COMSIZ - 1); comm[COMSIZ - 1] = '\0'; } /* * Convert the process's runtime from microseconds to seconds. This * time includes the interrupt time although that is not wanted here. * ps(1) is similarly sloppy. */ cputime = (pp->ki_runtime + 500000) / 1000000; /* calculate the base for cpu percentages */ pct = pctdouble(pp->ki_pctcpu); /* generate "STATE" field */ switch (state = pp->ki_stat) { case SRUN: if (smpmode && pp->ki_oncpu != 0xff) sprintf(status, "CPU%d", pp->ki_oncpu); else strcpy(status, "RUN"); break; case SLOCK: if (pp->ki_kiflag & KI_LOCKBLOCK) { sprintf(status, "*%.6s", pp->ki_lockname); break; } /* fall through */ case SSLEEP: if (pp->ki_wmesg != NULL) { sprintf(status, "%.6s", pp->ki_wmesg); break; } /* FALLTHROUGH */ default: if (state >= 0 && state < sizeof(state_abbrev) / sizeof(*state_abbrev)) sprintf(status, "%.6s", state_abbrev[(unsigned char) state]); else sprintf(status, "?%5d", state); break; } if (displaymode == DISP_IO) { oldp = get_old_proc(pp); if (oldp != NULL) { ru.ru_inblock = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; ru.ru_oublock = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; rup = &ru; } else { rup = RU(pp); } p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt; s_tot = total_inblock + total_oublock + total_majflt; sprintf(fmt, io_Proc_format, pp->ki_pid, namelength, namelength, (*get_userid)(pp->ki_ruid), (int)rup->ru_inblock, (int)rup->ru_oublock, (int)rup->ru_majflt, (int)p_tot, p_tot == 0 ? 0.0 : ((float)(p_tot * 100))/(float)s_tot, screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, printable(pp->ki_comm)); return (fmt); } /* format this entry */ sprintf(fmt, smpmode ? smp_Proc_format : up_Proc_format, pp->ki_pid, namelength, namelength, (*get_userid)(pp->ki_ruid), pp->ki_pri.pri_level - PZERO, /* * normal time -> nice value -20 - +20 * real time 0 - 31 -> nice value -52 - -21 * idle time 0 - 31 -> nice value +21 - +52 */ (pp->ki_pri.pri_class == PRI_TIMESHARE ? pp->ki_nice - NZERO : (PRI_IS_REALTIME(pp->ki_pri.pri_class) ? (PRIO_MIN - 1 - (PRI_MAX_REALTIME - pp->ki_pri.pri_level)) : (PRIO_MAX + 1 + pp->ki_pri.pri_level - PRI_MIN_IDLE))), format_k2(PROCSIZE(pp)), format_k2(pagetok(pp->ki_rssize)), status, smpmode ? pp->ki_lastcpu : 0, format_time(cputime), 100.0 * weighted_cpu(pct, pp), 100.0 * pct, screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, printable(pp->ki_comm)); /* return the result */ return (fmt); } static void getsysctl(char *name, void *ptr, size_t len) { size_t nlen = len; if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, strerror(errno)); quit(23); } if (nlen != len) { fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", name, (unsigned long)len, (unsigned long)nlen); quit(23); } } /* comparison routines for qsort */ int compare_pid(const void *p1, const void *p2) { const struct kinfo_proc * const *pp1 = p1; const struct kinfo_proc * const *pp2 = p2; if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0) abort(); return ((*pp1)->ki_pid - (*pp2)->ki_pid); } /* * 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) p2->ki_pctcpu - (long) p1->ki_pctcpu, \ (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) #define ORDERKEY_CPTICKS \ if ((result = p2->ki_runtime > p1->ki_runtime ? 1 : \ p2->ki_runtime < p1->ki_runtime ? -1 : 0) == 0) #define ORDERKEY_STATE \ if ((result = sorted_state[(unsigned char) p2->ki_stat] - \ sorted_state[(unsigned char) p1->ki_stat]) == 0) #define ORDERKEY_PRIO \ if ((result = p2->ki_pri.pri_level - p1->ki_pri.pri_level) == 0) #define ORDERKEY_RSSIZE \ if ((result = p2->ki_rssize - p1->ki_rssize) == 0) #define ORDERKEY_MEM \ if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 ) /* compare_cpu - the comparison function for sorting by cpu percentage */ int #ifdef ORDER compare_cpu(struct proc **pp1, struct proc **pp2) #else proc_compare(struct proc **pp1, struct proc **pp2) #endif { 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); } #ifdef ORDER /* compare routines */ int compare_size(), compare_res(), compare_time(), compare_prio(); int (*proc_compares[])() = { compare_cpu, compare_size, compare_res, compare_time, compare_prio, NULL }; /* 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 cpu percentage */ 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); } #endif int io_compare(struct proc **pp1, struct proc **pp2) { long t1, t2; t1 = get_io_total((struct kinfo_proc *)*pp1); t2 = get_io_total((struct kinfo_proc *)*pp2); return (t2 - t1); } /* * 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->ki_pid == (pid_t)pid) { return ((int)pp->ki_ruid); } } return (-1); } int swapmode(int *retavail, int *retfree) { int n; int pagesize = getpagesize(); struct kvm_swap swapary[1]; *retavail = 0; *retfree = 0; #define CONVERT(v) ((quad_t)(v) * pagesize / 1024) n = kvm_getswapinfo(kd, swapary, 1, 0); if (n < 0 || swapary[0].ksw_total == 0) return (0); *retavail = CONVERT(swapary[0].ksw_total); *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); n = (int)((double)swapary[0].ksw_used * 100.0 / (double)swapary[0].ksw_total); return (n); }