#!/usr/bin/perl -w
#
# check_smart_attributes - nagios plugin
#
#
# Copyright (C) 2006 Francesc Guasch
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Report bugs to: frankie@etsetb.upc.edu
#
use strict;
use Getopt::Long;
# 0.9 - frankie
# - mostly rewritten
# - removed default attribs, dead wrong threshold checking
#
# 0.05 - frankie
# - quiet mode
# - cleaned some code
# - ata support
#
# 0.04 - frankie
# - defaults to /dev/hda
# - sudo errors checked
# - IDE units autodetect
#
# 0.03 - frankie
# - now it works without config file
# - won't return
after ok if empty
# - default config at /etc/nagios/smart_attr.conf
# - debugging
#
# 0.02 - jrovira
# - misc improvements
#
# 0.01 - frankie
# - initial release
my $VERSION = "0.9";
my $SMARTCTL = "/usr/sbin/smartctl";
my $MOUNT = "/bin/mount";
$SMARTCTL = "/usr/local/sbin/smartctl"
unless -e $SMARTCTL;
use lib '/usr/local/nagios/plugins';
use utils qw(%ERRORS &print_revision &support &usage);
my $LASTLOG_FILE = "/tmp/last_smart_attr.log";
my @DRIVE=();
my $DEBUG=0;
my $VERBOSE = 0;
my $ATA;
my $TEXT;
my ($PROGNAME) = $0 =~ m#.*/(.*)#;
sub print_usage() {
print "Usage: $PROGNAME [--edebug] [--version] [--help] [--verbose] [--ata]".
" [--text]".
" [--drive=/dev/hda [--drive=/dev/hdc [...]]] \n";
}
{
my ($version,$help);
GetOptions(
ata => \$ATA,
text => \$TEXT,
edebug => \$DEBUG,
'drive=s' => \@DRIVE,
version => \$version,
verbose => \$VERBOSE,
help => \$help
);
if ($help) {
print_revision($PROGNAME,"\$Revision: $VERSION \$");
print "Copyright (c) 2005 Francesc Guasch - Ortiz
Check smart attributes plugin for Nagios
";
print_usage();
exit($ERRORS{OK});
}
if ($version) {
print_revision($PROGNAME,"\$Revision: $VERSION \$");
exit($ERRORS{OK});
}
my @DRIVE_FIXED = ();
foreach my $drive (@DRIVE) {
push @DRIVE_FIXED, split(",",$drive);
}
@DRIVE = @DRIVE_FIXED;
my %drive = map { $_ => 1} @DRIVE;
@DRIVE = keys %drive;
}
my ($RET,$INFO) = ( 'OK','');
sub add_info {
my ($strref,$alarm,$name,$value,$extra) = @_;
$value =~ s/^0+//;
$$strref .= " , " if $$strref;
if ($extra) {
$extra = " ($extra)";
} else {
$extra = '';
}
$$strref .= "" if ($alarm && !$TEXT);
$$strref .= "$name=$value$extra";
$$strref .= "" if ($alarm && !$TEXT);
}
sub detect_mounted_ide_drives {
my %drives;
open CMD, $MOUNT."|"
or return ();
while() {
chomp;
if(m#^(/dev/hd\w)\d*\s+#) {
$drives{$1} = 1;
}
}
close CMD;
return keys(%drives);
}
sub run_smartctl {
my $drive = shift or die "Missing drive";
my $strret;
my $found_start_tag = 0;
my $ata = '';
$ata = " -d ata" if $ATA;
my $cmd = "$SMARTCTL$ata -A $drive";
warn "\n$cmd\n" if $DEBUG;
my @data;
open CMD ,"sudo $cmd 2>&1|" or die $!;
open DALOG, ">$LASTLOG_FILE" or die "$! $LASTLOG_FILE";
while () {
print DALOG;
if(/command not found/) {
close CMD;
chomp;
print "Sudo command error!
$_";
exit $ERRORS{'CRITICAL'};
}
if(/^ID#\s*ATTRIBUTE_NAME\s*FLAG/) {
$found_start_tag = 1;
last;
}
if(/\[this device: CD\/DVD\]/) {
close CMD;
print "Device $drive is a CD/DVD drive!\n";
exit $ERRORS{'UNKNOWN'};
}
if(/^Smartctl: Device Read Identity Failed \(not an ATA\/ATAPI device\)/) {
close CMD;
print "Device $drive does not exist!\n";
exit $ERRORS{'UNKNOWN'};
}
}
unless($found_start_tag) {
close CMD;
warn "Smart output parse error, no param start tag found! (Check executed command)\n$cmd\n";
exit $ERRORS{'CRITICAL'};
}
while () {
print DALOG;
@data = split;
my ($name,$value,$thresh,$type,$when_failed)= @data[1,3,5,6,8];
next unless $when_failed;
if ($when_failed ne '-' || $value <= $thresh ) {
if ($type =~ /pre-fail/) {
$RET = 'CRITICAL';
} else {
$RET = 'WARNING' unless $RET eq 'CRITICAL';
}
my $text = $when_failed;
$text = "$value <= $thresh" if $when_failed eq '-';
add_info(\$strret,1,$name,$value,$when_failed);
next;
} else {
add_info(\$strret,0,$name,"$value>$thresh")
if $VERBOSE;
}
}
close CMD;
return $strret;
}
if(scalar(@DRIVE) == 0) {
@DRIVE = detect_mounted_ide_drives();
print "drives: ".join(",",@DRIVE)."\n";
# @DRIVE = ("/dev/hda");
}
foreach my $drive (@DRIVE) {
my $strret;
print "Checking $drive...\n" if($DEBUG);
$strret = run_smartctl($drive);
$INFO .= "
" if ($INFO && $strret && !$TEXT);
$INFO .= "$drive: $strret" if ($strret);
}
if ($INFO) {
if ($TEXT) {
$INFO =" $INFO";
} else {
$INFO = "
$INFO";
}
}
print "$RET$INFO";
exit($ERRORS{$RET});