You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

94 lines
3.4 KiB

#!/usr/bin/perl
use warnings;
use strict;
use Term::ANSIColor;
use Getopt::Long;
use Time::localtime;
my %temp = ('warn' => 38, 'bad' => 42);
my %color = ('good' => 'green', 'warn' => 'yellow', 'bad' => 'red');
my $devdir='/dev';
my $smartctl='/usr/sbin/smartctl';
my @udisks = ();
my @disks = ();
my %rotobois=();
my $CLEAR_LINE=`tput cub 40;tput el`;
# https://stackoverflow.com/a/5047362
sub clean {my $text = shift; $text=~s/\n//g; $text=~s/\r//g;return $text;}
sub ptime {my $min = localtime->min < 10 ? "0".localtime->min : localtime->min;
my $hr = localtime->hour < 10 ? "0".localtime->hour : localtime->hour;
return "$hr:$min";}
# https://www.perl.com/article/37/2013/8/18/Catch-and-Handle-Signals-in-Perl/
$SIG{INT} = sub {printf("%s",$CLEAR_LINE);printf("\n%s\n\n",clean(colored("Caught ctrl+c - exiting",'red')));exit 0;};
opendir my($DH), $devdir or die $!;
my @devicelist=readdir $DH;
closedir $DH;
for(@devicelist) {
my $device =$_;
# Directory listing includes . and .. but these aren't disks!
if ($device eq "." or $device eq "..") {next;}
# We don't' care about partitions
if ($device =~ /sd[a-z][0-9]/) {next;}
if ($device =~ /sd[a-z]/) {
push(@udisks,$device);
}
}
@disks=sort(@udisks);
GetOptions("interval|i=i" => \( my $INTERVAL=300 ),"header|h=i" => \( my $HEADER_REPEAT = 24 ),) or die "command line arguments error";
#my $INTERVAL=300;
#my $HEADER_REPEAT=24;
printf("\n%s\n","Running script forever, press ctrl+c to exit.\nScript args:");
printf("%s\n%s\n\n","- Interval: $INTERVAL seconds","- Re-Header: $HEADER_REPEAT rows");
sub diskheader {
my $rotoinv=keys %rotobois; if ($rotoinv > 0) {
printf("%-10s", "24hr"); for (@disks) {printf("%-5s",$rotobois{"/dev/$_"});} printf("\n");}
printf("%-10s", "Time"); for (@disks) {printf("%-5s",$_);} printf("\n");
}
sub headerlines {printf("%-10s", "---------+"); for (@disks) {printf("%-5s","----+");} printf("\n");}
my $preheaded=0;
printf("\n"); # placeholder ;)
diskheader();
headerlines();
my $headertracker=0;
while (1) {
printf("%s",$CLEAR_LINE);
if ($headertracker >= $HEADER_REPEAT) {$headertracker=0;headerlines();diskheader();headerlines();}
printf("%5s%5s",ptime(),"");
for (@disks) {
my $diskname="/dev/$_";
open my $cmd, '-|', "$smartctl -x $diskname";
while (my $line = <$cmd>) {
if ($line =~ /0x05\s+0x008\s+\d+\s+(\d+)/) {
my $disktemp=int($1);
if ($disktemp > $temp{"bad"}) {printf(" %-5s ",clean(colored($disktemp, $color{"bad"})));}
elsif($disktemp > $temp{"warn"}) {printf(" %-5s ",clean(colored($disktemp, $color{"warn"})));}
else {printf(" %-5s ",clean(colored($disktemp, $color{"good"})));}
}
elsif ($line =~ /Rotation Rate:\s+(Solid State Device|\d+\s*rpm)/) {
if ($line =~ /.*:\s+(\d+)\s+rpm/) {$rotobois{"$diskname"}="$1";}
else {$rotobois{"$diskname"}="SSD";}
}
}
close $cmd;
}
# We can't get the basic stats until at least one run-through of the smart output
# so this prepends the types of disks to the table header
if (not $preheaded) {
printf("%s",`tput cuu1; tput cuu1; tput cuu1; tput cub 80`);
diskheader();
printf("%s\n",`tput cub 80;`);
$preheaded=1;
}
printf("\n");
printf("%s","Sleeping for $INTERVAL seconds...");
$headertracker=$headertracker+1;
select()->flush(); # Heccin buffered I/O gets caulk blocked by the sleep. This forces a flush to STDIO
sleep($INTERVAL);
}