machine.c revision 47901
124143Sjoerg/* 224143Sjoerg * top - a top users display for Unix 324143Sjoerg * 447901Sn_hibma * SYNOPSIS: For FreeBSD-2.x and later 524143Sjoerg * 624143Sjoerg * DESCRIPTION: 724143Sjoerg * Originally written for BSD4.4 system by Christos Zoulas. 824143Sjoerg * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider 938278Swosch * Order support hacked in from top-3.5beta6/machine/m_aix41.c 1038278Swosch * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) 1124143Sjoerg * 1224143Sjoerg * This is the machine-dependent module for FreeBSD 2.2 1324143Sjoerg * Works for: 1447901Sn_hibma * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x 1524143Sjoerg * 1624143Sjoerg * LIBS: -lkvm 1724143Sjoerg * 1824143Sjoerg * AUTHOR: Christos Zoulas <christos@ee.cornell.edu> 1924143Sjoerg * Steven Wallace <swallace@freebsd.org> 2024143Sjoerg * Wolfram Schneider <wosch@FreeBSD.org> 2124143Sjoerg * 2247901Sn_hibma * $Id: machine.c,v 1.25 1999/05/11 14:32:15 peter Exp $ 2324143Sjoerg */ 2424143Sjoerg 2524143Sjoerg 2642447Sobrien#include <sys/time.h> 2724143Sjoerg#include <sys/types.h> 2824143Sjoerg#include <sys/signal.h> 2924143Sjoerg#include <sys/param.h> 3024143Sjoerg 3124143Sjoerg#include "os.h" 3224143Sjoerg#include <stdio.h> 3324143Sjoerg#include <nlist.h> 3424143Sjoerg#include <math.h> 3524143Sjoerg#include <kvm.h> 3627390Speter#include <pwd.h> 3724143Sjoerg#include <sys/errno.h> 3824143Sjoerg#include <sys/sysctl.h> 3924143Sjoerg#include <sys/dkstat.h> 4024143Sjoerg#include <sys/file.h> 4124143Sjoerg#include <sys/time.h> 4224143Sjoerg#include <sys/proc.h> 4324143Sjoerg#include <sys/user.h> 4424143Sjoerg#include <sys/vmmeter.h> 4529904Speter#include <sys/resource.h> 4629904Speter#include <sys/rtprio.h> 4724143Sjoerg 4824143Sjoerg/* Swap */ 4924143Sjoerg#include <stdlib.h> 5024143Sjoerg#include <sys/conf.h> 5124143Sjoerg 5224143Sjoerg#include <osreldate.h> /* for changes in kernel structures */ 5324143Sjoerg 5424143Sjoerg#include "top.h" 5524143Sjoerg#include "machine.h" 5624143Sjoerg 5724143Sjoergstatic int check_nlist __P((struct nlist *)); 5824143Sjoergstatic int getkval __P((unsigned long, int *, int, char *)); 5924143Sjoergextern char* printable __P((char *)); 6024143Sjoergint swapmode __P((int *retavail, int *retfree)); 6127340Speterstatic int smpmode; 6227390Speterstatic int namelength; 6327390Speterstatic int cmdlength; 6424143Sjoerg 6524143Sjoerg 6624143Sjoerg/* get_process_info passes back a handle. This is what it looks like: */ 6724143Sjoerg 6824143Sjoergstruct handle 6924143Sjoerg{ 7024143Sjoerg struct kinfo_proc **next_proc; /* points to next valid proc pointer */ 7124143Sjoerg int remaining; /* number of pointers remaining */ 7224143Sjoerg}; 7324143Sjoerg 7424143Sjoerg/* declarations for load_avg */ 7524143Sjoerg#include "loadavg.h" 7624143Sjoerg 7724143Sjoerg#define PP(pp, field) ((pp)->kp_proc . field) 7824143Sjoerg#define EP(pp, field) ((pp)->kp_eproc . field) 7924143Sjoerg#define VP(pp, field) ((pp)->kp_eproc.e_vm . field) 8024143Sjoerg 8124143Sjoerg/* define what weighted cpu is. */ 8224143Sjoerg#define weighted_cpu(pct, pp) (PP((pp), p_swtime) == 0 ? 0.0 : \ 8324143Sjoerg ((pct) / (1.0 - exp(PP((pp), p_swtime) * logcpu)))) 8424143Sjoerg 8524143Sjoerg/* what we consider to be process size: */ 8637100Sdt#define PROCSIZE(pp) (VP((pp), vm_map.size) / 1024) 8724143Sjoerg 8824143Sjoerg/* definitions for indices in the nlist array */ 8924143Sjoerg 9024143Sjoergstatic struct nlist nlst[] = { 9124143Sjoerg#define X_CCPU 0 9241358Sbde { "_ccpu" }, 9324143Sjoerg#define X_CP_TIME 1 9441358Sbde { "_cp_time" }, 9541358Sbde#define X_AVENRUN 2 9641358Sbde { "_averunnable" }, 9724143Sjoerg 9843053Sdillon#define X_BUFSPACE 3 9924143Sjoerg { "_bufspace" }, /* K in buffer cache */ 10043053Sdillon#define X_CNT 4 10124143Sjoerg { "_cnt" }, /* struct vmmeter cnt */ 10224143Sjoerg 10324143Sjoerg/* Last pid */ 10443053Sdillon#define X_LASTPID 5 10524143Sjoerg { "_nextpid" }, 10624143Sjoerg { 0 } 10724143Sjoerg}; 10824143Sjoerg 10924143Sjoerg/* 11024143Sjoerg * These definitions control the format of the per-process area 11124143Sjoerg */ 11224143Sjoerg 11327340Speterstatic char smp_header[] = 11430130Sfsmp " PID %-*.*s PRI NICE SIZE RES STATE C TIME WCPU CPU COMMAND"; 11524143Sjoerg 11627340Speter#define smp_Proc_format \ 11730130Sfsmp "%5d %-*.*s %3d %3d%7s %6s %-6.6s %1x%7s %5.2f%% %5.2f%% %.*s" 11824143Sjoerg 11927340Speterstatic char up_header[] = 12027390Speter " PID %-*.*s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; 12124143Sjoerg 12227340Speter#define up_Proc_format \ 12327390Speter "%5d %-*.*s %3d %3d%7s %6s %-6.6s%.0d%7s %5.2f%% %5.2f%% %.*s" 12424143Sjoerg 12524143Sjoerg 12624143Sjoerg 12724143Sjoerg/* process state names for the "STATE" column of the display */ 12824143Sjoerg/* the extra nulls in the string "run" are for adding a slash and 12924143Sjoerg the processor number when needed */ 13024143Sjoerg 13124143Sjoergchar *state_abbrev[] = 13224143Sjoerg{ 13324143Sjoerg "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", 13424143Sjoerg}; 13524143Sjoerg 13624143Sjoerg 13724143Sjoergstatic kvm_t *kd; 13824143Sjoerg 13924143Sjoerg/* values that we stash away in _init and use in later routines */ 14024143Sjoerg 14124143Sjoergstatic double logcpu; 14224143Sjoerg 14324143Sjoerg/* these are retrieved from the kernel in _init */ 14424143Sjoerg 14524143Sjoergstatic load_avg ccpu; 14624143Sjoerg 14724143Sjoerg/* these are offsets obtained via nlist and used in the get_ functions */ 14824143Sjoerg 14924143Sjoergstatic unsigned long cp_time_offset; 15024143Sjoergstatic unsigned long avenrun_offset; 15124143Sjoergstatic unsigned long lastpid_offset; 15224143Sjoergstatic long lastpid; 15324143Sjoergstatic unsigned long cnt_offset; 15424143Sjoergstatic unsigned long bufspace_offset; 15524143Sjoergstatic long cnt; 15624143Sjoerg 15724143Sjoerg/* these are for calculating cpu state percentages */ 15824143Sjoerg 15924143Sjoergstatic long cp_time[CPUSTATES]; 16024143Sjoergstatic long cp_old[CPUSTATES]; 16124143Sjoergstatic long cp_diff[CPUSTATES]; 16224143Sjoerg 16324143Sjoerg/* these are for detailing the process states */ 16424143Sjoerg 16524143Sjoergint process_states[6]; 16624143Sjoergchar *procstatenames[] = { 16724143Sjoerg "", " starting, ", " running, ", " sleeping, ", " stopped, ", 16824143Sjoerg " zombie, ", 16924143Sjoerg NULL 17024143Sjoerg}; 17124143Sjoerg 17224143Sjoerg/* these are for detailing the cpu states */ 17324143Sjoerg 17424143Sjoergint cpu_states[CPUSTATES]; 17524143Sjoergchar *cpustatenames[] = { 17624143Sjoerg "user", "nice", "system", "interrupt", "idle", NULL 17724143Sjoerg}; 17824143Sjoerg 17924143Sjoerg/* these are for detailing the memory statistics */ 18024143Sjoerg 18124143Sjoergint memory_stats[7]; 18224143Sjoergchar *memorynames[] = { 18324143Sjoerg "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", "K Free", 18424143Sjoerg NULL 18524143Sjoerg}; 18624143Sjoerg 18724143Sjoergint swap_stats[7]; 18824143Sjoergchar *swapnames[] = { 18924143Sjoerg/* 0 1 2 3 4 5 */ 19024143Sjoerg "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", 19124143Sjoerg NULL 19224143Sjoerg}; 19324143Sjoerg 19424143Sjoerg 19524143Sjoerg/* these are for keeping track of the proc array */ 19624143Sjoerg 19724143Sjoergstatic int nproc; 19824143Sjoergstatic int onproc = -1; 19924143Sjoergstatic int pref_len; 20024143Sjoergstatic struct kinfo_proc *pbase; 20124143Sjoergstatic struct kinfo_proc **pref; 20224143Sjoerg 20324143Sjoerg/* these are for getting the memory statistics */ 20424143Sjoerg 20524143Sjoergstatic int pageshift; /* log base 2 of the pagesize */ 20624143Sjoerg 20724143Sjoerg/* define pagetok in terms of pageshift */ 20824143Sjoerg 20924143Sjoerg#define pagetok(size) ((size) << pageshift) 21024143Sjoerg 21124143Sjoerg/* useful externals */ 21224143Sjoerglong percentages(); 21324143Sjoerg 21438278Swosch#ifdef ORDER 21538278Swosch/* sorting orders. first is default */ 21638278Swoschchar *ordernames[] = { 21738278Swosch "cpu", "size", "res", "time", "pri", NULL 21838278Swosch}; 21938278Swosch#endif 22038278Swosch 22124143Sjoergint 22224143Sjoergmachine_init(statics) 22324143Sjoerg 22424143Sjoergstruct statics *statics; 22524143Sjoerg 22624143Sjoerg{ 22724143Sjoerg register int i = 0; 22824143Sjoerg register int pagesize; 22927340Speter int modelen; 23027390Speter struct passwd *pw; 23124143Sjoerg 23227340Speter modelen = sizeof(smpmode); 23328819Speter if ((sysctlbyname("machdep.smp_active", &smpmode, &modelen, NULL, 0) < 0 && 23428819Speter sysctlbyname("smp.smp_active", &smpmode, &modelen, NULL, 0) < 0) || 23527340Speter modelen != sizeof(smpmode)) 23627340Speter smpmode = 0; 23727340Speter 23827390Speter while ((pw = getpwent()) != NULL) { 23927390Speter if (strlen(pw->pw_name) > namelength) 24027390Speter namelength = strlen(pw->pw_name); 24127390Speter } 24227390Speter if (namelength < 8) 24327390Speter namelength = 8; 24427390Speter if (namelength > 16) 24527390Speter namelength = 16; 24627390Speter 24724143Sjoerg if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open")) == NULL) 24824143Sjoerg return -1; 24924143Sjoerg 25024143Sjoerg 25124143Sjoerg /* get the list of symbols we want to access in the kernel */ 25224143Sjoerg (void) kvm_nlist(kd, nlst); 25324143Sjoerg if (nlst[0].n_type == 0) 25424143Sjoerg { 25524143Sjoerg fprintf(stderr, "top: nlist failed\n"); 25624143Sjoerg return(-1); 25724143Sjoerg } 25824143Sjoerg 25924143Sjoerg /* make sure they were all found */ 26024143Sjoerg if (i > 0 && check_nlist(nlst) > 0) 26124143Sjoerg { 26224143Sjoerg return(-1); 26324143Sjoerg } 26424143Sjoerg 26524143Sjoerg (void) getkval(nlst[X_CCPU].n_value, (int *)(&ccpu), sizeof(ccpu), 26624143Sjoerg nlst[X_CCPU].n_name); 26724143Sjoerg 26824143Sjoerg /* stash away certain offsets for later use */ 26924143Sjoerg cp_time_offset = nlst[X_CP_TIME].n_value; 27024143Sjoerg avenrun_offset = nlst[X_AVENRUN].n_value; 27124143Sjoerg lastpid_offset = nlst[X_LASTPID].n_value; 27224143Sjoerg cnt_offset = nlst[X_CNT].n_value; 27324143Sjoerg bufspace_offset = nlst[X_BUFSPACE].n_value; 27424143Sjoerg 27524143Sjoerg /* this is used in calculating WCPU -- calculate it ahead of time */ 27624143Sjoerg logcpu = log(loaddouble(ccpu)); 27724143Sjoerg 27824143Sjoerg pbase = NULL; 27924143Sjoerg pref = NULL; 28024143Sjoerg nproc = 0; 28124143Sjoerg onproc = -1; 28224143Sjoerg /* get the page size with "getpagesize" and calculate pageshift from it */ 28324143Sjoerg pagesize = getpagesize(); 28424143Sjoerg pageshift = 0; 28524143Sjoerg while (pagesize > 1) 28624143Sjoerg { 28724143Sjoerg pageshift++; 28824143Sjoerg pagesize >>= 1; 28924143Sjoerg } 29024143Sjoerg 29124143Sjoerg /* we only need the amount of log(2)1024 for our conversion */ 29224143Sjoerg pageshift -= LOG1024; 29324143Sjoerg 29424143Sjoerg /* fill in the statics information */ 29524143Sjoerg statics->procstate_names = procstatenames; 29624143Sjoerg statics->cpustate_names = cpustatenames; 29724143Sjoerg statics->memory_names = memorynames; 29824143Sjoerg statics->swap_names = swapnames; 29938278Swosch#ifdef ORDER 30038278Swosch statics->order_names = ordernames; 30138278Swosch#endif 30224143Sjoerg 30324143Sjoerg /* all done! */ 30424143Sjoerg return(0); 30524143Sjoerg} 30624143Sjoerg 30724143Sjoergchar *format_header(uname_field) 30824143Sjoerg 30924143Sjoergregister char *uname_field; 31024143Sjoerg 31124143Sjoerg{ 31224143Sjoerg register char *ptr; 31327390Speter static char Header[128]; 31424143Sjoerg 31527390Speter snprintf(Header, sizeof(Header), smpmode ? smp_header : up_header, 31627390Speter namelength, namelength, uname_field); 31727340Speter 31827390Speter cmdlength = 80 - strlen(Header) + 6; 31924143Sjoerg 32027390Speter return Header; 32124143Sjoerg} 32224143Sjoerg 32324143Sjoergstatic int swappgsin = -1; 32424143Sjoergstatic int swappgsout = -1; 32524143Sjoergextern struct timeval timeout; 32624143Sjoerg 32724143Sjoergvoid 32824143Sjoergget_system_info(si) 32924143Sjoerg 33024143Sjoergstruct system_info *si; 33124143Sjoerg 33224143Sjoerg{ 33324143Sjoerg long total; 33424143Sjoerg load_avg avenrun[3]; 33542447Sobrien int mib[2]; 33642447Sobrien struct timeval boottime; 33742447Sobrien size_t bt_size; 33824143Sjoerg 33924143Sjoerg /* get the cp_time array */ 34024143Sjoerg (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time), 34124143Sjoerg nlst[X_CP_TIME].n_name); 34224143Sjoerg (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun), 34324143Sjoerg nlst[X_AVENRUN].n_name); 34424143Sjoerg 34524143Sjoerg (void) getkval(lastpid_offset, (int *)(&lastpid), sizeof(lastpid), 34624143Sjoerg "!"); 34724143Sjoerg 34824143Sjoerg /* convert load averages to doubles */ 34924143Sjoerg { 35024143Sjoerg register int i; 35124143Sjoerg register double *infoloadp; 35224143Sjoerg load_avg *avenrunp; 35324143Sjoerg 35424143Sjoerg#ifdef notyet 35524143Sjoerg struct loadavg sysload; 35624143Sjoerg int size; 35724143Sjoerg getkerninfo(KINFO_LOADAVG, &sysload, &size, 0); 35824143Sjoerg#endif 35924143Sjoerg 36024143Sjoerg infoloadp = si->load_avg; 36124143Sjoerg avenrunp = avenrun; 36224143Sjoerg for (i = 0; i < 3; i++) 36324143Sjoerg { 36424143Sjoerg#ifdef notyet 36524143Sjoerg *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale; 36624143Sjoerg#endif 36724143Sjoerg *infoloadp++ = loaddouble(*avenrunp++); 36824143Sjoerg } 36924143Sjoerg } 37024143Sjoerg 37124143Sjoerg /* convert cp_time counts to percentages */ 37224143Sjoerg total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); 37324143Sjoerg 37424143Sjoerg /* sum memory & swap statistics */ 37524143Sjoerg { 37624143Sjoerg struct vmmeter sum; 37724143Sjoerg static unsigned int swap_delay = 0; 37824143Sjoerg static int swapavail = 0; 37924143Sjoerg static int swapfree = 0; 38024143Sjoerg static int bufspace = 0; 38124143Sjoerg 38224143Sjoerg (void) getkval(cnt_offset, (int *)(&sum), sizeof(sum), 38324143Sjoerg "_cnt"); 38424143Sjoerg (void) getkval(bufspace_offset, (int *)(&bufspace), sizeof(bufspace), 38524143Sjoerg "_bufspace"); 38624143Sjoerg 38724143Sjoerg /* convert memory stats to Kbytes */ 38824143Sjoerg memory_stats[0] = pagetok(sum.v_active_count); 38924143Sjoerg memory_stats[1] = pagetok(sum.v_inactive_count); 39024143Sjoerg memory_stats[2] = pagetok(sum.v_wire_count); 39124143Sjoerg memory_stats[3] = pagetok(sum.v_cache_count); 39224143Sjoerg memory_stats[4] = bufspace / 1024; 39324143Sjoerg memory_stats[5] = pagetok(sum.v_free_count); 39424143Sjoerg memory_stats[6] = -1; 39524143Sjoerg 39624143Sjoerg /* first interval */ 39724143Sjoerg if (swappgsin < 0) { 39824143Sjoerg swap_stats[4] = 0; 39924143Sjoerg swap_stats[5] = 0; 40024143Sjoerg } 40124143Sjoerg 40224143Sjoerg /* compute differences between old and new swap statistic */ 40324143Sjoerg else { 40424143Sjoerg swap_stats[4] = pagetok(((sum.v_swappgsin - swappgsin))); 40524143Sjoerg swap_stats[5] = pagetok(((sum.v_swappgsout - swappgsout))); 40624143Sjoerg } 40724143Sjoerg 40824143Sjoerg swappgsin = sum.v_swappgsin; 40924143Sjoerg swappgsout = sum.v_swappgsout; 41024143Sjoerg 41124143Sjoerg /* call CPU heavy swapmode() only for changes */ 41224143Sjoerg if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { 41324143Sjoerg swap_stats[3] = swapmode(&swapavail, &swapfree); 41424143Sjoerg swap_stats[0] = swapavail; 41524143Sjoerg swap_stats[1] = swapavail - swapfree; 41624143Sjoerg swap_stats[2] = swapfree; 41724143Sjoerg } 41824143Sjoerg swap_delay = 1; 41924143Sjoerg swap_stats[6] = -1; 42024143Sjoerg } 42124143Sjoerg 42224143Sjoerg /* set arrays and strings */ 42324143Sjoerg si->cpustates = cpu_states; 42424143Sjoerg si->memory = memory_stats; 42524143Sjoerg si->swap = swap_stats; 42624143Sjoerg 42724143Sjoerg 42824143Sjoerg if(lastpid > 0) { 42924143Sjoerg si->last_pid = lastpid; 43024143Sjoerg } else { 43124143Sjoerg si->last_pid = -1; 43224143Sjoerg } 43342447Sobrien 43442447Sobrien /* 43542447Sobrien * Print how long system has been up. 43642447Sobrien * (Found by looking getting "boottime" from the kernel) 43742447Sobrien */ 43842447Sobrien mib[0] = CTL_KERN; 43942447Sobrien mib[1] = KERN_BOOTTIME; 44042447Sobrien bt_size = sizeof(boottime); 44142447Sobrien if (sysctl(mib, 2, &boottime, &bt_size, NULL, 0) != -1 && 44242447Sobrien boottime.tv_sec != 0) { 44342447Sobrien si->boottime = boottime; 44442447Sobrien } else { 44542447Sobrien si->boottime.tv_sec = -1; 44642447Sobrien } 44724143Sjoerg} 44824143Sjoerg 44924143Sjoergstatic struct handle handle; 45024143Sjoerg 45124143Sjoergcaddr_t get_process_info(si, sel, compare) 45224143Sjoerg 45324143Sjoergstruct system_info *si; 45424143Sjoergstruct process_select *sel; 45524143Sjoergint (*compare)(); 45624143Sjoerg 45724143Sjoerg{ 45824143Sjoerg register int i; 45924143Sjoerg register int total_procs; 46024143Sjoerg register int active_procs; 46124143Sjoerg register struct kinfo_proc **prefp; 46224143Sjoerg register struct kinfo_proc *pp; 46324143Sjoerg 46424143Sjoerg /* these are copied out of sel for speed */ 46524143Sjoerg int show_idle; 46638090Sdes int show_self; 46724143Sjoerg int show_system; 46824143Sjoerg int show_uid; 46924143Sjoerg int show_command; 47024143Sjoerg 47124143Sjoerg 47224143Sjoerg pbase = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc); 47324143Sjoerg if (nproc > onproc) 47424143Sjoerg pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *) 47524143Sjoerg * (onproc = nproc)); 47624143Sjoerg if (pref == NULL || pbase == NULL) { 47724143Sjoerg (void) fprintf(stderr, "top: Out of memory.\n"); 47824143Sjoerg quit(23); 47924143Sjoerg } 48024143Sjoerg /* get a pointer to the states summary array */ 48124143Sjoerg si->procstates = process_states; 48224143Sjoerg 48324143Sjoerg /* set up flags which define what we are going to select */ 48424143Sjoerg show_idle = sel->idle; 48538090Sdes show_self = sel->self; 48624143Sjoerg show_system = sel->system; 48724143Sjoerg show_uid = sel->uid != -1; 48824143Sjoerg show_command = sel->command != NULL; 48924143Sjoerg 49024143Sjoerg /* count up process states and get pointers to interesting procs */ 49124143Sjoerg total_procs = 0; 49224143Sjoerg active_procs = 0; 49324143Sjoerg memset((char *)process_states, 0, sizeof(process_states)); 49424143Sjoerg prefp = pref; 49524143Sjoerg for (pp = pbase, i = 0; i < nproc; pp++, i++) 49624143Sjoerg { 49724143Sjoerg /* 49824143Sjoerg * Place pointers to each valid proc structure in pref[]. 49924143Sjoerg * Process slots that are actually in use have a non-zero 50024143Sjoerg * status field. Processes with P_SYSTEM set are system 50124143Sjoerg * processes---these get ignored unless show_sysprocs is set. 50224143Sjoerg */ 50324143Sjoerg if (PP(pp, p_stat) != 0 && 50438090Sdes (show_self != PP(pp, p_pid)) && 50524143Sjoerg (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0))) 50624143Sjoerg { 50724143Sjoerg total_procs++; 50824143Sjoerg process_states[(unsigned char) PP(pp, p_stat)]++; 50924143Sjoerg if ((PP(pp, p_stat) != SZOMB) && 51024143Sjoerg (show_idle || (PP(pp, p_pctcpu) != 0) || 51124143Sjoerg (PP(pp, p_stat) == SRUN)) && 51224143Sjoerg (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid)) 51324143Sjoerg { 51424143Sjoerg *prefp++ = pp; 51524143Sjoerg active_procs++; 51624143Sjoerg } 51724143Sjoerg } 51824143Sjoerg } 51924143Sjoerg 52024143Sjoerg /* if requested, sort the "interesting" processes */ 52124143Sjoerg if (compare != NULL) 52224143Sjoerg { 52324143Sjoerg qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare); 52424143Sjoerg } 52524143Sjoerg 52624143Sjoerg /* remember active and total counts */ 52724143Sjoerg si->p_total = total_procs; 52824143Sjoerg si->p_active = pref_len = active_procs; 52924143Sjoerg 53024143Sjoerg /* pass back a handle */ 53124143Sjoerg handle.next_proc = pref; 53224143Sjoerg handle.remaining = active_procs; 53324143Sjoerg return((caddr_t)&handle); 53424143Sjoerg} 53524143Sjoerg 53624143Sjoergchar fmt[128]; /* static area where result is built */ 53724143Sjoerg 53824143Sjoergchar *format_next_process(handle, get_userid) 53924143Sjoerg 54024143Sjoergcaddr_t handle; 54124143Sjoergchar *(*get_userid)(); 54224143Sjoerg 54324143Sjoerg{ 54424143Sjoerg register struct kinfo_proc *pp; 54524143Sjoerg register long cputime; 54624143Sjoerg register double pct; 54724143Sjoerg struct handle *hp; 54824143Sjoerg char status[16]; 54943720Sfenner int state; 55024143Sjoerg 55124143Sjoerg /* find and remember the next proc structure */ 55224143Sjoerg hp = (struct handle *)handle; 55324143Sjoerg pp = *(hp->next_proc++); 55424143Sjoerg hp->remaining--; 55524143Sjoerg 55624143Sjoerg 55724143Sjoerg /* get the process's user struct and set cputime */ 55824143Sjoerg if ((PP(pp, p_flag) & P_INMEM) == 0) { 55924143Sjoerg /* 56024143Sjoerg * Print swapped processes as <pname> 56124143Sjoerg */ 56224143Sjoerg char *comm = PP(pp, p_comm); 56324143Sjoerg#define COMSIZ sizeof(PP(pp, p_comm)) 56424143Sjoerg char buf[COMSIZ]; 56524143Sjoerg (void) strncpy(buf, comm, COMSIZ); 56624143Sjoerg comm[0] = '<'; 56724143Sjoerg (void) strncpy(&comm[1], buf, COMSIZ - 2); 56824143Sjoerg comm[COMSIZ - 2] = '\0'; 56924143Sjoerg (void) strncat(comm, ">", COMSIZ - 1); 57024143Sjoerg comm[COMSIZ - 1] = '\0'; 57124143Sjoerg } 57224143Sjoerg 57324143Sjoerg#if 0 57424143Sjoerg /* This does not produce the correct results */ 57524143Sjoerg cputime = PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks); 57624143Sjoerg#endif 57737885Swosch /* This does not count interrupts */ 57837885Swosch cputime = (PP(pp, p_runtime) / 1000 + 500) / 1000; 57924143Sjoerg 58024143Sjoerg /* calculate the base for cpu percentages */ 58124143Sjoerg pct = pctdouble(PP(pp, p_pctcpu)); 58224143Sjoerg 58324143Sjoerg /* generate "STATE" field */ 58443720Sfenner switch (state = PP(pp, p_stat)) { 58524143Sjoerg case SRUN: 58644543Sbde if (smpmode && PP(pp, p_oncpu) != 0xff) 58724143Sjoerg sprintf(status, "CPU%d", PP(pp, p_oncpu)); 58824143Sjoerg else 58924143Sjoerg strcpy(status, "RUN"); 59024143Sjoerg break; 59124143Sjoerg case SSLEEP: 59224143Sjoerg if (PP(pp, p_wmesg) != NULL) { 59324143Sjoerg sprintf(status, "%.6s", EP(pp, e_wmesg)); 59424143Sjoerg break; 59524143Sjoerg } 59624143Sjoerg /* fall through */ 59724143Sjoerg default: 59843720Sfenner 59943720Sfenner if (state >= 0 && 60043720Sfenner state < sizeof(state_abbrev) / sizeof(*state_abbrev)) 60143720Sfenner sprintf(status, "%.6s", state_abbrev[(unsigned char) state]); 60243720Sfenner else 60343720Sfenner sprintf(status, "?%5d", state); 60424143Sjoerg break; 60524143Sjoerg } 60624143Sjoerg 60724143Sjoerg /* format this entry */ 60824143Sjoerg sprintf(fmt, 60927340Speter smpmode ? smp_Proc_format : up_Proc_format, 61024143Sjoerg PP(pp, p_pid), 61127390Speter namelength, namelength, 61224143Sjoerg (*get_userid)(EP(pp, e_pcred.p_ruid)), 61324143Sjoerg PP(pp, p_priority) - PZERO, 61429904Speter 61529904Speter /* 61629904Speter * normal time -> nice value -20 - +20 61729904Speter * real time 0 - 31 -> nice value -52 - -21 61829904Speter * idle time 0 - 31 -> nice value +21 - +52 61929904Speter */ 62029904Speter (PP(pp, p_rtprio.type) == RTP_PRIO_NORMAL ? 62129904Speter PP(pp, p_nice) - NZERO : 62245936Sjhay (RTP_PRIO_IS_REALTIME(PP(pp, p_rtprio.type)) ? 62329904Speter (PRIO_MIN - 1 - RTP_PRIO_MAX + PP(pp, p_rtprio.prio)) : 62429904Speter (PRIO_MAX + 1 + PP(pp, p_rtprio.prio)))), 62537100Sdt format_k2(PROCSIZE(pp)), 62624143Sjoerg format_k2(pagetok(VP(pp, vm_rssize))), 62724143Sjoerg status, 62827340Speter smpmode ? PP(pp, p_lastcpu) : 0, 62924143Sjoerg format_time(cputime), 63041325Sdfr 100.0 * weighted_cpu(pct, pp), 63141325Sdfr 100.0 * pct, 63227390Speter cmdlength, 63324143Sjoerg printable(PP(pp, p_comm))); 63424143Sjoerg 63524143Sjoerg /* return the result */ 63624143Sjoerg return(fmt); 63724143Sjoerg} 63824143Sjoerg 63924143Sjoerg 64024143Sjoerg/* 64124143Sjoerg * check_nlist(nlst) - checks the nlist to see if any symbols were not 64224143Sjoerg * found. For every symbol that was not found, a one-line 64324143Sjoerg * message is printed to stderr. The routine returns the 64424143Sjoerg * number of symbols NOT found. 64524143Sjoerg */ 64624143Sjoerg 64724143Sjoergstatic int check_nlist(nlst) 64824143Sjoerg 64924143Sjoergregister struct nlist *nlst; 65024143Sjoerg 65124143Sjoerg{ 65224143Sjoerg register int i; 65324143Sjoerg 65424143Sjoerg /* check to see if we got ALL the symbols we requested */ 65524143Sjoerg /* this will write one line to stderr for every symbol not found */ 65624143Sjoerg 65724143Sjoerg i = 0; 65824143Sjoerg while (nlst->n_name != NULL) 65924143Sjoerg { 66024143Sjoerg if (nlst->n_type == 0) 66124143Sjoerg { 66224143Sjoerg /* this one wasn't found */ 66324143Sjoerg (void) fprintf(stderr, "kernel: no symbol named `%s'\n", 66424143Sjoerg nlst->n_name); 66524143Sjoerg i = 1; 66624143Sjoerg } 66724143Sjoerg nlst++; 66824143Sjoerg } 66924143Sjoerg 67024143Sjoerg return(i); 67124143Sjoerg} 67224143Sjoerg 67324143Sjoerg 67424143Sjoerg/* 67524143Sjoerg * getkval(offset, ptr, size, refstr) - get a value out of the kernel. 67624143Sjoerg * "offset" is the byte offset into the kernel for the desired value, 67724143Sjoerg * "ptr" points to a buffer into which the value is retrieved, 67824143Sjoerg * "size" is the size of the buffer (and the object to retrieve), 67924143Sjoerg * "refstr" is a reference string used when printing error meessages, 68024143Sjoerg * if "refstr" starts with a '!', then a failure on read will not 68124143Sjoerg * be fatal (this may seem like a silly way to do things, but I 68224143Sjoerg * really didn't want the overhead of another argument). 68324143Sjoerg * 68424143Sjoerg */ 68524143Sjoerg 68624143Sjoergstatic int getkval(offset, ptr, size, refstr) 68724143Sjoerg 68824143Sjoergunsigned long offset; 68924143Sjoergint *ptr; 69024143Sjoergint size; 69124143Sjoergchar *refstr; 69224143Sjoerg 69324143Sjoerg{ 69424143Sjoerg if (kvm_read(kd, offset, (char *) ptr, size) != size) 69524143Sjoerg { 69624143Sjoerg if (*refstr == '!') 69724143Sjoerg { 69824143Sjoerg return(0); 69924143Sjoerg } 70024143Sjoerg else 70124143Sjoerg { 70224143Sjoerg fprintf(stderr, "top: kvm_read for %s: %s\n", 70324143Sjoerg refstr, strerror(errno)); 70424143Sjoerg quit(23); 70524143Sjoerg } 70624143Sjoerg } 70724143Sjoerg return(1); 70824143Sjoerg} 70924143Sjoerg 71038278Swosch/* comparison routines for qsort */ 71124143Sjoerg 71224143Sjoerg/* 71324143Sjoerg * proc_compare - comparison function for "qsort" 71424143Sjoerg * Compares the resource consumption of two processes using five 71524143Sjoerg * distinct keys. The keys (in descending order of importance) are: 71624143Sjoerg * percent cpu, cpu ticks, state, resident set size, total virtual 71724143Sjoerg * memory usage. The process states are ordered as follows (from least 71824143Sjoerg * to most important): WAIT, zombie, sleep, stop, start, run. The 71924143Sjoerg * array declaration below maps a process state index into a number 72024143Sjoerg * that reflects this ordering. 72124143Sjoerg */ 72224143Sjoerg 72324143Sjoergstatic unsigned char sorted_state[] = 72424143Sjoerg{ 72524143Sjoerg 0, /* not used */ 72624143Sjoerg 3, /* sleep */ 72724143Sjoerg 1, /* ABANDONED (WAIT) */ 72824143Sjoerg 6, /* run */ 72924143Sjoerg 5, /* start */ 73024143Sjoerg 2, /* zombie */ 73124143Sjoerg 4 /* stop */ 73224143Sjoerg}; 73324143Sjoerg 73438278Swosch 73538278Swosch#define ORDERKEY_PCTCPU \ 73641325Sdfr if (lresult = (long) PP(p2, p_pctcpu) - (long) PP(p1, p_pctcpu), \ 73738278Swosch (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0) 73838278Swosch 73938278Swosch#define ORDERKEY_CPTICKS \ 74038278Swosch if ((result = PP(p2, p_runtime) - PP(p1, p_runtime)) == 0) 74138278Swosch 74238278Swosch#define ORDERKEY_STATE \ 74338278Swosch if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \ 74438278Swosch sorted_state[(unsigned char) PP(p1, p_stat)]) == 0) 74538278Swosch 74638278Swosch#define ORDERKEY_PRIO \ 74738278Swosch if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0) 74838278Swosch 74938278Swosch#define ORDERKEY_RSSIZE \ 75038278Swosch if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0) 75138278Swosch 75238278Swosch#define ORDERKEY_MEM \ 75338278Swosch if ( (result = PROCSIZE(p2) - PROCSIZE(p1)) == 0 ) 75438278Swosch 75538278Swosch/* compare_cpu - the comparison function for sorting by cpu percentage */ 75638278Swosch 75724143Sjoergint 75838278Swosch#ifdef ORDER 75938278Swoschcompare_cpu(pp1, pp2) 76038278Swosch#else 76124143Sjoergproc_compare(pp1, pp2) 76238278Swosch#endif 76324143Sjoerg 76424143Sjoergstruct proc **pp1; 76524143Sjoergstruct proc **pp2; 76624143Sjoerg 76724143Sjoerg{ 76824143Sjoerg register struct kinfo_proc *p1; 76924143Sjoerg register struct kinfo_proc *p2; 77024143Sjoerg register int result; 77124143Sjoerg register pctcpu lresult; 77224143Sjoerg 77324143Sjoerg /* remove one level of indirection */ 77424143Sjoerg p1 = *(struct kinfo_proc **) pp1; 77524143Sjoerg p2 = *(struct kinfo_proc **) pp2; 77624143Sjoerg 77738278Swosch ORDERKEY_PCTCPU 77838278Swosch ORDERKEY_CPTICKS 77938278Swosch ORDERKEY_STATE 78038278Swosch ORDERKEY_PRIO 78138278Swosch ORDERKEY_RSSIZE 78238278Swosch ORDERKEY_MEM 78338278Swosch ; 78424143Sjoerg 78524143Sjoerg return(result); 78624143Sjoerg} 78724143Sjoerg 78838278Swosch#ifdef ORDER 78938278Swosch/* compare routines */ 79038278Swoschint compare_size(), compare_res(), compare_time(), compare_prio(); 79124143Sjoerg 79238278Swoschint (*proc_compares[])() = { 79338278Swosch compare_cpu, 79438278Swosch compare_size, 79538278Swosch compare_res, 79638278Swosch compare_time, 79738278Swosch compare_prio, 79838278Swosch NULL 79938278Swosch}; 80038278Swosch 80138278Swosch/* compare_size - the comparison function for sorting by total memory usage */ 80238278Swosch 80338278Swoschint 80438278Swoschcompare_size(pp1, pp2) 80538278Swosch 80638278Swoschstruct proc **pp1; 80738278Swoschstruct proc **pp2; 80838278Swosch 80938278Swosch{ 81038278Swosch register struct kinfo_proc *p1; 81138278Swosch register struct kinfo_proc *p2; 81238278Swosch register int result; 81338278Swosch register pctcpu lresult; 81438278Swosch 81538278Swosch /* remove one level of indirection */ 81638278Swosch p1 = *(struct kinfo_proc **) pp1; 81738278Swosch p2 = *(struct kinfo_proc **) pp2; 81838278Swosch 81938278Swosch ORDERKEY_MEM 82038278Swosch ORDERKEY_RSSIZE 82138278Swosch ORDERKEY_PCTCPU 82238278Swosch ORDERKEY_CPTICKS 82338278Swosch ORDERKEY_STATE 82438278Swosch ORDERKEY_PRIO 82538278Swosch ; 82638278Swosch 82738278Swosch return(result); 82838278Swosch} 82938278Swosch 83038278Swosch/* compare_res - the comparison function for sorting by resident set size */ 83138278Swosch 83238278Swoschint 83338278Swoschcompare_res(pp1, pp2) 83438278Swosch 83538278Swoschstruct proc **pp1; 83638278Swoschstruct proc **pp2; 83738278Swosch 83838278Swosch{ 83938278Swosch register struct kinfo_proc *p1; 84038278Swosch register struct kinfo_proc *p2; 84138278Swosch register int result; 84238278Swosch register pctcpu lresult; 84338278Swosch 84438278Swosch /* remove one level of indirection */ 84538278Swosch p1 = *(struct kinfo_proc **) pp1; 84638278Swosch p2 = *(struct kinfo_proc **) pp2; 84738278Swosch 84838278Swosch ORDERKEY_RSSIZE 84938278Swosch ORDERKEY_MEM 85038278Swosch ORDERKEY_PCTCPU 85138278Swosch ORDERKEY_CPTICKS 85238278Swosch ORDERKEY_STATE 85338278Swosch ORDERKEY_PRIO 85438278Swosch ; 85538278Swosch 85638278Swosch return(result); 85738278Swosch} 85838278Swosch 85938278Swosch/* compare_time - the comparison function for sorting by total cpu time */ 86038278Swosch 86138278Swoschint 86238278Swoschcompare_time(pp1, pp2) 86338278Swosch 86438278Swoschstruct proc **pp1; 86538278Swoschstruct proc **pp2; 86638278Swosch 86738278Swosch{ 86838278Swosch register struct kinfo_proc *p1; 86938278Swosch register struct kinfo_proc *p2; 87038278Swosch register int result; 87138278Swosch register pctcpu lresult; 87238278Swosch 87338278Swosch /* remove one level of indirection */ 87438278Swosch p1 = *(struct kinfo_proc **) pp1; 87538278Swosch p2 = *(struct kinfo_proc **) pp2; 87638278Swosch 87738278Swosch ORDERKEY_CPTICKS 87838278Swosch ORDERKEY_PCTCPU 87938278Swosch ORDERKEY_STATE 88038278Swosch ORDERKEY_PRIO 88138278Swosch ORDERKEY_RSSIZE 88238278Swosch ORDERKEY_MEM 88338278Swosch ; 88438278Swosch 88538278Swosch return(result); 88638278Swosch } 88738278Swosch 88838278Swosch/* compare_prio - the comparison function for sorting by cpu percentage */ 88938278Swosch 89038278Swoschint 89138278Swoschcompare_prio(pp1, pp2) 89238278Swosch 89338278Swoschstruct proc **pp1; 89438278Swoschstruct proc **pp2; 89538278Swosch 89638278Swosch{ 89738278Swosch register struct kinfo_proc *p1; 89838278Swosch register struct kinfo_proc *p2; 89938278Swosch register int result; 90038278Swosch register pctcpu lresult; 90138278Swosch 90238278Swosch /* remove one level of indirection */ 90338278Swosch p1 = *(struct kinfo_proc **) pp1; 90438278Swosch p2 = *(struct kinfo_proc **) pp2; 90538278Swosch 90638278Swosch ORDERKEY_PRIO 90738278Swosch ORDERKEY_CPTICKS 90838278Swosch ORDERKEY_PCTCPU 90938278Swosch ORDERKEY_STATE 91038278Swosch ORDERKEY_RSSIZE 91138278Swosch ORDERKEY_MEM 91238278Swosch ; 91338278Swosch 91438278Swosch return(result); 91538278Swosch} 91638278Swosch#endif 91738278Swosch 91824143Sjoerg/* 91924143Sjoerg * proc_owner(pid) - returns the uid that owns process "pid", or -1 if 92024143Sjoerg * the process does not exist. 92124143Sjoerg * It is EXTREMLY IMPORTANT that this function work correctly. 92224143Sjoerg * If top runs setuid root (as in SVR4), then this function 92324143Sjoerg * is the only thing that stands in the way of a serious 92424143Sjoerg * security problem. It validates requests for the "kill" 92524143Sjoerg * and "renice" commands. 92624143Sjoerg */ 92724143Sjoerg 92824143Sjoergint proc_owner(pid) 92924143Sjoerg 93024143Sjoergint pid; 93124143Sjoerg 93224143Sjoerg{ 93324143Sjoerg register int cnt; 93424143Sjoerg register struct kinfo_proc **prefp; 93524143Sjoerg register struct kinfo_proc *pp; 93624143Sjoerg 93724143Sjoerg prefp = pref; 93824143Sjoerg cnt = pref_len; 93924143Sjoerg while (--cnt >= 0) 94024143Sjoerg { 94124143Sjoerg pp = *prefp++; 94224143Sjoerg if (PP(pp, p_pid) == (pid_t)pid) 94324143Sjoerg { 94424143Sjoerg return((int)EP(pp, e_pcred.p_ruid)); 94524143Sjoerg } 94624143Sjoerg } 94724143Sjoerg return(-1); 94824143Sjoerg} 94924143Sjoerg 95024143Sjoerg 95124143Sjoerg/* 95224143Sjoerg * swapmode is based on a program called swapinfo written 95324143Sjoerg * by Kevin Lahey <kml@rokkaku.atl.ga.us>. 95424143Sjoerg */ 95524143Sjoerg 95624143Sjoerg#define SVAR(var) __STRING(var) /* to force expansion */ 95724143Sjoerg#define KGET(idx, var) \ 95824143Sjoerg KGET1(idx, &var, sizeof(var), SVAR(var)) 95924143Sjoerg#define KGET1(idx, p, s, msg) \ 96024143Sjoerg KGET2(nlst[idx].n_value, p, s, msg) 96124143Sjoerg#define KGET2(addr, p, s, msg) \ 96224143Sjoerg if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 96324143Sjoerg warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 96424143Sjoerg return (0); \ 96524143Sjoerg } 96624143Sjoerg#define KGETRET(addr, p, s, msg) \ 96724143Sjoerg if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 96824143Sjoerg warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 96924143Sjoerg return (0); \ 97024143Sjoerg } 97124143Sjoerg 97224143Sjoerg 97324143Sjoergint 97424143Sjoergswapmode(retavail, retfree) 97524143Sjoerg int *retavail; 97624143Sjoerg int *retfree; 97724143Sjoerg{ 97843053Sdillon int n; 97943053Sdillon int pagesize = getpagesize(); 98043053Sdillon struct kvm_swap swapary[1]; 98124143Sjoerg 98243053Sdillon *retavail = 0; 98343053Sdillon *retfree = 0; 98424143Sjoerg 98543053Sdillon#define CONVERT(v) ((quad_t)(v) * pagesize / 1024) 98624143Sjoerg 98743053Sdillon n = kvm_getswapinfo(kd, swapary, 1, 0); 98843697Sdillon if (n < 0 || swapary[0].ksw_total == 0) 98924143Sjoerg return(0); 99024143Sjoerg 99143053Sdillon *retavail = CONVERT(swapary[0].ksw_total); 99243053Sdillon *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); 99324143Sjoerg 99443053Sdillon n = (int)((double)swapary[0].ksw_used * 100.0 / 99543053Sdillon (double)swapary[0].ksw_total); 99643053Sdillon return(n); 99743053Sdillon} 99824143Sjoerg 999