diff --git a/proc/library.map b/proc/library.map index 032ada0c..d09c6e1d 100644 --- a/proc/library.map +++ b/proc/library.map @@ -13,7 +13,7 @@ global: Hertz; smp_num_cpus; have_privs; getbtime; sprint_uptime; uptime; user_from_uid; print_uptime; loadavg; pretty_print_signals; print_given_signals; unix_print_signals; signal_name_to_number; signal_number_to_name; - meminfo; vminfo; getstat; getdiskstat; getpartitions_num; getslabinfo; get_pid_digits; + cpuinfo; meminfo; vminfo; getstat; getdiskstat; getpartitions_num; getslabinfo; get_pid_digits; kb_active; kb_inactive; kb_main_buffers; kb_main_cached; kb_main_free; kb_main_total; kb_main_used; kb_swap_free; kb_swap_total; kb_swap_used; kb_main_shared; diff --git a/proc/sysinfo.c b/proc/sysinfo.c index 952faf41..40487aa9 100644 --- a/proc/sysinfo.c +++ b/proc/sysinfo.c @@ -24,9 +24,7 @@ #include /* htons */ #endif -#ifndef OOMEM_ENABLE long smp_num_cpus; /* number of CPUs */ -#endif #define BAD_OPEN_MESSAGE \ "Error: /proc must be mounted\n" \ @@ -182,11 +180,7 @@ static void old_Hertz_hack(void){ setlocale(LC_NUMERIC, savelocale); jiffies = user_j + nice_j + sys_j + other_j; seconds = (up_1 + up_2) / 2; -#ifndef OOMEM_ENABLE h = (unsigned)( (double)jiffies/seconds/smp_num_cpus ); -#else - h = (unsigned)( (double)jiffies/seconds/smp_num_cpus() ); -#endif /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */ switch(h){ case 9 ... 11 : Hertz = 10; break; /* S/390 (sometimes) */ @@ -252,44 +246,13 @@ static int check_for_privs(void){ return !!rc; } -#ifdef OOMEM_ENABLE -long smp_num_cpus(void) -{ - static long _smp_num_cpus=-1; /* number of CPUs */ - - if (_smp_num_cpus != -1) - return(_smp_num_cpus); - - // ought to count CPUs in /proc/stat instead of relying - // on glibc, which foolishly tries to parse /proc/cpuinfo - // - // SourceForge has an old Alpha running Linux 2.2.20 that - // appears to have a non-SMP kernel on a 2-way SMP box. - // _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512 - // _SC_NPROCESSORS_ONLN returns 1, which should work OK - - _smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if(_smp_num_cpus<1) _smp_num_cpus=1; /* SPARC glibc is buggy */ - - return(_smp_num_cpus); -} -#endif - static void init_libproc(void) __attribute__((constructor)); static void init_libproc(void){ have_privs = check_for_privs(); init_Linux_version(); /* Must be called before we check code */ -#ifndef OOMEM_ENABLE - // ought to count CPUs in /proc/stat instead of relying - // on glibc, which foolishly tries to parse /proc/cpuinfo - // - // SourceForge has an old Alpha running Linux 2.2.20 that - // appears to have a non-SMP kernel on a 2-way SMP box. - // _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512 - // _SC_NPROCESSORS_ONLN returns 1, which should work OK - smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if(smp_num_cpus<1) smp_num_cpus=1; /* SPARC glibc is buggy */ -#endif + + cpuinfo(); + if(linux_version_code > LINUX_VERSION(2, 4, 0)){ Hertz = find_elf_note(AT_CLKTCK); if(Hertz!=NOTE_NOT_FOUND) return; @@ -978,3 +941,19 @@ unsigned get_pid_digits(void){ out: return ret; } + +/////////////////////////////////////////////////////////////////////////// + +void cpuinfo (void) { + // ought to count CPUs in /proc/stat instead of relying + // on glibc, which foolishly tries to parse /proc/cpuinfo + // + // SourceForge has an old Alpha running Linux 2.2.20 that + // appears to have a non-SMP kernel on a 2-way SMP box. + // _SC_NPROCESSORS_CONF returns 2, resulting in HZ=512 + // _SC_NPROCESSORS_ONLN returns 1, which should work OK + + smp_num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + if (smp_num_cpus<1) /* SPARC glibc is buggy */ + smp_num_cpus=1; +} diff --git a/proc/sysinfo.h b/proc/sysinfo.h index 744f2805..194cb2a6 100644 --- a/proc/sysinfo.h +++ b/proc/sysinfo.h @@ -7,12 +7,8 @@ EXTERN_C_BEGIN extern unsigned long long Hertz; /* clock tick frequency */ -#ifndef OOMEM_ENABLE -extern long smp_num_cpus; /* number of CPUs */ -#else -extern long smp_num_cpus(void); /* number of CPUs */ -#endif -extern int have_privs; /* boolean, true if setuid or similar */ +extern long smp_num_cpus; /* number of CPUs */ +extern int have_privs; /* boolean, true if setuid or similar */ #if 0 #define JT double @@ -136,5 +132,7 @@ extern unsigned int getslabinfo (struct slab_cache**); extern unsigned get_pid_digits(void) FUNCTION; +extern void cpuinfo (void); + EXTERN_C_END #endif /* SYSINFO_H */ diff --git a/top.1 b/top.1 index 5c21ce76..e88eec22 100644 --- a/top.1 +++ b/top.1 @@ -59,9 +59,9 @@ .ds FM full\-screen mode .ds KA arrow key .ds KS scrolling key -.ds MP \fBphysical\fR memory -.ds MS \fBshared\fR memory -.ds MV \fBvirtual\fR memory +.ds MP physical memory +.ds MS shared memory +.ds MV virtual memory .ds NT \fBNote\fR: .ds PU CPU .ds Pu cpu @@ -775,9 +775,9 @@ line. .TP 7 \ \ \<\fBEnter\fR> or <\fBSpace\fR> :\fIRefresh-Display \fR -These commands do nothing, they are simply ignored. -However, they will awaken \*(We and following receipt of any input +These commands awaken \*(We and following receipt of any input the entire display will be repainted. +They also force an update of any hotplugged \*(Pu or \*(MP changes. Use either of these keys if you have a large delay interval and wish to see current status, diff --git a/top.c b/top.c index 9b2c43f0..2a000280 100644 --- a/top.c +++ b/top.c @@ -1679,7 +1679,7 @@ static void zap_fieldstab (void) { Cpu_pmax = 99.0; Fieldstab[P_CPU].fmts = "%#4.1f "; - if (Rc.mode_irixps && Cpu_tot > 1 && !Thread_mode) { + if (Rc.mode_irixps && Cpu_tot > 1 && !Thread_mode) { Cpu_pmax = 9999.0; Fieldstab[P_CPU].fmts = "%4.0f "; } @@ -1696,13 +1696,13 @@ static void zap_fieldstab (void) { static CPU_t *cpus_refresh (CPU_t *cpus) { static const char err_read[] = "failed /proc/stat read"; static FILE *fp = NULL; - static int smp_sav = -1; + static int sav_cpus = -1; char buf[MEDBUFSIZ]; // enough for /proc/stat CPU line (not the intr line) int i; /*** hotplug_acclimated ***/ - if (smp_sav != SMP_NUM_CPUS) { - Cpu_tot = smp_sav = SMP_NUM_CPUS; + if (sav_cpus != smp_num_cpus) { + Cpu_tot = sav_cpus = smp_num_cpus; zap_fieldstab(); calibrate_fields(); if (fp) { fclose(fp); fp = NULL; } @@ -2000,11 +2000,38 @@ static proc_t **procs_refresh (proc_t **ppt) { #undef PTRsz #undef ENTsz } // end: procs_refresh + + + /* + * This serves as our interface to the memory & cpu count (sysinfo) + * portion of libproc. In support of those hotpluggable resources, + * the sampling frequencies are reduced so as to minimize overhead. + * We'll strive to verify the number of cpus every 5 minutes and the + * memory availability/usage every 3 seconds. */ +static void sysinfo_refresh (int forced) { + static time_t mem_secs, cpu_secs; + time_t cur_secs; + + if (forced) + mem_secs = cpu_secs = 0; + time(&cur_secs); + + if (3 <= cur_secs - mem_secs) { + meminfo(); + mem_secs = cur_secs; + } +#ifndef PRETEND4CPUS + if (300 <= cur_secs - cpu_secs) { + cpuinfo(); + cpu_secs = cur_secs; + } +#endif +} // end: sysinfo_refresh /*###### Startup routines ##############################################*/ /* - * No mater what *they* say, we handle the really really BIG and + * No matter what *they* say, we handle the really really BIG and * IMPORTANT stuff upon which all those lessor functions depend! */ static void before (char *me) { int i; @@ -2015,10 +2042,9 @@ static void before (char *me) { // establish cpu particulars -- even bigger! #ifdef PRETEND4CPUS - SMP_NUM_CPUS = Cpu_tot = 4; -#else - Cpu_tot = SMP_NUM_CPUS; + smp_num_cpus = 4; #endif + Cpu_tot = smp_num_cpus; if (linux_version_code > LINUX_VERSION(2, 5, 41)) Cpu_States_fmts = STATES_line2x5; if (linux_version_code >= LINUX_VERSION(2, 6, 0)) @@ -2081,6 +2107,7 @@ static void configs_read (void) { fbuf[0] = '\0'; fgets(fbuf, sizeof(fbuf), fp); // sys rc file, line 2 sscanf(fbuf, "%f", &Rc.delay_time); + fclose(fp); } fp = fopen(Rc_name, "r"); @@ -3009,7 +3036,8 @@ static void do_key (int ch) { help_view(); break; case kbd_ENTER: // these two will have the effect of waking us - case kbd_SPACE: // from 'select()' then refreshing the display + case kbd_SPACE: // from 'select()', updating hotplugged resources + sysinfo_refresh(1); // and then refreshing the display break; default: // and now, the real work... for (i = 0; i < MAXTBL(key_tab); ++i) @@ -3110,14 +3138,14 @@ static proc_t **summary_show (void) { // whoa first time, gotta' prime the pump... if (!p_table) { - struct timeval tv = { 0, 300000 }; p_table = procs_refresh(NULL); putp(Cap_clr_scr); - select(0, NULL, NULL, NULL, &tv); // sleep for a bit... + usleep(LIB_USLEEP); } else putp(Batch ? "\n\n" : Cap_home); p_table = procs_refresh(p_table); + sysinfo_refresh(0); // Display Uptime and Loadavg if (isROOM(View_LOADAV, 1)) { @@ -3157,7 +3185,6 @@ static proc_t **summary_show (void) { } // Display Memory and Swap stats - meminfo(); if (isROOM(View_MEMORY, 2)) { #define mkM(x) (unsigned long)(kb_main_ ## x >> shift) #define mkS(x) (unsigned long)(kb_swap_ ## x >> shift) diff --git a/top.h b/top.h index 2e889562..cba3dea6 100644 --- a/top.h +++ b/top.h @@ -62,23 +62,16 @@ #define STRSORTCMP strcmp #endif -#ifdef OOMEM_ENABLE - /* FIXME: perhaps making this a function in the suse version of - sysinfo.c was a prelude to hotpluggable updates -- unfortunately, - the return value is invariant as currently implemented! */ -#define SMP_NUM_CPUS smp_num_cpus() -#else -#define SMP_NUM_CPUS smp_num_cpus -#endif - /*###### Some Miscellaneous constants ##################################*/ /* The default delay twix updates */ #define DEF_DELAY 3.0 - /* Length of time a 'message' is displayed (in microseconds) */ + /* Length of time a message is displayed and the duration + of a 'priming' wait during library startup (in microseconds) */ #define MSG_USLEEP (useconds_t)1250000 +#define LIB_USLEEP (useconds_t)150000 /* Specific process id monitoring support (command line only) */ #define MONPIDMAX 20 @@ -592,9 +585,6 @@ typedef struct WIN_t { #if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH) # error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH' #endif -#if defined(PRETEND4CPUS) && defined (OOMEM_ENABLE) -# error 'PRETEND4CPUS' conflicts with 'OOMEM_ENABLE' -#endif #if (LRGBUFSIZ < SCREENMAX) # error 'LRGBUFSIZ' must NOT be less than 'SCREENMAX' #endif @@ -655,6 +645,7 @@ typedef struct WIN_t { #endif //atic void prochlp (proc_t *p); //atic proc_t **procs_refresh (proc_t **ppt); +//atic void sysinfo_refresh (int forced); /*------ Startup routines ----------------------------------------------*/ //atic void before (char *me); //atic void configs_read (void); diff --git a/w.c b/w.c index f479433c..e41fb937 100644 --- a/w.c +++ b/w.c @@ -29,6 +29,7 @@ #include #include #include +#include static int ignoreuser = 0; /* for '-u' */ static proc_t **procs; /* our snapshot of the process table */ @@ -44,6 +45,7 @@ typedef struct utmp utmp_t; /* Uh... same thing as UT_NAMESIZE */ #define USERSZ (sizeof u->ut_user) +#define MAX_FROM_LEN 16 /* This routine is careful since some programs leave utmp strings * unprintable. Always outputs at least 16 chars padded with spaces @@ -57,7 +59,7 @@ static void print_host(const char *restrict host, int len) { /* for now, we'll just limit it to the 16 that the libc5 version * of utmp uses. */ - if (len > 16) len = 16; + if (len > MAX_FROM_LEN) len = MAX_FROM_LEN; last = host + len; for ( ; host < last ; host++){ if (isprint(*host) && *host != ' ') { @@ -67,8 +69,45 @@ static void print_host(const char *restrict host, int len) { break; } } - // space-fill, and a '-' too if needed to ensure the column exists - if(width < 16) fputs("- "+width, stdout); + /* space-fill, and a '-' too if needed to ensure the column exists */ + if(width < MAX_FROM_LEN) fputs("- "+width, stdout); +} + +/* This routine prints either the hostname or the IP address of the remote */ +static void print_from(const utmp_t *restrict const u, int ip_addresses) { + char buf[MAX_FROM_LEN + 1]; + char buf_ipv6[INET6_ADDRSTRLEN]; + int len; + int32_t ut_addr_v6[4]; /* IP address of remote host. */ + + if (ip_addresses) { /* -n switch used */ + memcpy(&ut_addr_v6, &u->ut_addr_v6, sizeof(ut_addr_v6)); + if (IN6_IS_ADDR_V4MAPPED(&ut_addr_v6)) { + /* map back */ + ut_addr_v6[0] = ut_addr_v6[3]; + ut_addr_v6[1] = 0; + ut_addr_v6[2] = 0; + ut_addr_v6[3] = 0; + } + if (ut_addr_v6[1] || ut_addr_v6[2] || ut_addr_v6[3]) { + /* IPv6 */ + if (!inet_ntop(AF_INET6, &ut_addr_v6, buf_ipv6, sizeof(buf_ipv6))) { + snprintf(buf_ipv6, INET6_ADDRSTRLEN, "?"); + } + strncpy(buf, buf_ipv6, MAX_FROM_LEN); + } else { + /* IPv4 */ + if (!inet_ntop(AF_INET, &ut_addr_v6[0], buf, sizeof(buf))) { + snprintf(buf, MAX_FROM_LEN, "?"); + } + } + buf[MAX_FROM_LEN] = 0; + for (len = strlen(buf); len < MAX_FROM_LEN; len++) buf[len]=' '; + buf[MAX_FROM_LEN] = 0; + fputs(buf, stdout); + } else { + print_host(u->ut_host, sizeof u->ut_host); + } } /***** compact 7 char format for time intervals (belongs in libproc?) */ @@ -169,7 +208,7 @@ static const proc_t *getproc(const utmp_t *restrict const u, const char *restric /***** showinfo */ -static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) { +static void showinfo(utmp_t *u, int formtype, int maxcmd, int from, int ip_addresses) { unsigned long long jcpu; int ut_pid_found; unsigned i; @@ -196,7 +235,7 @@ static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) { if (formtype) { printf("%-9.8s%-9.8s", uname, u->ut_line); if (from) - print_host(u->ut_host, sizeof u->ut_host); + print_from(u, ip_addresses); print_logintime(u->ut_time, stdout); if (*u->ut_line == ':') /* idle unknown for xdm logins */ printf(" ?xdm? "); @@ -211,7 +250,7 @@ static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) { } else { printf("%-9.8s%-9.8s", u->ut_user, u->ut_line); if (from) - print_host(u->ut_host, sizeof u->ut_host); + print_from(u, ip_addresses); if (*u->ut_line == ':') /* idle unknown for xdm logins */ printf(" ?xdm? "); else @@ -233,14 +272,22 @@ int main(int argc, char **argv) { char *user = NULL; utmp_t *u; struct winsize win; - int header=1, longform=1, from=1, args, maxcmd=80, ch; + int args; + int maxcmd = 80; + int ch; + + /* defaults */ + int header = 1; + int longform = 1; + int from = 1; + int ip_addresses = 0; #ifndef W_SHOWFROM from = 0; #endif setlocale(LC_ALL, ""); - for (args=0; (ch = getopt(argc, argv, "hlusfV")) != EOF; args++) + for (args=0; (ch = getopt(argc, argv, "hlusfnV")) != EOF; args++) switch (ch) { case 'h': header = 0; break; case 'l': longform = 1; break; @@ -248,6 +295,7 @@ int main(int argc, char **argv) { case 'f': from = !from; break; case 'V': display_version(); exit(0); case 'u': ignoreuser = 1; break; + case 'n': ip_addresses = 1; break; default: printf("usage: w -hlsufV [user]\n" " -h skip header\n" @@ -255,6 +303,7 @@ int main(int argc, char **argv) { " -s short listing\n" " -u ignore uid of processes\n" " -f toggle FROM field (default %s)\n" + " -n use IP addresses instead of hostname\n" " -V display version\n", FROM_STRING); exit(1); } @@ -292,14 +341,14 @@ int main(int argc, char **argv) { u = getutent(); if (unlikely(!u)) break; if (u->ut_type != USER_PROCESS) continue; - if (!strncmp(u->ut_user, user, USERSZ)) showinfo(u, longform, maxcmd, from); + if (!strncmp(u->ut_user, user, USERSZ)) showinfo(u, longform, maxcmd, from, ip_addresses); } } else { for (;;) { u = getutent(); if (unlikely(!u)) break; if (u->ut_type != USER_PROCESS) continue; - if (*u->ut_user) showinfo(u, longform, maxcmd, from); + if (*u->ut_user) showinfo(u, longform, maxcmd, from, ip_addresses); } } endutent();