File: //scripts.20110531.215904.25158/smartcheck
#!/usr/bin/perl
# cpanel - smartcheck Copyright(c) 2010 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
BEGIN { unshift @INC, '/usr/local/cpanel'; }
use strict;
use warnings;
use Cpanel::iContact ();
use Cpanel::DataStore ();
use Cpanel::CPAN::Getopt::Param ();
use Cpanel::StringFunc::Trim ();
use Cpanel::SafeRun::Dynamic ();
my %smart = (
'url' => 'http://smartmontools.sourceforge.net/',
'version_cmd' => '-V',
'version_rgx' => 'smartctl version ',
'2.1' => {
'smart_enabled_cmd' => '-i',
'smart_enabled_rgx' => 'Drive supports S.M.A.R.T. and is enabled',
'errors_only' => '-l',
'ok_drive_rgx' => [qw(/sd /hd)],
},
'5.x' => {
'smart_enabled_cmd' => '-i',
'smart_enabled_rgx' => 'SMART support is: Enabled',
'errors_only' => '-q errorsonly -H -l selftest -l error',
'ok_drive_rgx' => [qw(/sd /hd)],
},
);
my $cust_d_file = '/var/cpanel/smartcheck_custom_dash_d.yaml';
my $custom_d = Cpanel::DataStore::fetch_ref($cust_d_file);
my $param = Cpanel::CPAN::Getopt::Param->new(
{
'help_coderef' => sub {
print <<"SMARTCHECK_HELP";
$0 - check the status of your harddrive(s) with smartctl.
--help this screen
--quiet bare minimum output
--noemail output to screen only, do not send email
If you have a harddrive that keeps getting this output:
"Checking /dev/sda....S.M.A.R.T does not appear to be enabled for this device."
but you are certain it has SMART support enabled then smartctl was unable to guess your drive's type.
You can specify a drive's type via smartctl's -d flag.
You can tell $0 to use a specific -d flag for a given drive via a simple YAML file:
$cust_d_file
It should be a simple key/value hash where the key is the drive and the value is the value of that drive's -d
For example to tell smartctl that /dev/sda is an ata we create this file:
# cat $cust_d_file
---
/dev/sda: ata
#
Then the next time its run we'll see this output instead:
Checking /dev/sda....
Adding custom '-d ata' flag for /dev/sda from $cust_d_file
Ok
While YAML files are plain text, its best to use a YAML aware tool to edit them.
2 simple command line commands to do this are:
To write the hash to the file:
perl -MYAML::Syck=DumpFile -e 'DumpFile("$cust_d_file", {"/dev/sda"=>"ata"});'
To dump the current has to the screen:
perl -MYAML::Syck=LoadFile -MData::Dumper -e 'print Dumper(LoadFile("$cust_d_file"));'
SMARTCHECK_HELP
exit;
},
}
);
eval { require Digest::MD5::File; } or die 'Skipping smartcheck: Digest::MD5::File install still pending';
my %drive_lookup;
my $msg = '';
my $didhowdy = 0;
my $quiet = $param->get_param('quiet') ? 1 : 0;
my $nomail = $param->get_param('nomail') ? 1 : 0;
my $debug = 0;
my $bin = '/usr/local/cpanel/3rdparty/bin/smartctl';
my $last_sent = '/var/cpanel/last_smartcheck_msg_alert';
if ( !-l $bin ) {
if ( -e $bin ) {
unlink $bin or die "Could not remove old cPanel smartctl: $!";
}
for my $smartctl (qw(/usr/sbin/smartctl /usr/local/sbin/smartctl)) {
if ( -e $smartctl ) {
system 'ln', '-s', $smartctl, $bin;
last;
}
}
}
my $link = readlink($bin) || 'smartctl';
exit if !-e $bin; # or -l or -x instead ???
exit if -e '/var/cpanel/disablesmartcheck';
my $vrs = '';
Cpanel::SafeRun::Dynamic::livesaferun(
'prog' => [ $bin, split( /\s+/, $smart{'version_cmd'} ) ],
'formatter' => sub {
my ( $line, $quit_saferun_loop_sr ) = @_;
if ( $line =~ m/\Q$smart{'version_rgx'}\E(\d+(?:\.\d+))+/ ) {
$vrs = $1;
${$quit_saferun_loop_sr} = 1;
}
return '';
},
);
$smart{'BINVER'} = $vrs || '';
# default to the oldest "new" config if not parseable or available
$vrs = '5.x' if !defined $vrs || !$vrs || !exists $smart{$vrs};
# unsupported SCSI was here
my @mounts;
Cpanel::SafeRun::Dynamic::livesaferun(
'prog' => ['mount'],
'formatter' => sub {
my ( $line, $quit_saferun_loop_sr ) = @_;
push @mounts, $line;
return '';
},
);
open my $fstab, '/etc/fstab' or die "Could not open /etc/fstab: $!";
for my $mount_lines ( @mounts, <$fstab> ) {
next if $mount_lines =~ m{ (?:cdrom | floppy | noauto) }xms;
my ($drive) = $mount_lines =~ /^(\/\S+)/;
if ($drive) {
$drive =~ s{\d+$}{}g;
$drive_lookup{$drive} = 1;
}
}
close $fstab;
for my $dsk ( sort keys %drive_lookup ) {
next if !grep { $dsk =~ m/\Q$_\E/ } @{ $smart{$vrs}->{'ok_drive_rgx'} };
if ( !$didhowdy ) {
print "Using smartcheck config $vrs for smartctl($smart{'BINVER'})\n"
if !$quiet;
$didhowdy++;
}
print "Checking $dsk...." unless $quiet;
if ( exists $custom_d->{$dsk} && $custom_d->{$dsk} =~ m{^\S+$} ) {
print "\n\tAdding custom '-d $custom_d->{$dsk}' flag for $dsk from $cust_d_file\n";
$smart{$vrs}->{'smart_enabled_cmd'} = "-d $custom_d->{$dsk} $smart{$vrs}->{'smart_enabled_cmd'}";
}
my $disk_enabled = '';
Cpanel::SafeRun::Dynamic::livesaferun(
'prog' => [ $bin, split( /\s+/, $smart{$vrs}->{'smart_enabled_cmd'} ), $dsk ],
'formatter' => sub {
my ( $line, $quit_saferun_loop_sr ) = @_;
$disk_enabled .= $line;
return '';
},
);
if ( $disk_enabled =~ m/\Q$smart{$vrs}->{'smart_enabled_rgx'}\E/i ) {
my $error = '';
Cpanel::SafeRun::Dynamic::livesaferun(
'prog' => [ $bin, split( /\s+/, $smart{$vrs}->{'errors_only'} ), $dsk ],
'formatter' => sub {
my ( $line, $quit_saferun_loop_sr ) = @_;
$error .= $line;
return '';
},
);
$error = Cpanel::StringFunc::Trim::ws_trim($error);
if ($error) {
$msg .= <<"MSG_END";
S.M.A.R.T Errors on $dsk
From Command: $link $smart{$vrs}->{'errors_only'} $dsk
$error
----END $dsk--
MSG_END
print "\nErrors:\n $error\n\n" if !$quiet;
}
else {
print "Ok\n" if !$quiet;
}
}
else {
print "S.M.A.R.T does not appear to be enabled for this device.\n"
if !$quiet;
}
}
if ( $msg && -e $last_sent ) {
$msg = '' if Digest::MD5::File::file_md5_hex($last_sent) eq Digest::MD5::md5_hex($msg);
}
if ( $msg ne '' ) {
if ( open my $last_fh, '>', $last_sent ) {
print {$last_fh} $msg;
close $last_fh;
}
else {
warn "Could not open $last_sent for writing: $!";
}
my $subject = '[cPanel smartcheck] Possible Hard Drive Failure Soon';
my $smsg = <<"SMART_END";
IMPORTANT: Do not ignore this email! !!!! READ IT THOUROUGHLY !!
Your system's smartctl utility has detected some errors.
(see the "---- smartctl report --" section below for details).
You should investigate those errors according to `man smartctl`
and documentation at $smart{'url'}
including their mailing list. You can disable this check by doing:
`touch /var/cpanel/disablesmartcheck`
and reenable it at anytime by removing that file.
If you do find issues you should consider using smartd to
monitor your drives instead of/along with this script.
This email was generated by the cPanel smartcheck script and is
reporting errors from your S.M.A.R.T enabled drives with the
given commands below. It is up to you to investigate further
and take appropriate steps:
!!!! Do not submit tickets or bug reports if you get this email.
Use the avenues outlined in this email to deal with your
system's S.M.A.R.T setup. !!
To begin your troubleshooting you may want to run
`/scripts/smartcheck --nomail` as root via SSH.
---- smartctl report --
$msg
SMART_END
if ( !$nomail ) {
Cpanel::iContact::icontact(
'application' => 'smartcheck',
'level' => 3,
'subject' => $subject,
'message' => $msg,
'msgtype' => '',
);
}
if ($debug) {
print "This was emailed unless you used --nomail:\n" . "Subject: $subject\n\n$smsg";
}
}