#!/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});