top hotplug memory support

Another patch from Jim for top to support hot-pluggable memory. Not
fully tested on real hot-pluggable memory because neither of us have
it
This commit is contained in:
Craig Small 2011-07-14 21:16:02 +10:00
parent 29b8775c39
commit a26c3bfa39
7 changed files with 131 additions and 87 deletions

View File

@ -13,7 +13,7 @@ global:
Hertz; smp_num_cpus; have_privs; getbtime; Hertz; smp_num_cpus; have_privs; getbtime;
sprint_uptime; uptime; user_from_uid; print_uptime; loadavg; 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; 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_active; kb_inactive; kb_main_buffers; kb_main_cached;
kb_main_free; kb_main_total; kb_main_used; kb_swap_free; kb_main_free; kb_main_total; kb_main_used; kb_swap_free;
kb_swap_total; kb_swap_used; kb_main_shared; kb_swap_total; kb_swap_used; kb_main_shared;

View File

@ -24,9 +24,7 @@
#include <netinet/in.h> /* htons */ #include <netinet/in.h> /* htons */
#endif #endif
#ifndef OOMEM_ENABLE
long smp_num_cpus; /* number of CPUs */ long smp_num_cpus; /* number of CPUs */
#endif
#define BAD_OPEN_MESSAGE \ #define BAD_OPEN_MESSAGE \
"Error: /proc must be mounted\n" \ "Error: /proc must be mounted\n" \
@ -182,11 +180,7 @@ static void old_Hertz_hack(void){
setlocale(LC_NUMERIC, savelocale); setlocale(LC_NUMERIC, savelocale);
jiffies = user_j + nice_j + sys_j + other_j; jiffies = user_j + nice_j + sys_j + other_j;
seconds = (up_1 + up_2) / 2; seconds = (up_1 + up_2) / 2;
#ifndef OOMEM_ENABLE
h = (unsigned)( (double)jiffies/seconds/smp_num_cpus ); 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 */ /* actual values used by 2.4 kernels: 32 64 100 128 1000 1024 1200 */
switch(h){ switch(h){
case 9 ... 11 : Hertz = 10; break; /* S/390 (sometimes) */ case 9 ... 11 : Hertz = 10; break; /* S/390 (sometimes) */
@ -252,44 +246,13 @@ static int check_for_privs(void){
return !!rc; 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) __attribute__((constructor));
static void init_libproc(void){ static void init_libproc(void){
have_privs = check_for_privs(); have_privs = check_for_privs();
init_Linux_version(); /* Must be called before we check code */ init_Linux_version(); /* Must be called before we check code */
#ifndef OOMEM_ENABLE
// ought to count CPUs in /proc/stat instead of relying cpuinfo();
// 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
if(linux_version_code > LINUX_VERSION(2, 4, 0)){ if(linux_version_code > LINUX_VERSION(2, 4, 0)){
Hertz = find_elf_note(AT_CLKTCK); Hertz = find_elf_note(AT_CLKTCK);
if(Hertz!=NOTE_NOT_FOUND) return; if(Hertz!=NOTE_NOT_FOUND) return;
@ -978,3 +941,19 @@ unsigned get_pid_digits(void){
out: out:
return ret; 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;
}

View File

@ -7,12 +7,8 @@
EXTERN_C_BEGIN EXTERN_C_BEGIN
extern unsigned long long Hertz; /* clock tick frequency */ extern unsigned long long Hertz; /* clock tick frequency */
#ifndef OOMEM_ENABLE extern long smp_num_cpus; /* number of CPUs */
extern long smp_num_cpus; /* number of CPUs */ extern int have_privs; /* boolean, true if setuid or similar */
#else
extern long smp_num_cpus(void); /* number of CPUs */
#endif
extern int have_privs; /* boolean, true if setuid or similar */
#if 0 #if 0
#define JT double #define JT double
@ -136,5 +132,7 @@ extern unsigned int getslabinfo (struct slab_cache**);
extern unsigned get_pid_digits(void) FUNCTION; extern unsigned get_pid_digits(void) FUNCTION;
extern void cpuinfo (void);
EXTERN_C_END EXTERN_C_END
#endif /* SYSINFO_H */ #endif /* SYSINFO_H */

10
top.1
View File

@ -59,9 +59,9 @@
.ds FM full\-screen mode .ds FM full\-screen mode
.ds KA arrow key .ds KA arrow key
.ds KS scrolling key .ds KS scrolling key
.ds MP \fBphysical\fR memory .ds MP physical memory
.ds MS \fBshared\fR memory .ds MS shared memory
.ds MV \fBvirtual\fR memory .ds MV virtual memory
.ds NT \fBNote\fR: .ds NT \fBNote\fR:
.ds PU CPU .ds PU CPU
.ds Pu cpu .ds Pu cpu
@ -775,9 +775,9 @@ line.
.TP 7 .TP 7
\ \ \<\fBEnter\fR> or <\fBSpace\fR> :\fIRefresh-Display \fR \ \ \<\fBEnter\fR> or <\fBSpace\fR> :\fIRefresh-Display \fR
These commands do nothing, they are simply ignored. These commands awaken \*(We and following receipt of any input
However, they will awaken \*(We and following receipt of any input
the entire display will be repainted. 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 Use either of these keys if you have a large delay interval and wish
to see current status, to see current status,

51
top.c
View File

@ -1679,7 +1679,7 @@ static void zap_fieldstab (void) {
Cpu_pmax = 99.0; Cpu_pmax = 99.0;
Fieldstab[P_CPU].fmts = "%#4.1f "; 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; Cpu_pmax = 9999.0;
Fieldstab[P_CPU].fmts = "%4.0f "; Fieldstab[P_CPU].fmts = "%4.0f ";
} }
@ -1696,13 +1696,13 @@ static void zap_fieldstab (void) {
static CPU_t *cpus_refresh (CPU_t *cpus) { static CPU_t *cpus_refresh (CPU_t *cpus) {
static const char err_read[] = "failed /proc/stat read"; static const char err_read[] = "failed /proc/stat read";
static FILE *fp = NULL; 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) char buf[MEDBUFSIZ]; // enough for /proc/stat CPU line (not the intr line)
int i; int i;
/*** hotplug_acclimated ***/ /*** hotplug_acclimated ***/
if (smp_sav != SMP_NUM_CPUS) { if (sav_cpus != smp_num_cpus) {
Cpu_tot = smp_sav = SMP_NUM_CPUS; Cpu_tot = sav_cpus = smp_num_cpus;
zap_fieldstab(); zap_fieldstab();
calibrate_fields(); calibrate_fields();
if (fp) { fclose(fp); fp = NULL; } if (fp) { fclose(fp); fp = NULL; }
@ -2000,11 +2000,38 @@ static proc_t **procs_refresh (proc_t **ppt) {
#undef PTRsz #undef PTRsz
#undef ENTsz #undef ENTsz
} // end: procs_refresh } // 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 ##############################################*/ /*###### 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! */ * IMPORTANT stuff upon which all those lessor functions depend! */
static void before (char *me) { static void before (char *me) {
int i; int i;
@ -2015,10 +2042,9 @@ static void before (char *me) {
// establish cpu particulars -- even bigger! // establish cpu particulars -- even bigger!
#ifdef PRETEND4CPUS #ifdef PRETEND4CPUS
SMP_NUM_CPUS = Cpu_tot = 4; smp_num_cpus = 4;
#else
Cpu_tot = SMP_NUM_CPUS;
#endif #endif
Cpu_tot = smp_num_cpus;
if (linux_version_code > LINUX_VERSION(2, 5, 41)) if (linux_version_code > LINUX_VERSION(2, 5, 41))
Cpu_States_fmts = STATES_line2x5; Cpu_States_fmts = STATES_line2x5;
if (linux_version_code >= LINUX_VERSION(2, 6, 0)) if (linux_version_code >= LINUX_VERSION(2, 6, 0))
@ -2081,6 +2107,7 @@ static void configs_read (void) {
fbuf[0] = '\0'; fbuf[0] = '\0';
fgets(fbuf, sizeof(fbuf), fp); // sys rc file, line 2 fgets(fbuf, sizeof(fbuf), fp); // sys rc file, line 2
sscanf(fbuf, "%f", &Rc.delay_time); sscanf(fbuf, "%f", &Rc.delay_time);
fclose(fp);
} }
fp = fopen(Rc_name, "r"); fp = fopen(Rc_name, "r");
@ -3009,7 +3036,8 @@ static void do_key (int ch) {
help_view(); help_view();
break; break;
case kbd_ENTER: // these two will have the effect of waking us 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; break;
default: // and now, the real work... default: // and now, the real work...
for (i = 0; i < MAXTBL(key_tab); ++i) 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... // whoa first time, gotta' prime the pump...
if (!p_table) { if (!p_table) {
struct timeval tv = { 0, 300000 };
p_table = procs_refresh(NULL); p_table = procs_refresh(NULL);
putp(Cap_clr_scr); putp(Cap_clr_scr);
select(0, NULL, NULL, NULL, &tv); // sleep for a bit... usleep(LIB_USLEEP);
} else } else
putp(Batch ? "\n\n" : Cap_home); putp(Batch ? "\n\n" : Cap_home);
p_table = procs_refresh(p_table); p_table = procs_refresh(p_table);
sysinfo_refresh(0);
// Display Uptime and Loadavg // Display Uptime and Loadavg
if (isROOM(View_LOADAV, 1)) { if (isROOM(View_LOADAV, 1)) {
@ -3157,7 +3185,6 @@ static proc_t **summary_show (void) {
} }
// Display Memory and Swap stats // Display Memory and Swap stats
meminfo();
if (isROOM(View_MEMORY, 2)) { if (isROOM(View_MEMORY, 2)) {
#define mkM(x) (unsigned long)(kb_main_ ## x >> shift) #define mkM(x) (unsigned long)(kb_main_ ## x >> shift)
#define mkS(x) (unsigned long)(kb_swap_ ## x >> shift) #define mkS(x) (unsigned long)(kb_swap_ ## x >> shift)

17
top.h
View File

@ -62,23 +62,16 @@
#define STRSORTCMP strcmp #define STRSORTCMP strcmp
#endif #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 ##################################*/ /*###### Some Miscellaneous constants ##################################*/
/* The default delay twix updates */ /* The default delay twix updates */
#define DEF_DELAY 3.0 #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 MSG_USLEEP (useconds_t)1250000
#define LIB_USLEEP (useconds_t)150000
/* Specific process id monitoring support (command line only) */ /* Specific process id monitoring support (command line only) */
#define MONPIDMAX 20 #define MONPIDMAX 20
@ -592,9 +585,6 @@ typedef struct WIN_t {
#if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH) #if defined(ATEOJ_RPTHSH) && defined(OFF_HST_HASH)
# error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH' # error 'ATEOJ_RPTHSH' conflicts with 'OFF_HST_HASH'
#endif #endif
#if defined(PRETEND4CPUS) && defined (OOMEM_ENABLE)
# error 'PRETEND4CPUS' conflicts with 'OOMEM_ENABLE'
#endif
#if (LRGBUFSIZ < SCREENMAX) #if (LRGBUFSIZ < SCREENMAX)
# error 'LRGBUFSIZ' must NOT be less than 'SCREENMAX' # error 'LRGBUFSIZ' must NOT be less than 'SCREENMAX'
#endif #endif
@ -655,6 +645,7 @@ typedef struct WIN_t {
#endif #endif
//atic void prochlp (proc_t *p); //atic void prochlp (proc_t *p);
//atic proc_t **procs_refresh (proc_t **ppt); //atic proc_t **procs_refresh (proc_t **ppt);
//atic void sysinfo_refresh (int forced);
/*------ Startup routines ----------------------------------------------*/ /*------ Startup routines ----------------------------------------------*/
//atic void before (char *me); //atic void before (char *me);
//atic void configs_read (void); //atic void configs_read (void);

69
w.c
View File

@ -29,6 +29,7 @@
#include <utmp.h> #include <utmp.h>
#include <locale.h> #include <locale.h>
#include <termios.h> #include <termios.h>
#include <arpa/inet.h>
static int ignoreuser = 0; /* for '-u' */ static int ignoreuser = 0; /* for '-u' */
static proc_t **procs; /* our snapshot of the process table */ 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 */ /* Uh... same thing as UT_NAMESIZE */
#define USERSZ (sizeof u->ut_user) #define USERSZ (sizeof u->ut_user)
#define MAX_FROM_LEN 16
/* This routine is careful since some programs leave utmp strings /* This routine is careful since some programs leave utmp strings
* unprintable. Always outputs at least 16 chars padded with spaces * 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 /* for now, we'll just limit it to the 16 that the libc5 version
* of utmp uses. * of utmp uses.
*/ */
if (len > 16) len = 16; if (len > MAX_FROM_LEN) len = MAX_FROM_LEN;
last = host + len; last = host + len;
for ( ; host < last ; host++){ for ( ; host < last ; host++){
if (isprint(*host) && *host != ' ') { if (isprint(*host) && *host != ' ') {
@ -67,8 +69,45 @@ static void print_host(const char *restrict host, int len) {
break; break;
} }
} }
// space-fill, and a '-' too if needed to ensure the column exists /* space-fill, and a '-' too if needed to ensure the column exists */
if(width < 16) fputs("- "+width, stdout); 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?) */ /***** 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 */ /***** 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; unsigned long long jcpu;
int ut_pid_found; int ut_pid_found;
unsigned i; unsigned i;
@ -196,7 +235,7 @@ static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) {
if (formtype) { if (formtype) {
printf("%-9.8s%-9.8s", uname, u->ut_line); printf("%-9.8s%-9.8s", uname, u->ut_line);
if (from) if (from)
print_host(u->ut_host, sizeof u->ut_host); print_from(u, ip_addresses);
print_logintime(u->ut_time, stdout); print_logintime(u->ut_time, stdout);
if (*u->ut_line == ':') /* idle unknown for xdm logins */ if (*u->ut_line == ':') /* idle unknown for xdm logins */
printf(" ?xdm? "); printf(" ?xdm? ");
@ -211,7 +250,7 @@ static void showinfo(utmp_t *u, int formtype, int maxcmd, int from) {
} else { } else {
printf("%-9.8s%-9.8s", u->ut_user, u->ut_line); printf("%-9.8s%-9.8s", u->ut_user, u->ut_line);
if (from) 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 */ if (*u->ut_line == ':') /* idle unknown for xdm logins */
printf(" ?xdm? "); printf(" ?xdm? ");
else else
@ -233,14 +272,22 @@ int main(int argc, char **argv) {
char *user = NULL; char *user = NULL;
utmp_t *u; utmp_t *u;
struct winsize win; 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 #ifndef W_SHOWFROM
from = 0; from = 0;
#endif #endif
setlocale(LC_ALL, ""); 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) { switch (ch) {
case 'h': header = 0; break; case 'h': header = 0; break;
case 'l': longform = 1; break; case 'l': longform = 1; break;
@ -248,6 +295,7 @@ int main(int argc, char **argv) {
case 'f': from = !from; break; case 'f': from = !from; break;
case 'V': display_version(); exit(0); case 'V': display_version(); exit(0);
case 'u': ignoreuser = 1; break; case 'u': ignoreuser = 1; break;
case 'n': ip_addresses = 1; break;
default: default:
printf("usage: w -hlsufV [user]\n" printf("usage: w -hlsufV [user]\n"
" -h skip header\n" " -h skip header\n"
@ -255,6 +303,7 @@ int main(int argc, char **argv) {
" -s short listing\n" " -s short listing\n"
" -u ignore uid of processes\n" " -u ignore uid of processes\n"
" -f toggle FROM field (default %s)\n" " -f toggle FROM field (default %s)\n"
" -n use IP addresses instead of hostname\n"
" -V display version\n", FROM_STRING); " -V display version\n", FROM_STRING);
exit(1); exit(1);
} }
@ -292,14 +341,14 @@ int main(int argc, char **argv) {
u = getutent(); u = getutent();
if (unlikely(!u)) break; if (unlikely(!u)) break;
if (u->ut_type != USER_PROCESS) continue; 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 { } else {
for (;;) { for (;;) {
u = getutent(); u = getutent();
if (unlikely(!u)) break; if (unlikely(!u)) break;
if (u->ut_type != USER_PROCESS) continue; 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(); endutent();