check_smart.pl 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #!/usr/bin/perl -w
  2. # chec_smart
  3. # Check S.M.A.R.T. enabled disks status.
  4. #
  5. # This uses smartmontools to check for disk status.
  6. # This is NOT compatible with smartsuite
  7. # Please use smartctl --smart=on --offlineauto=on --saveauto=on /dev/something
  8. # or similar to enable automatic data collection, and RTFM about it.
  9. #
  10. # this uses sudo to access the smartctl program, so please add a line in sudoers
  11. # nagios computername = NOPASSWD:/usr/sbin/smartctl
  12. #
  13. # CopyLeft Roy Sigurd Karlsbakk <roy@karlsbakk.net>
  14. # Developed under Debian/SID
  15. # No warranties what so ever. If this toasts your PC, or your wife
  16. # runs away with your girlfriend, or even me, don't blame me.
  17. #
  18. # Licenced under GPL
  19. #
  20. use strict;
  21. use Getopt::Long;
  22. my (
  23. $s, $i, $out, $retcode, $errtxt, $exitcode,
  24. $device, $text_mode, $exitcode_mode, $help, $verbose, $type,
  25. );
  26. my $smartctl = "sudo /usr/sbin/smartctl";
  27. my $e_commandline = 0;
  28. my $e_devopen = 0;
  29. my $e_chksum = 0;
  30. my $e_disk_failing = 0;
  31. my $e_prefail = 0;
  32. my $e_mayprefail = 0;
  33. my $e_errlog = 0;
  34. my $e_selftestlog = 0;
  35. sub end {
  36. $s = shift;
  37. $i = shift;
  38. if ($i == 0) {
  39. $s = "OK: $s";
  40. } elsif ($i == 1) {
  41. $s = "WARNNG: $s";
  42. } elsif ($i == 2) {
  43. $s = "CRITICAL: $s";
  44. } elsif ($i == 3) {
  45. $s = "UNKNOWN: $s";
  46. } else {
  47. $s = "OUT OF RANGE: $s";
  48. }
  49. print "$s\n";
  50. exit($i);
  51. }
  52. sub syntax {
  53. $s = shift or $s = 'Unknown';
  54. printf STDERR ("Error: $s\n") unless ($help);
  55. printf STDERR ("Syntax: %s (-t|-e) -d <device> [-vh]\n", $0);
  56. printf STDERR (" --text-mode -t check by parsing smartctl's output\n");
  57. printf STDERR (" --exitcode-mode -e check smartctl's exitcode (only works on IDE)\n");
  58. printf STDERR (" --device -d disk device to check\n");
  59. printf STDERR (" --type -T drive type. See the -d flag in the smartctl manual\n");
  60. printf STDERR (" --verbose -v verbose\n");
  61. printf STDERR (" --help -h this help\n");
  62. exit(0) if $help;
  63. exit(3);
  64. }
  65. Getopt::Long::Configure('bundling');
  66. GetOptions(
  67. "d=s" => \$device, "device=s" => \$device,
  68. "T=s" => \$type, "type=s" => \$type,
  69. "t" => \$text_mode, "text-mode" => \$text_mode,
  70. "e" => \$exitcode_mode, "exitcode-mode" => \$exitcode_mode,
  71. "h" => \$help, "help" => \$help,
  72. "v" => \$verbose, "verbose" => \$verbose
  73. ) || syntax("RTFM!");
  74. syntax if ($help);
  75. syntax("Need device to check") unless ($device);
  76. syntax("Conflicting modes") if ($text_mode && $exitcode_mode);
  77. syntax("Need test mode") unless ($text_mode || $exitcode_mode);
  78. syntax("Exitcode mode only works on ATA drives") if ($exitcode_mode && ! ($device =~ /\/dev\/hd./));
  79. if ($type) {
  80. $type =~ s/[\r\n]*?//g;
  81. print "type: '$type'\n" if ($verbose);
  82. syntax("Valid --type entries include ata, scsi and 3ware,n")
  83. unless (($type =~ /^ata$/) || ($type =~ /^scsi$/) || ($type =~ /^3ware,\d+$/));
  84. }
  85. if (defined($type)) {
  86. $type = "--device=$type";
  87. } else {
  88. $type = "";
  89. }
  90. if ($text_mode) {
  91. print "running $smartctl $type -H $device" if ($verbose);
  92. unless (open SMARTCTL,"$smartctl $type -H $device|") {
  93. print STDERR "Can't execute $smartctl: $!\n";
  94. exit(3);
  95. }
  96. while (<SMARTCTL>) {
  97. last if (/=== START OF READ SMART DATA SECTION ===/);
  98. }
  99. $out = <SMARTCTL>;
  100. print $out;
  101. exit(0) if ($out =~ /PASSED/);
  102. exit(2) if ($out =~ /SAVE ALL DATA/ || $out =~ /FAILED/);
  103. exit(3);
  104. } elsif ($exitcode_mode) {
  105. print "Running $smartctl $type -q silent $device\n" if ($verbose);
  106. system("$smartctl $type -q silent $device");
  107. $retcode = $?;
  108. $e_commandline = 1 if ($retcode & 0x0100);
  109. $e_devopen = 1 if ($retcode & 0x0200);
  110. $e_chksum = 1 if ($retcode & 0x0400);
  111. $e_disk_failing = 1 if ($retcode & 0x0800);
  112. $e_prefail = 1 if ($retcode & 0x1000);
  113. $e_mayprefail = 1 if ($retcode & 0x2000);
  114. $e_errlog = 1 if ($retcode & 0x4000);
  115. $e_selftestlog = 1 if ($retcode & 0x8000);
  116. print "$e_commandline $e_devopen $e_chksum $e_disk_failing $e_prefail $e_mayprefail $e_errlog $e_selftestlog\n"
  117. if ($verbose);
  118. $exitcode = 0;
  119. $errtxt = "";
  120. if ($exitcode) {
  121. if ($e_commandline) {
  122. $errtxt .= "Commandline didn't parse, ";
  123. $exitcode = 3 if ($exitcode == 0);
  124. }
  125. if ($e_devopen) {
  126. $errtxt .= "Device could not be opened, ";
  127. $exitcode = 3 if ($exitcode == 0);
  128. }
  129. if ($e_chksum) {
  130. $errtxt .= "Checksum failure somewhere, ";
  131. $exitcode = 1 if ($exitcode != 2);
  132. }
  133. if ($e_disk_failing) {
  134. $errtxt .= "Disk is failing!, ";
  135. $exitcode = 2;
  136. }
  137. if ($e_prefail) {
  138. $errtxt .= "Disk is in prefail, ";
  139. $exitcode = 1 if ($exitcode != 2);
  140. }
  141. if ($e_mayprefail) {
  142. $errtxt .= "Disk is close to prefail. Please check manually, ";
  143. $exitcode = 1 if ($exitcode != 2);
  144. }
  145. if ($e_errlog) {
  146. $errtxt .= "The device error log contains records of errors, ";
  147. $exitcode = 1 if ($exitcode != 2);
  148. }
  149. if ($e_selftestlog) {
  150. $errtxt .= "The device self-test log contains records of errors, ";
  151. $exitcode = 1 if ($exitcode != 2);
  152. }
  153. if ($exitcode == 1) {
  154. $errtxt = "WARNNG: $errtxt";
  155. } elsif ($exitcode == 2) {
  156. $errtxt = "CRITICAL: $errtxt";
  157. } else {
  158. $errtxt = "UNKNOWN: $errtxt";
  159. }
  160. } else {
  161. $errtxt = "OK";
  162. }
  163. print "$errtxt\n";
  164. exit($exitcode);
  165. } else {
  166. print STDERR "Something's strange is going on :~|\n";
  167. exit(3);
  168. }
  169. # vim:ts=4:sw=4:cindent