#!/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 <br>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 .= "<font color=\"red\">" if ($alarm && !$TEXT);
    $$strref .= "$name=$value$extra";
	$$strref .= "</font>" if ($alarm && !$TEXT);
}

sub detect_mounted_ide_drives {
	my %drives;

	open CMD, $MOUNT."|"
		or return ();
	while(<CMD>) {
		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 (<CMD>) {
		print DALOG;
		if(/command not found/) {
			close CMD;
			chomp;
			print "Sudo command error!<br>$_";
			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 (<CMD>) {
		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 .= "<br>" if ($INFO && $strret && !$TEXT);
	$INFO .= "$drive: $strret" if ($strret);
}

if ($INFO) {
    if ($TEXT) {
        $INFO =" $INFO";
    } else {
        $INFO = "<br>$INFO";
    }
}
print "$RET|$INFO";
exit($ERRORS{$RET});
