diff options
| author | Paul Buetow (venus) <paul@buetow.org> | 2012-02-04 11:09:18 +0100 |
|---|---|---|
| committer | Paul Buetow (venus) <paul@buetow.org> | 2012-02-04 11:09:18 +0100 |
| commit | 9ae838a2982890ebb42c09185bbb36a063665b0c (patch) | |
| tree | 55312fc527a57dcc2d26fcaa06a7817699e6836c | |
| parent | 2ad50b481a05d30744531939ac5a108a06926110 (diff) | |
| parent | a9ee3fde00a793bfa58087342d8caac2287a1af8 (diff) | |
Merge remote-tracking branch 'remotes/origin/devel'
| -rw-r--r-- | BUGS | 3 | ||||
| -rw-r--r-- | CHANGELOG | 22 | ||||
| -rw-r--r-- | HELP | 15 | ||||
| -rw-r--r-- | WISHLIST | 3 | ||||
| -rw-r--r-- | loadbars | 1180 |
5 files changed, 787 insertions, 436 deletions
@@ -1 +1,2 @@ -* After quit ssh processes dont shut down instantly but later +* After quit ssh processes don't shut down instantly. But this is not an issue + since whey will quit automatically after 'samples' times. @@ -1,9 +1,19 @@ -Sun Jan 29 12:30:00 CET 2012 -* Releases v0.4.0.1 -* Fixed some docu typos -* Code cleanup: Replaced tabs by 4 whitespaces - -Sat Jan 21 18:32:45 CET 2012 +Sat Feb 4 10:56:27 CET 2012 +* Release v0.5.0 +* Add stats for rudimentary memory and swap usage (--showmem option or m hotkey) +* Remove --width and --inter options +* Add --barwidth option, each bar is barwidth pixels now +* Add --maxwidth option, which represents the max total window width +* Auto disable text display if text does not fit into window (maxwidth) pixels +* Auto re-enable text display if text does fit again into window +* Key right increases window width by 100px and left decreases by 100px +* Key down increases window height by 100px and up decreases by 100px +* Set 'samples' default values from 1000 down to 500. +* No sporadic crashes on shutdown anymore +* Some internal tweaks, no separate event thread needed anymore. This fixes + some sporadic bugs. + +Sun Jan 21 14:16:37 CET 2012 * Released v0.4.0 * Also show stats for idle, iowait, irq, softirq, steal and guest cpu time * Some parameters have been renamed (see --help) @@ -1,4 +1,4 @@ -Explanations: +CPU stuff: st = Steal in % [see man proc] (extended) Color: Red gt = Guest in % [see man proc] (extended) @@ -22,21 +22,28 @@ Explanations: avg = System load average; desc. order: 1, 5 and 15 min. avg. 1px horizontal line: Maximum sy+us+io of last 'avg' samples (extended) Extended means: text display only if extended mode is turned on +Memory stuff: + Ram: System ram usage in % + Color: Dark grey + Swp: System swap usage in % + Color: Grey Examples: - loadbars --extended 1 --showcores 1 --width 600 --hosts localhost + loadbars --extended 1 --showcores 1 --height 300 --hosts localhost loadbars --hosts localhost,server1.example.com,server2.example.com - loadbars --cluster foocluster (foocluster is in /etc/clusters of cssh) + loadbars --cluster foocluster (foocluster is in /etc/clusters [ClusterSSH]) --average <ARG> - Num of samples for avg. (more fluent animations) +--barwidth <ARG> - Set bar width --cluster <ARG> - Cluster name from /etc/clusters --extended <ARG> - Toggle extended display (0 or 1) --factor <ARG> - Set graph scale factor (1.0 means 100%) --height <ARG> - Set windows height --hosts <ARG> - Comma sep. list of hosts; optional: user@ in front to each host --inter <ARG> - Set update interval in seconds (default 0.1) +--maxwidth <ARG> - Set max width --samples <ARG> - Set number of samples until ssh reconnects --showcores <ARG> - Toggle core display (0 or 1) +--showmem <ARG> - Toggle mem display (0 or 1) --showtexthost <ARG> - Toggle hostname/num text display (0 or 1) --showtext <ARG> - Toggle text display (0 or 1) --sshopts <ARG> - Set SSH options --title <ARG> - Set the window title ---width <ARG> - Set windows width @@ -1,5 +1,4 @@ * Local configuration file for default values -* Stats for memory +* More stats for memory * Stats for network -* Dynamic/online resizing of the window * .deb for Debian and Ubuntu @@ -11,6 +11,7 @@ use warnings; use Getopt::Long; +use SDL; use SDL::App; use SDL::Rect; use SDL::Color; @@ -25,28 +26,29 @@ use threads; use threads::shared; use constant { - VERSION => 'loadbars v0.4.0.1', - Copyright => '2010 - 2012 (c) Paul Buetow <loadbars@mx.buetow.org>', - CSSH_CONFFILE => '/etc/clusters', + VERSION => 'loadbars v0.5.0', + Copyright => '2010-2012 (c) Paul Buetow <loadbars@mx.buetow.org>', + CSSH_CONFFILE => '/etc/clusters', CSSH_MAX_RECURSION => 10, - COLOR_DEPTH => 8, - BLACK => SDL::Color->new(-r => 0x00, -g => 0x00, -b => 0x00), - BLUE0=> SDL::Color->new(-r => 0x00, -g => 0x00, -b => 0xff), - BLUE => SDL::Color->new(-r => 0x00, -g => 0x00, -b => 0x88), - GREEN => SDL::Color->new(-r => 0x00, -g => 0x90, -b => 0x00), - ORANGE => SDL::Color->new(-r => 0xff, -g => 0x70, -b => 0x00), - PURPLE => SDL::Color->new(-r => 0xa0, -g => 0x20, -b => 0xf0), - RED => SDL::Color->new(-r => 0xff, -g => 0x00, -b => 0x00), - WHITE => SDL::Color->new(-r => 0xff, -g => 0xff, -b => 0xff), - GREY0 => SDL::Color->new(-r => 0x11, -g => 0x11, -b => 0x11), - GREY => SDL::Color->new(-r => 0xaa, -g => 0xaa, -b => 0xaa), - YELLOW0 => SDL::Color->new(-r => 0xff, -g => 0xa0, -b => 0x00), - YELLOW => SDL::Color->new(-r => 0xff, -g => 0xc0, -b => 0x00), - SYSTEM_BLUE0 => 30, - USER_ORANGE => 70, - USER_YELLOW0 => 50, - NULL => 0, - DEBUG => 0, + COLOR_DEPTH => 8, + BLACK => SDL::Color->new( -r => 0x00, -g => 0x00, -b => 0x00 ), + BLUE0 => SDL::Color->new( -r => 0x00, -g => 0x00, -b => 0xff ), + BLUE => SDL::Color->new( -r => 0x00, -g => 0x00, -b => 0x88 ), + GREEN => SDL::Color->new( -r => 0x00, -g => 0x90, -b => 0x00 ), + ORANGE => SDL::Color->new( -r => 0xff, -g => 0x70, -b => 0x00 ), + PURPLE => SDL::Color->new( -r => 0xa0, -g => 0x20, -b => 0xf0 ), + RED => SDL::Color->new( -r => 0xff, -g => 0x00, -b => 0x00 ), + WHITE => SDL::Color->new( -r => 0xff, -g => 0xff, -b => 0xff ), + GREY0 => SDL::Color->new( -r => 0x11, -g => 0x11, -b => 0x11 ), + GREY => SDL::Color->new( -r => 0xaa, -g => 0xaa, -b => 0xaa ), + DARK_GREY => SDL::Color->new( -r => 0x15, -g => 0x15, -b => 0x15 ), + YELLOW0 => SDL::Color->new( -r => 0xff, -g => 0xa0, -b => 0x00 ), + YELLOW => SDL::Color->new( -r => 0xff, -g => 0xc0, -b => 0x00 ), + SYSTEM_BLUE0 => 30, + USER_ORANGE => 70, + USER_YELLOW0 => 50, + INTERVAL => 0.1, + INTERVAL_WARN => 1.0, }; $| = 1; @@ -54,25 +56,30 @@ $| = 1; my %AVGSTATS : shared; my %CPUSTATS : shared; my %MEMSTATS : shared; +my %MEMSTATS_HAS : shared; +#my %NETSTATS : shared; +#my %NETSTATS_HAS : shared; # Global configuration hash my %C : shared; # Setting defaults %C = ( - title => Loadbars::VERSION . ' (press h for help on stdout)', - average => 15, - showcores => 0, - cpuregexp => 'cpu', - factor => 1, - extended => 0, - displaytxt => 1, + title => Loadbars::VERSION . ' (press h for help on stdout)', + average => 15, + showcores => 0, + showmem => 0, + cpuregexp => 'cpu', + factor => 1, + extended => 0, + displaytxt => 1, + displaytxtoff => 0, displaytxthost => 0, - inter => 0.1, - samples => 1000, - sshopts => '', - width => 1250, - height => 230, + samples => 500, + sshopts => '', + barwidth => 35, + maxwidth => 1280, + height => 230, ); # Quick n dirty helpers @@ -80,39 +87,50 @@ sub say (@) { print "$_\n" for @_; return undef } sub newline () { say ''; return undef } sub debugsay (@) { say "Loadbars::DEBUG: $_" for @_; return undef } sub sum (@) { my $sum = 0; $sum += $_ for @_; return $sum } -sub null ($) { my $arg = shift; return defined $arg ? $arg : 0 } +sub null ($) { defined $_[0] ? $_[0] : 0 } +sub notnull ($) { $_[0] != 0 ? $_[0] : 1 } sub set_showcores_regexp () { $C{cpuregexp} = $C{showcores} ? 'cpu' : 'cpu ' } sub error ($) { die shift, "\n" } +sub display_info ($) { say "==> " . shift } -sub norm ($) { - my $n = shift; +sub percentage ($$) { + my ($total, $part) = @_; + + return int (null($part) / notnull ( null($total) / 100 )); +} + +sub norm ($) { + my $n = shift; return $n if $C{factor} != 1; - return $n > 100 ? 100 : ($n < 0 ? 0 : $n); + return $n > 100 ? 100 : ( $n < 0 ? 0 : $n ); } sub parse_cpu_line ($) { my $line = shift; - my ($name, %load); + my ( $name, %load ); - ($name, @load{qw(user nice system idle iowait irq softirq steal guest)}) = split ' ', $line; + ( $name, @load{qw(user nice system idle iowait irq softirq steal guest)} ) = + split ' ', $line; $load{steal} = 0 unless defined $load{steal}; $load{guest} = 0 unless defined $load{guest}; - $load{TOTAL} = sum @load{qw(user nice system idle iowait irq softirq steal guest)}; + $load{TOTAL} = + sum @load{qw(user nice system idle iowait irq softirq steal guest)}; - return ($name, \%load); + return ( $name, \%load ); } sub thread_get_stats ($;$) { - my ($host, $user) = @_; - $user = defined $user ? "-l $user" : ''; + my ( $host, $user ) = @_; + $user = defined $user ? "-l $user" : ''; - my ($sigusr1, $quit) = (0, 0); + my ( $sigusr1, $quit ) = ( 0, 0 ); my $loadavgexp = qr/(\d+\.\d{2}) (\d+\.\d{2}) (\d+\.\d{2})/; + my $inter = INTERVAL; - for (;;) { + for ( ; ; ) { my $bash = <<"BASH"; if [ -e /proc/stat ]; then loadavg=/proc/loadavg @@ -120,8 +138,11 @@ sub thread_get_stats ($;$) { meminfo=/proc/meminfo for i in \$(seq $C{samples}); do - cat \$loadavg \$stat \$meminfo - sleep $C{inter} + echo CPUSTATS + cat \$loadavg \$stat + echo MEMSTATS + cat \$meminfo + sleep $inter done else loadavg=/compat/linux/proc/loadavg @@ -129,14 +150,15 @@ sub thread_get_stats ($;$) { for i in \$(jot $C{samples}); do cat \$loadavg \$stat - sleep $C{inter} + sleep $inter done fi BASH - - my $cmd = $host eq 'localhost' ? $bash - : "ssh $user -o StrictHostKeyChecking=no $C{sshopts} $host '$bash'"; + my $cmd = + ($host eq 'localhost' || $host eq '127.0.0.1') + ? $bash + : "ssh $user -o StrictHostKeyChecking=no $C{sshopts} $host '$bash'"; my $pid = open my $pipe, "$cmd |" or do { say "Warning: $!"; @@ -147,31 +169,51 @@ BASH # Toggle CPUs $SIG{USR1} = sub { $sigusr1 = 1 }; my $cpuregexp = qr/$C{cpuregexp}/; + # 1=cpu, 2=mem, 3=net + my $mode = 0; + + while (<$pipe>) { + chomp; - while (<$pipe>) { - if (/^$loadavgexp/) { - $AVGSTATS{$host} = "$1;$2;$3"; + if ($mode == 0) { + if ($_ eq 'MEMSTATS') { + $mode = 1; - } elsif (/$cpuregexp/) { - my ($name, $load) = parse_cpu_line $_; - $CPUSTATS{"$host;$name"} = join ';', - map { $_ . '=' . $load->{$_} } - grep { defined $load->{$_} } keys %$load; + } elsif (/^$loadavgexp/) { + $AVGSTATS{$host} = "$1;$2;$3"; + + } elsif (/$cpuregexp/) { + my ( $name, $load ) = parse_cpu_line $_; + $CPUSTATS{"$host;$name"} = join ';', + map { $_ . '=' . $load->{$_} } + grep { defined $load->{$_} } keys %$load; + } + } elsif ($mode == 1) { + if ($_ eq 'CPUSTATS') { + $mode = 0; + + } else { + for my $meminfo (qw(MemTotal MemFree Buffers Cached SwapTotal SwapFree)) { + if (/^$meminfo: *(\d+)/) { + $MEMSTATS_HAS{$host} = 1; + $MEMSTATS{"$host;$meminfo"} = $1; + } + } + } } if ($sigusr1) { $cpuregexp = qr/$C{cpuregexp}/; - $sigusr1 = 0; + $sigusr1 = 0; } } - - } + } return undef; } sub get_rect ($$) { - my ($rects, $name) = @_; + my ( $rects, $name ) = @_; return $rects->{$name} if exists $rects->{$name}; return $rects->{$name} = SDL::Rect->new(); @@ -183,438 +225,557 @@ sub normalize_loads (%) { return %loads unless exists $loads{TOTAL}; my $total = $loads{TOTAL} == 0 ? 1 : $loads{TOTAL}; - return map { $_ => $loads{$_} / ($total / 100) } keys %loads; + return map { $_ => $loads{$_} / ( $total / 100 ) } keys %loads; } sub get_cpuaverage ($@) { - my ($factor, @loads) = @_; - my (%cpumax, %cpuaverage); + my ( $factor, @loads ) = @_; + my ( %cpumax, %cpuaverage ); for my $l (@loads) { - for (keys %$l) { - $cpuaverage{$_} += $l->{$_}; + for ( keys %$l ) { + $cpuaverage{$_} += $l->{$_}; - $cpumax{$_} = $l->{$_} - if not exists $cpumax{$_} or $cpumax{$_} < $l->{$_}; - } + $cpumax{$_} = $l->{$_} + if not exists $cpumax{$_} + or $cpumax{$_} < $l->{$_}; + } } my $div = @loads / $factor; - for (keys %cpuaverage) { - $cpuaverage{$_} /= $div; - $cpumax{$_} /= $factor; - } + for ( keys %cpuaverage ) { + $cpuaverage{$_} /= $div; + $cpumax{$_} /= $factor; + } - return (\%cpumax, \%cpuaverage); + return ( \%cpumax, \%cpuaverage ); } sub draw_background ($$) { - my ($app, $rects) = @_; + my ( $app, $rects ) = @_; my $rect = get_rect $rects, 'background'; - $rect->width($C{width}); - $rect->height($C{height}); - $app->fill($rect, Loadbars::BLACK); + $rect->width( $C{width} ); + $rect->height( $C{height} ); + $app->fill( $rect, Loadbars::BLACK ); $app->update($rect); return undef; } sub create_threads (@) { - return map { - $_->detach(); + return map { + $_->detach(); $_; - } map { - threads->create('thread_get_stats', split /:/); + } map { + threads->create( 'thread_get_stats', split /:/ ); + + } @_; +} + +sub auto_off_text ($) { + my ($barwidth) = @_; + + if ($barwidth < $C{barwidth} - 1 && $C{displaytxtoff} == 0) { + display_info 'Disabling text display, text does not fit into window. Use \'t\' to re-enable.'; + $C{displaytxtoff} = 1; + $C{displaytxt} = 0; - } @_; + } elsif ($C{displaytxtoff} && $barwidth >= $C{barwidth} - 1) { + display_info 'Re-enabling text display, text fits into window now.'; + $C{displaytxt} = 1; + $C{displaytxtoff} = 0; + } +} + +sub set_dimensions ($$) { + my ($width, $height) = @_; + my $display_info = 0; + + if ($width < 1) { + $C{width} = 1 if $C{width} != 1; + + } elsif ($width > $C{maxwidth}) { + $C{width} = $C{maxwidth} if $C{width} != $C{maxwidth}; + + } elsif ($C{width} != $width) { + $C{width} = $width; + } + + if ($height < 1) { + $C{height} = 1 if $C{height} != 1; + + } elsif ($C{height} != $height) { + $C{height} = $height; + } } sub main_loop ($@) { - my ($dispatch, @threads) = @_; + my ( $dispatch, @threads ) = @_; + + my $num_stats = 1; + $C{width} = $C{barwidth}; my $app = SDL::App->new( - -title => $C{title}, + -title => $C{title}, -icon_title => $C{title}, - -width => $C{width}, - -height => $C{height}, - -depth => Loadbars::COLOR_DEPTH, - -resizeable => 0, + -width => $C{width}, + -height => $C{height}, + -depth => Loadbars::COLOR_DEPTH, + -resizeable => 1, ); SDL::Font->new('font.png')->use(); - my $num_stats = keys %CPUSTATS; - my $rects = {}; my %prev_stats; my %last_loads; my $redraw_background = 0; - my $font_height = 14; + my $font_height = 14; - my $displayinfo_time = 5; - my $displayinfo_start = 0; - my $displayinfo : shared = ''; my $infotxt : shared = ''; my $quit : shared = 0; - - my ($t1, $t2) = (Time::HiRes::time(), undef); + my $resize_window : shared = 0; + my %newsize : shared; my $event = SDL::Event->new(); - my $event_thread = async { - for (;;) { - $event->pump(); - $event->poll(); - $event->wait(); - - my $type = $event->type(); - my $key_name = $event->key_name(); - - debugsay "Event type=$type key_name=$key_name" if Loadbars::DEBUG; - next if $type != 2; + my ( $t1, $t2 ) = ( Time::HiRes::time(), undef ); - if ($key_name eq '1') { + my $event_handler = sub { + while ($event->poll() == 1) { + next if $event->type() != 2; + my $key_name = $event->key_name(); + + if ( $key_name eq '1' ) { $C{showcores} = !$C{showcores}; set_showcores_regexp; $_->kill('USR1') for @threads; - %AVGSTATS = (); - %CPUSTATS = (); - $displayinfo = 'Toggled CPUs'; + %AVGSTATS = (); + %CPUSTATS = (); + display_info 'Toggled CPUs'; - } elsif ($key_name eq 'e') { - $C{extended} = !$C{extended}; - $displayinfo = 'Toggled extended display'; + } + elsif ( $key_name eq 'e' ) { + $C{extended} = !$C{extended}; + display_info 'Toggled extended display'; - } elsif ($key_name eq 'h') { + } + elsif ( $key_name eq 'h' ) { say '=> Hotkeys to use in the SDL interface'; say $dispatch->('hotkeys'); - $displayinfo = 'Hotkeys help printed on terminal stdout'; - - } elsif ($key_name eq 't') { - $C{displaytxt} = !$C{displaytxt}; - $displayinfo = 'Toggled text display'; + display_info 'Hotkeys help printed on terminal stdout'; - } elsif ($key_name eq 'u') { - $C{displaytxthost} = !$C{displaytxthost}; - $displayinfo = 'Toggled number/hostname display'; - - } elsif ($key_name eq 'q') { + } + elsif ( $key_name eq 'm' ) { + $C{showmem} = !$C{showmem}; + display_info 'Toggled show mem'; + + } + elsif ( $key_name eq 't' ) { + $C{displaytxt} = !$C{displaytxt}; + display_info 'Toggled text display'; + + } + elsif ( $key_name eq 'u' ) { + $C{displaytxthost} = !$C{displaytxthost}; + display_info 'Toggled number/hostname display'; + + } + elsif ( $key_name eq 'q' ) { $quit = 1; - last; - - # Increase and decrease pairs - } elsif ($key_name eq 'a') { + return; + + } + elsif ( $key_name eq 'a' ) { ++$C{average}; - $displayinfo = "Set sample average to $C{average}"; - } elsif ($key_name eq 'y' or $key_name eq 'z') { + display_info "Set sample average to $C{average}"; + } + elsif ( $key_name eq 'y' or $key_name eq 'z' ) { my $avg = $C{average}; --$avg; $C{average} = $avg > 1 ? $avg : 2; - $displayinfo = "Set sample average to $C{average}"; + display_info "Set sample average to $C{average}"; - } elsif ($key_name eq 's') { + } + elsif ( $key_name eq 's' ) { $C{factor} += 0.1; - $displayinfo = "Set scale factor to $C{factor}"; - } elsif ($key_name eq 'x' or $key_name eq 'z') { + display_info "Set scale factor to $C{factor}"; + } + elsif ( $key_name eq 'x' or $key_name eq 'z' ) { $C{factor} -= 0.1; - $displayinfo = "Set scale factor to $C{factor}"; - - } elsif ($key_name eq 'd') { - $C{inter} += 0.1; - $displayinfo = "Set graph update interval to $C{inter}"; - } elsif ($key_name eq 'c' or $key_name eq 'z') { - my $int = $C{inter}; - $int -= 0.1; - $C{inter} = $int > 0 ? $int : 0.1; - $displayinfo = "Set graph update interval to $C{inter}"; + display_info "Set scale factor to $C{factor}"; + + } + elsif ( $key_name eq 'left') { + $newsize{width} = $C{width} - 100; + $newsize{height} = $C{height}; + $resize_window = 1; + } + elsif ( $key_name eq 'right' ) { + $newsize{width} = $C{width} + 100; + $newsize{height} = $C{height}; + $resize_window = 1; + } + elsif ( $key_name eq 'up' ) { + $newsize{width} = $C{width}; + $newsize{height} = $C{height} - 100; + $resize_window = 1; + } + elsif ( $key_name eq 'down' ) { + $newsize{width} = $C{width}; + $newsize{height} = $C{height} + 100; + $resize_window = 1; } } }; do { - my ($x, $y) = (0, 0); - my %is_host_summary; - - my $new_num_stats = keys %CPUSTATS; + my ( $x, $y ) = ( 0, 0 ); - if ($new_num_stats != $num_stats) { - %prev_stats = (); - %last_loads = (); - - $num_stats = $new_num_stats; - $redraw_background = 1; - } - - # Avoid division by null # Also substract 1 (each bar is followed by an 1px separator bar) - my $width = $C{width} / ($num_stats ? $num_stats : 1) - 1; + my $width = $C{width} / notnull($num_stats) - 1; - my ($current_barnum, $current_corenum) = (-1, -1); + my ( $current_barnum, $current_corenum ) = ( -1, -1 ); - for my $key (sort keys %CPUSTATS) { - ++$current_barnum; + for my $key ( sort keys %CPUSTATS ) { + last if (++$current_barnum > $num_stats); ++$current_corenum; - my ($host, $name) = split ';', $key; + my ( $host, $name ) = split ';', $key; next unless defined $CPUSTATS{$key}; - my %stat = map { - my ($k, $v) = split '='; $k => $v + my %stat = map { + my ( $k, $v ) = split '='; + $k => $v } split ';', $CPUSTATS{$key}; - unless (exists $prev_stats{$key}) { + unless ( exists $prev_stats{$key} ) { $prev_stats{$key} = \%stat; next; } my $prev_stat = $prev_stats{$key}; - my %loads = null $stat{TOTAL} == null $prev_stat->{TOTAL} - ? %stat : map { - $_ => $stat{$_} - $prev_stat->{$_} - } keys %stat; + my %loads = + null $stat{TOTAL} == null $prev_stat->{TOTAL} + ? %stat + : map { $_ => $stat{$_} - $prev_stat->{$_} } keys %stat; $prev_stats{$key} = \%stat; %loads = normalize_loads %loads; - push @{$last_loads{$key}}, \%loads; - shift @{$last_loads{$key}} while @{$last_loads{$key}} >= $C{average}; + push @{ $last_loads{$key} }, \%loads; + shift @{ $last_loads{$key} } + while @{ $last_loads{$key} } >= $C{average}; - my ($cpumax, $cpuaverage) = get_cpuaverage $C{factor}, @{$last_loads{$key}}; + my ( $cpumax, $cpuaverage ) = get_cpuaverage $C{factor}, + @{ $last_loads{$key} }; - my %heights = map { - $_ => defined $cpuaverage->{$_} ? $cpuaverage->{$_} * ($C{height}/100) : 1 + my %heights = map { + $_ => defined $cpuaverage->{$_} + ? $cpuaverage->{$_} * ( $C{height} / 100 ) + : 1 } keys %$cpuaverage; - my $is_host_summary = exists $is_host_summary{$host}; - + my $is_host_summary = $name eq 'cpu' ? 1 : 0; + my $rect_separator = undef; - my $rect_idle = get_rect $rects, "$key;idle"; - my $rect_steal = get_rect $rects, "$key;steal"; - my $rect_guest = get_rect $rects, "$key;guest"; - my $rect_irq = get_rect $rects, "$key;irq"; + my $rect_idle = get_rect $rects, "$key;idle"; + my $rect_steal = get_rect $rects, "$key;steal"; + my $rect_guest = get_rect $rects, "$key;guest"; + my $rect_irq = get_rect $rects, "$key;irq"; my $rect_softirq = get_rect $rects, "$key;softirq"; - my $rect_nice = get_rect $rects, "$key;nice"; - my $rect_iowait = get_rect $rects, "$key;iowait"; - my $rect_user = get_rect $rects, "$key;user"; - my $rect_system = get_rect $rects, "$key;system"; - - my $rect_peak; - - unless ($is_host_summary || !$C{showcores}) { - $current_corenum = 0; - $rect_separator = get_rect $rects, "$key;separator"; - $rect_separator->width(1); - $rect_separator->height($C{height}); - $rect_separator->x($x-1); - $rect_separator->y(0); - $app->fill($rect_separator, Loadbars::GREY); - } - + my $rect_nice = get_rect $rects, "$key;nice"; + my $rect_iowait = get_rect $rects, "$key;iowait"; + my $rect_user = get_rect $rects, "$key;user"; + my $rect_system = get_rect $rects, "$key;system"; + + my $rect_peak; + $y = $C{height} - $heights{system}; $rect_system->width($width); - $rect_system->height($heights{system}); + $rect_system->height( $heights{system} ); $rect_system->x($x); $rect_system->y($y); - + $y -= $heights{user}; $rect_user->width($width); - $rect_user->height($heights{user}); + $rect_user->height( $heights{user} ); $rect_user->x($x); $rect_user->y($y); - + $y -= $heights{nice}; $rect_nice->width($width); - $rect_nice->height($heights{nice}); + $rect_nice->height( $heights{nice} ); $rect_nice->x($x); $rect_nice->y($y); - + $y -= $heights{idle}; $rect_idle->width($width); - $rect_idle->height($heights{idle}); + $rect_idle->height( $heights{idle} ); $rect_idle->x($x); $rect_idle->y($y); $y -= $heights{iowait}; $rect_iowait->width($width); - $rect_iowait->height($heights{iowait}); + $rect_iowait->height( $heights{iowait} ); $rect_iowait->x($x); $rect_iowait->y($y); - + $y -= $heights{irq}; $rect_irq->width($width); - $rect_irq->height($heights{irq}); + $rect_irq->height( $heights{irq} ); $rect_irq->x($x); $rect_irq->y($y); $y -= $heights{softirq}; $rect_softirq->width($width); - $rect_softirq->height($heights{softirq}); + $rect_softirq->height( $heights{softirq} ); $rect_softirq->x($x); $rect_softirq->y($y); - + $y -= $heights{guest}; $rect_guest->width($width); - $rect_guest->height($heights{guest}); + $rect_guest->height( $heights{guest} ); $rect_guest->x($x); $rect_guest->y($y); $y -= $heights{steal}; $rect_steal->width($width); - $rect_steal->height($heights{steal}); + $rect_steal->height( $heights{steal} ); $rect_steal->x($x); $rect_steal->y($y); - my $all = 100 - $cpuaverage->{idle}; + my $all = 100 - $cpuaverage->{idle}; my $max_all = 0; - - $app->fill($rect_idle, Loadbars::BLACK); - $app->fill($rect_steal, Loadbars::RED); - $app->fill($rect_guest, Loadbars::RED); - $app->fill($rect_irq, Loadbars::WHITE); - $app->fill($rect_softirq, Loadbars::WHITE); - $app->fill($rect_nice, Loadbars::GREEN); - $app->fill($rect_iowait, Loadbars::PURPLE); - - if ($C{extended}) { + + $app->fill( $rect_idle, Loadbars::BLACK ); + $app->fill( $rect_steal, Loadbars::RED ); + $app->fill( $rect_guest, Loadbars::RED ); + $app->fill( $rect_irq, Loadbars::WHITE ); + $app->fill( $rect_softirq, Loadbars::WHITE ); + $app->fill( $rect_nice, Loadbars::GREEN ); + $app->fill( $rect_iowait, Loadbars::PURPLE ); + + my $add_x = 0; + my $rect_memused = get_rect $rects, "$host;memused"; + my $rect_memfree = get_rect $rects, "$host;memfree"; + my $rect_buffers = get_rect $rects, "$host;buffers"; + my $rect_cached = get_rect $rects, "$host;cached"; + my $rect_swapused = get_rect $rects, "$host;swapused"; + my $rect_swapfree = get_rect $rects, "$host;swapfree"; + + my %meminfo; + if ( $is_host_summary ) { + if ( $C{showmem} ) { + $add_x = $width + 1; + + my $ram_per = percentage $MEMSTATS{"$host;MemTotal"}, $MEMSTATS{"$host;MemFree"}; + my $swap_per = percentage $MEMSTATS{"$host;SwapTotal"}, $MEMSTATS{"$host;SwapFree"}; + + %meminfo = ( + ram_per => $ram_per, + swap_per => $swap_per, + ); + + my %heights = ( + MemFree => $ram_per * ( $C{height} / 100 ), + MemUsed => (100 - $ram_per) * ( $C{height} / 100 ), + SwapFree => $swap_per * ( $C{height} / 100 ), + SwapUsed => (100 - $swap_per) * ( $C{height} / 100 ), + ); + + my $half_width = $width / 2; + $y = $C{height} - $heights{MemUsed}; + $rect_memused->width($half_width); + $rect_memused->height( $heights{MemUsed} ); + $rect_memused->x($x+$add_x); + $rect_memused->y($y); + + $y -= $heights{MemFree}; + $rect_memfree->width($half_width); + $rect_memfree->height( $heights{MemFree} ); + $rect_memfree->x($x+$add_x); + $rect_memfree->y($y); + + $y = $C{height} - $heights{SwapUsed}; + $rect_swapused->width($half_width); + $rect_swapused->height( $heights{SwapUsed} ); + $rect_swapused->x($x+$add_x+$half_width); + $rect_swapused->y($y); + + $y -= $heights{SwapFree}; + $rect_swapfree->width($half_width); + $rect_swapfree->height( $heights{SwapFree} ); + $rect_swapfree->x($x+$add_x+$half_width); + $rect_swapfree->y($y); + + $app->fill( $rect_memused, Loadbars::DARK_GREY ); + $app->fill( $rect_memfree, Loadbars::BLACK ); + + $app->fill( $rect_swapused, Loadbars::GREY ); + $app->fill( $rect_swapfree, Loadbars::BLACK ); + } + + if ( $C{showcores} ) { + $current_corenum = 0; + $rect_separator = get_rect $rects, "$key;separator"; + $rect_separator->width(1); + $rect_separator->height( $C{height} ); + $rect_separator->x( $x - 1 ); + $rect_separator->y(0); + $app->fill( $rect_separator, Loadbars::GREY ); + } + } + + if ( $C{extended} ) { my %maxheights = map { - $_ => defined $cpumax->{$_} ? $cpumax->{$_} * ($C{height}/100) : 1 - } keys %$cpumax; - + $_ => defined $cpumax->{$_} + ? $cpumax->{$_} * ( $C{height} / 100 ) + : 1 + } keys %$cpumax; + $rect_peak = get_rect $rects, "$key;max"; $rect_peak->width($width); - $rect_peak->height(1); - $rect_peak->x($x); - $rect_peak->y($C{height} - $maxheights{system} - $maxheights{user}); - - $max_all = sum @{$cpumax}{qw(user system iowait irq softirq steal guest)}; - - $app->fill($rect_peak, $max_all > Loadbars::USER_ORANGE ? Loadbars::ORANGE - : ($max_all > Loadbars::USER_YELLOW0 ? Loadbars::YELLOW0 - : (Loadbars::YELLOW))); + $rect_peak->height(1); + $rect_peak->x($x); + $rect_peak->y( $C{height} - $maxheights{system} - $maxheights{user} ); + + $max_all = sum @{$cpumax} {qw(user system iowait irq softirq steal guest)}; + + $app->fill( $rect_peak, $max_all > Loadbars::USER_ORANGE ? Loadbars::ORANGE + : ( $max_all > Loadbars::USER_YELLOW0 ? Loadbars::YELLOW0 : (Loadbars::YELLOW))); } - $app->fill($rect_user, $all > Loadbars::USER_ORANGE ? Loadbars::ORANGE - : ($all > Loadbars::USER_YELLOW0 ? Loadbars::YELLOW0 - : (Loadbars::YELLOW))); - $app->fill($rect_system, $cpuaverage->{system} > Loadbars::SYSTEM_BLUE0 ? Loadbars::BLUE0 - : Loadbars::BLUE); - - my ($y, $space) = (5, $font_height); + $app->fill( $rect_user, $all > Loadbars::USER_ORANGE ? Loadbars::ORANGE + : ( $all > Loadbars::USER_YELLOW0 ? Loadbars::YELLOW0 : (Loadbars::YELLOW))); + $app->fill( $rect_system, $cpuaverage->{system} > Loadbars::SYSTEM_BLUE0 + ? Loadbars::BLUE0 : Loadbars::BLUE ); + + my ( $y, $space ) = ( 5, $font_height ); + my @loadavg = split ';', $AVGSTATS{$host}; - $is_host_summary{$host} = 1 if defined $loadavg[0]; - if ($C{displaytxt}) { - if ($C{displaytxthost} && not $is_host_summary) { + if ( $C{displaytxt} ) { + if ( $C{showmem} && $is_host_summary ) { + my $y_ = $y; + $app->print( $x+$add_x, $y_, 'Ram:'); + $app->print( $x+$add_x, $y_ += $space, sprintf '%02d', (100-$meminfo{ram_per})); + $app->print( $x+$add_x, $y_ += $space, 'Swp:'); + $app->print( $x+$add_x, $y_ += $space, sprintf '%02d', (100-$meminfo{swap_per})); + } + if ( $C{displaytxthost} && $is_host_summary ) { # If hostname is printed don't use FQDN # because of its length. $host =~ /([^\.]*)/; - $app->print($x, $y, sprintf '%s:', $1); + $app->print( $x, $y, sprintf '%s:', $1 ); - } else { - $app->print($x, $y, sprintf '%i:', - $C{showcores} ? $current_corenum : $current_barnum + 1); + } + else { + $app->print( $x, $y, sprintf '%i:', $C{showcores} ? $current_corenum : $current_barnum + 1 ); } - - if ($C{extended}) { - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{steal}, 'st'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{guest}, 'gt'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{softirq}, 'sr'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{irq}, 'ir'); + if ( $C{extended} ) { + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{steal}, 'st'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{guest}, 'gt'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{softirq}, 'sr'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{irq}, 'ir'); } - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{iowait}, 'io'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{iowait}, 'io'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{idle}, 'id') if $C{extended}; + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{idle}, 'id') if $C{extended}; - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{nice}, 'ni'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{user}, 'us'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $cpuaverage->{system}, 'sy'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $all, 'to'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{nice}, 'ni'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{user}, 'us'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $cpuaverage->{system}, 'sy'); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $all, 'to'); - $app->print($x, $y+=$space, sprintf '%02d%s', norm $max_all, 'pk') if $C{extended}; - - unless ($is_host_summary) { - if (defined $loadavg[0]) { - $app->print($x, $y+=$space, 'avg:'); - $app->print($x, $y+=$space, sprintf "%.2f", $loadavg[0]); - $app->print($x, $y+=$space, sprintf "%.2f", $loadavg[1]); - $app->print($x, $y+=$space, sprintf "%.2f", $loadavg[2]); + $app->print( $x, $y += $space, sprintf '%02d%s', norm $max_all, 'pk') if $C{extended}; + + if ($is_host_summary) { + if ( defined $loadavg[0] ) { + $app->print( $x, $y += $space, 'Avg:' ); + $app->print( $x, $y += $space, sprintf "%.2f", $loadavg[0]); + $app->print( $x, $y += $space, sprintf "%.2f", $loadavg[1]); + $app->print( $x, $y += $space, sprintf "%.2f", $loadavg[2]); } } } - # Display an informational text message if any - #$app->print(0, $y+=$space, $displayinfo) if length $displayinfo; - if (length $displayinfo) { - say $displayinfo; - $displayinfo = ''; - } - $app->update( - $rect_idle, - $rect_iowait, - $rect_irq, - $rect_nice, - $rect_softirq, - $rect_steal, - $rect_guest, - $rect_system, - $rect_user, - ); + $rect_idle, $rect_iowait, $rect_irq, + $rect_nice, $rect_softirq, $rect_steal, + $rect_guest, $rect_system, $rect_user, + ); + $app->update( $rect_memfree, $rect_memused, $rect_swapused, $rect_swapfree ) if $C{showmem}; $app->update($rect_separator) if defined $rect_separator; - $x += $width + 1; + $x += $width + 1 + $add_x; + } -TIMEKEEPER: + TIMEKEEPER: $t2 = Time::HiRes::time(); + my $t_diff = $t2 - $t1; - if (length $displayinfo) { - if ($displayinfo_start == 0) { - $displayinfo_start = $t2; + if ( INTERVAL > $t_diff ) { + usleep 10000; + + # Goto is OK if you don't produce spaghetti code + goto TIMEKEEPER; - } else { - if ($displayinfo_time < $t2 - $displayinfo_start) { - $displayinfo = ''; - $displayinfo_start = 0; - } - } + } elsif ( INTERVAL_WARN < $t_diff ) { + display_info "WARN: Loop is behind $t_diff seconds, your computer may be too slow"; } + $t1 = $t2; - if ($C{inter} > $t2 - $t1) { - usleep 10000; - # Goto is OK if you don't produce spaghetti code - goto TIMEKEEPER; + $event_handler->(); + + my $new_num_stats = keys %CPUSTATS; + $new_num_stats += keys %MEMSTATS_HAS if $C{showmem}; + + if ( $new_num_stats != $num_stats ) { + %prev_stats = (); + %last_loads = (); + + $num_stats = $new_num_stats; + $newsize{width} = $C{barwidth} * $num_stats; + $newsize{height} = $C{height}; + $resize_window = 1; } - $t1 = $t2; + if ($resize_window) { + set_dimensions $newsize{width}, $newsize{height}; + $app->resize( $C{width}, $C{height} ); + $resize_window = 0; + $redraw_background = 1; + } if ($redraw_background) { draw_background $app, $rects; $redraw_background = 0; } + auto_off_text $width; + } until $quit; say "Good bye"; - # $_->kill('STOP') for @threads; - $event_thread->join(); + exit 0; } - sub dispatch_table () { my $hosts = ''; my $textdesc = <<END; -Explanations: +CPU stuff: st = Steal in % [see man proc] (extended) Color: Red gt = Guest in % [see man proc] (extended) @@ -638,181 +799,353 @@ Explanations: avg = System load average; desc. order: 1, 5 and 15 min. avg. 1px horizontal line: Maximum sy+us+io of last 'avg' samples (extended) Extended means: text display only if extended mode is turned on +Memory stuff: + Ram: System ram usage in % + Color: Dark grey + Swp: System swap usage in % + Color: Grey Examples: - loadbars --extended 1 --showcores 1 --width 600 --hosts localhost + loadbars --extended 1 --showcores 1 --height 300 --hosts localhost loadbars --hosts localhost,server1.example.com,server2.example.com - loadbars --cluster foocluster (foocluster is in /etc/clusters of cssh) + loadbars --cluster foocluster (foocluster is in /etc/clusters [ClusterSSH]) END - # mode 1: Option is shown in the online help menu (stdout not sdl) - # mode 2: Option is shown in the 'usage' screen from the command line - # mode 4: Option is used to generate the GetOptions parameters for Getopt::Long - # Combinations: Like chmod(1) - - my %d = ( - average => { menupos => 3, help => 'Num of samples for avg. (more fluent animations)', mode => 6, type => 'i' }, - average_hot_up => { menupos => 4, cmd => 'a', help => 'Increases number of samples for calculating avg. by 1', mode => 1 }, - average_hot_dn => { menupos => 5, cmd => 'y', help => 'Decreases number of samples for calculating avg. by 1', mode => 1 }, - - cluster => { menupos => 6, help => 'Cluster name from /etc/clusters', var => \$C{cluster}, mode => 6, type => 's' }, - configuration => { menupos => 6, cmd => 'c', help => 'Show current configuration', mode => 4 }, - - extended => { menupos => 6, help => 'Toggle extended display (0 or 1)', mode => 7, type => 'i' }, - extended_hot => { menupos => 23, cmd => 'e', help => 'Toggle peak display', mode => 1 }, - - factor => { menupos => 7, help => 'Set graph scale factor (1.0 means 100%)', mode => 6, type => 's' }, - factor_hot_up => { menupos => 8, cmd => 's', help => 'Increases graph scale factor by 0.1', mode => 1 }, - factor_hot_dn => { menupos => 9, cmd => 'x', help => 'Decreases graph scale factor by 0.1', mode => 1 }, - - height => { menupos => 10, help => 'Set windows height', mode => 6, type => 'i' }, - - help_hot => { menupos => 11, cmd => 'h', help => 'Prints this help screen', mode => 1 }, - - hosts => { menupos => 12, help => 'Comma sep. list of hosts; optional: user@ in front to each host', var => \$hosts, mode => 6, type => 's' }, - - inter => { menupos => 13, help => 'Set update interval in seconds (default 0.1)', mode => 7, type => 's' }, - inter_hot_up => { menupos => 14, cmd => 'd', help => 'Increases update interval in seconds by 0.1', mode => 1 }, - inter_hot_dn => { menupos => 15, cmd => 'c', help => 'Decreases update interval in seconds by 0.1', mode => 1 }, + # mode 1: Option is shown in the online help menu (stdout not sdl) + # mode 2: Option is shown in the 'usage' screen from the command line + # mode 4: Option is used to generate the GetOptions parameters for Getopt::Long + # Combinations: Like chmod(1) + + my %d = ( + average => { + menupos => 3, + help => 'Num of samples for avg. (more fluent animations)', + mode => 6, + type => 'i' + }, + average_hot_up => { + menupos => 4, + cmd => 'a', + help => 'Increases number of samples for calculating avg. by 1', + mode => 1 + }, + average_hot_dn => { + menupos => 5, + cmd => 'y', + help => 'Decreases number of samples for calculating avg. by 1', + mode => 1 + }, + + barwidth => { + menupos => 5, + help => 'Set bar width', + mode => 6, + type => 'i' + }, + windowwidth_hot_up => { + menupos => 90, + help => 'Increase window width by 100px', + cmd => 'right', + mode => 1, + }, + windowwidth_hot_dn => { + menupos => 91, + help => 'Decrease window width by 100px', + cmd => 'left', + mode => 1, + }, + windowheight_hot_up => { + menupos => 92, + help => 'Increase window height by 100px', + cmd => 'down', + mode => 1, + }, + windowheight_hot_dn => { + menupos => 93, + help => 'Decrease window height by 100px', + cmd => 'up', + mode => 1, + }, + + cluster => { + menupos => 6, + help => 'Cluster name from /etc/clusters', + var => \$C{cluster}, + mode => 6, + type => 's' + }, + configuration => { + menupos => 6, + cmd => 'c', + help => 'Show current configuration', + mode => 4 + }, + + extended => { + menupos => 6, + help => 'Toggle extended display (0 or 1)', + mode => 7, + type => 'i' + }, + extended_hot => { + menupos => 23, + cmd => 'e', + help => 'Toggle extended mode', + mode => 1 + }, + + factor => { + menupos => 7, + help => 'Set graph scale factor (1.0 means 100%)', + mode => 6, + type => 's' + }, + factor_hot_up => { + menupos => 8, + cmd => 's', + help => 'Increases graph scale factor by 0.1', + mode => 1 + }, + factor_hot_dn => { + menupos => 9, + cmd => 'x', + help => 'Decreases graph scale factor by 0.1', + mode => 1 + }, + + height => { + menupos => 10, + help => 'Set windows height', + mode => 6, + type => 'i' + }, + + help_hot => { + menupos => 11, + cmd => 'h', + help => 'Prints this help screen', + mode => 1 + }, + + hosts => { + menupos => 12, + help => + 'Comma sep. list of hosts; optional: user@ in front to each host', + var => \$hosts, + mode => 6, + type => 's' + }, + + maxwidth => { + menupos => 16, + help => 'Set max width', + mode => 6, + type => 'i' + }, + + quit_hot => { menupos => 16, cmd => 'q', help => 'Quits', mode => 1 }, + + samples => { + menupos => 17, + help => 'Set number of samples until ssh reconnects', + mode => 6, + type => 'i' + }, + + showcores => { + menupos => 17, + help => 'Toggle core display (0 or 1)', + mode => 7, + type => 'i' + }, + showcores_hot => + { menupos => 17, cmd => '1', help => 'Toggle show cores', mode => 1 }, + + showmem => { + menupos => 17, + help => 'Toggle mem display (0 or 1)', + mode => 7, + type => 'i' + }, + showmem_hot => + { menupos => 17, cmd => 'm', help => 'Toggle show mem', mode => 1 }, + + showtexthost => { + menupos => 18, + help => 'Toggle hostname/num text display (0 or 1)', + mode => 7, + type => 'i' + }, + showtexthost_hot => { + menupos => 18, + cmd => 'u', + help => 'Toggle hostname/num text display', + mode => 1 + }, + + showtext => { + menupos => 19, + help => 'Toggle text display (0 or 1)', + mode => 7, + type => 'i' + }, + showtext_hot => { + menupos => 19, + cmd => 't', + help => 'Toggle text display', + mode => 1 + }, + + sshopts => + { menupos => 20, help => 'Set SSH options', mode => 6, type => 's' }, + title => { + menupos => 21, + help => 'Set the window title', + var => \$C{title}, + mode => 6, + type => 's' + }, - quit_hot => { menupos => 16, cmd => 'q', help => 'Quits', mode => 1 }, - - samples => { menupos => 17, help => 'Set number of samples until ssh reconnects', mode => 6, type => 'i' }, - - showcores => { menupos => 17, help => 'Toggle core display (0 or 1)', mode => 7, type => 'i' }, - showcores_hot => { menupos => 17, cmd => '1', help => 'Toggle CPUs', mode => 1 }, - - showtexthost => { menupos => 18, help => 'Toggle hostname/num text display (0 or 1)', mode => 7, type => 'i' }, - showtexthost_hot => { menupos => 18, cmd => 'u', help => 'Toggle hostname/num text display', mode => 1 }, - - showtext => { menupos => 19, help => 'Toggle text display (0 or 1)', mode => 7, type => 'i' }, - showtext_hot => { menupos => 19, cmd => 't', help => 'Toggle text display', mode => 1 }, - - sshopts => { menupos => 20, help => 'Set SSH options', mode => 6, type => 's' }, - title => { menupos => 21, help => 'Set the window title', var => \$C{title}, mode => 6, type => 's' }, - - width => { menupos => 24, help => 'Set windows width', mode => 6, type => 'i' }, ); - my %d_by_short = map { - $d{$_}{cmd} => $d{$_} + my %d_by_short = map { + $d{$_}{cmd} => $d{$_} - } grep { - exists $d{$_}{cmd} + } grep { + exists $d{$_}{cmd} - } keys %d; + } keys %d; my $closure = sub ($;$) { - my ($arg, @rest) = @_; + my ( $arg, @rest ) = @_; - if ($arg eq 'command') { - my ($cmd, @args) = @rest; + if ( $arg eq 'command' ) { + my ( $cmd, @args ) = @rest; my $cb = $d{$cmd}; $cb = $d_by_short{$cmd} unless defined $cb; - unless (defined $cb) { - system $cmd; + unless ( defined $cb ) { + system $cmd; return 0; } - if (length $cmd == 1) { - for my $key (grep { exists $d{$_}{cmd} } keys %d) { + if ( length $cmd == 1 ) { + for my $key ( grep { exists $d{$_}{cmd} } keys %d ) { do { $cmd = $key; last } if $d{$key}{cmd} eq $cmd; } } - } elsif ($arg eq 'hotkeys') { - $textdesc . "Hotkeys:\n" . (join "\n", map { - "$_\t- $d_by_short{$_}{help}" + } + elsif ( $arg eq 'hotkeys' ) { + $textdesc . "Hotkeys:\n" . ( + join "\n", + map { + "$_\t- $d_by_short{$_}{help}" - } grep { - $d_by_short{$_}{mode} & 1 and exists $d_by_short{$_}{help}; + } grep { + $d_by_short{$_}{mode} & 1 and exists $d_by_short{$_}{help}; - } sort { $d_by_short{$a}{menupos} <=> $d_by_short{$b}{menupos} } sort keys %d_by_short); + } sort { $d_by_short{$a}{menupos} <=> $d_by_short{$b}{menupos} } + sort keys %d_by_short + ); - } elsif ($arg eq 'usage') { - $textdesc . (join "\n", map { - if ($_ eq 'help') { - "--$_\t\t- $d{$_}{help}" - } else { - "--$_ <ARG>\t- $d{$_}{help}" + } + elsif ( $arg eq 'usage' ) { + $textdesc . ( + join "\n", + map { + if ( $_ eq 'help' ) + { + "--$_\t\t- $d{$_}{help}"; + } + else { + "--$_ <ARG>\t- $d{$_}{help}"; } - } grep { - $d{$_}{mode} & 2 and exists $d{$_}{help} + } grep { + $d{$_}{mode} & 2 + and exists $d{$_}{help} - } sort { $d{$a}{menupos} <=> $d{$b}{menupos} } sort keys %d); + } sort { $d{$a}{menupos} <=> $d{$b}{menupos} } sort keys %d + ); - } elsif ($arg eq 'options') { - map { - "$_=".$d{$_}{type} => (defined $d{$_}{var} ? $d{$_}{var} : \$C{$_}); + } + elsif ( $arg eq 'options' ) { + map { + "$_=" + . $d{$_}{type} => + ( defined $d{$_}{var} ? $d{$_}{var} : \$C{$_} ); - } grep { - $d{$_}{mode} & 4 and exists $d{$_}{type}; + } grep { + $d{$_}{mode} & 4 and exists $d{$_}{type}; - } sort keys %d; - } + } sort keys %d; + } }; - $d{configuration}{cb} = sub { - say sort map { - "$_->[0] = $_->[1]" + $d{configuration}{cb} = sub { + say sort map { + "$_->[0] = $_->[1]" - } grep { - defined $_->[1] + } grep { + defined $_->[1] - } map { - [$_ => exists $d{$_}{var} ? ${$d{$_}{var}} : $C{$_}] + } map { + [ $_ => exists $d{$_}{var} ? ${ $d{$_}{var} } : $C{$_} ] - } keys %d + } keys %d; }; - return (\$hosts, $closure); + return ( \$hosts, $closure ); } # Recursuve function sub get_cluster_hosts ($;$); + sub get_cluster_hosts ($;$) { - my ($cluster, $recursion) = @_; + my ( $cluster, $recursion ) = @_; - unless (defined $recursion) { - $recursion = 1; + unless ( defined $recursion ) { + $recursion = 1; - } elsif ($recursion > CSSH_MAX_RECURSION) { - error "CSSH_MAX_RECURSION reached. Infinite circle loop in " . CSSH_CONFFILE . "?"; - } + } + elsif ( $recursion > CSSH_MAX_RECURSION ) { + error "CSSH_MAX_RECURSION reached. Infinite circle loop in " + . CSSH_CONFFILE . "?"; + } - open my $fh, CSSH_CONFFILE or error "$!: " . CSSH_CONFFILE; + open my $fh, CSSH_CONFFILE or error "$!: " . CSSH_CONFFILE; my $hosts; while (<$fh>) { if (/^$cluster\s*(.*)/) { $hosts = $1; last; - } + } } close $fh; - unless (defined $hosts) { - error "No such cluster in " . CSSH_CONFFILE . ": $cluster" - unless defined $recursion; + unless ( defined $hosts ) { + error "No such cluster in " . CSSH_CONFFILE . ": $cluster" + unless defined $recursion; - return ($cluster); - } + return ($cluster); + } - my @hosts; - push @hosts, get_cluster_hosts $_, ($recursion + 1) for (split /\s+/, $hosts); - return @hosts; + my @hosts; + push @hosts, get_cluster_hosts $_, ( $recursion + 1 ) + for ( split /\s+/, $hosts ); + return @hosts; } sub main () { - my ($hosts, $dispatch) = dispatch_table; + my ( $hosts, $dispatch ) = dispatch_table; my $usage; - GetOptions ('help|?' => \$usage, $dispatch->('options')); + GetOptions( 'help|?' => \$usage, $dispatch->('options') ); - if (defined $usage) { + if ( defined $usage ) { say $dispatch->('usage'); exit 1; } @@ -820,15 +1153,16 @@ sub main () { set_showcores_regexp; my @hosts = map { - my ($a, $b) = split /\@/, $_; + my ( $a, $b ) = split /\@/, $_; defined $b ? "$b:$a" : $a; } split ',', $$hosts; - if (@hosts || defined $C{cluster}) { - push @hosts, get_cluster_hosts $C{cluster} if defined $C{cluster}; + if ( @hosts || defined $C{cluster} ) { + push @hosts, get_cluster_hosts $C{cluster} if defined $C{cluster}; system 'ssh-add'; - } else { + } + else { say $dispatch->('usage'); exit 1; } |
