root / plugins / sensors / hddtemp_smartctl @ 9791e321
Historique | Voir | Annoter | Télécharger (8,4 ko)
| 1 | 6dbfc425 | Nikolay Beresnev | #!/usr/local/bin/perl -w |
|---|---|---|---|
| 2 | # -*- perl -*- |
||
| 3 | |||
| 4 | =head1 NAME |
||
| 5 | |||
| 6 | hddtemp_smartctl - Plugin to monitor harddrive temperatures through |
||
| 7 | SMART |
||
| 8 | |||
| 9 | =head1 CONFIGURATION |
||
| 10 | |||
| 11 | This plugin needs to run as root or some other user that has access to |
||
| 12 | the harddrive devices. |
||
| 13 | |||
| 14 | The following environment variables are used |
||
| 15 | |||
| 16 | smartctl - path to smartctl executable |
||
| 17 | drives - List drives to monitor. E.g. "env.drives hda hdc". |
||
| 18 | type_$dev - device type for one drive, e.g. "env.type_sda 3ware,0" |
||
| 19 | or more typically "env.type_sda ata" if sda is a SATA disk. |
||
| 20 | args_$dev - additional arguments to smartctl for one drive, |
||
| 21 | e.g. "env.args_hda -v 194,10xCelsius". Use this to make |
||
| 22 | the plugin use the --all or -a option if your disk will |
||
| 23 | not return its temperature when only the -A option is |
||
| 24 | used. |
||
| 25 | dev_$dev - monitoring device for one drive, e.g. twe0 |
||
| 26 | |||
| 27 | If the "smartctl" enviroment variable is not set the plugin will |
||
| 28 | search your $PATH, /usr/bin, /usr/sbin, /usr/local/bin and |
||
| 29 | /usr/local/sbin for a file called "smartctl", and use that. |
||
| 30 | |||
| 31 | If the "drives" environment variable is not set, the plugin will |
||
| 32 | attempt to search for drives to probe. |
||
| 33 | |||
| 34 | =head1 MAGIC MARKERS |
||
| 35 | |||
| 36 | #%# family=auto |
||
| 37 | #%# capabilities=autoconf |
||
| 38 | |||
| 39 | =head1 AUTHOR |
||
| 40 | |||
| 41 | Copyright (c) 2005, Lutz Peter Christoph |
||
| 42 | All rights reserved. |
||
| 43 | |||
| 44 | =head1 LICENSE |
||
| 45 | |||
| 46 | Redistribution and use in source and binary forms, with or without |
||
| 47 | modification, are permitted provided that the following conditions |
||
| 48 | are met: |
||
| 49 | |||
| 50 | * Redistributions of source code must retain the above copyright |
||
| 51 | notice, this list of conditions and the following disclaimer. |
||
| 52 | |||
| 53 | * Redistributions in binary form must reproduce the above copyright |
||
| 54 | notice, this list of conditions and the following disclaimer in |
||
| 55 | the documentation and/or other materials provided with the |
||
| 56 | distribution. |
||
| 57 | |||
| 58 | * The name and aliases of Lutz Peter Christoph ("Lupe Christoph",
|
||
| 59 | "Lutz Christoph") may not be used to endorse or promote products |
||
| 60 | derived from this software without specific prior written |
||
| 61 | permission. |
||
| 62 | |||
| 63 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
| 64 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
| 65 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
| 66 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
| 67 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
| 68 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
| 69 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
| 70 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
| 71 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
| 72 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
| 73 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
| 74 | |||
| 75 | =head1 NOTES |
||
| 76 | |||
| 77 | Note for users of RAID controllers (smartmontools currently only |
||
| 78 | supports 3ware): you can specify the drives attached to your RAID |
||
| 79 | controller(s) as raiddev_num (e.g. sda_0). Then you must specify the |
||
| 80 | type like this: type_sda_0 3ware,0. |
||
| 81 | |||
| 82 | Recent versions of the kernel driver use a separate major device |
||
| 83 | number for monitoring purposes, like /dev/twe<n> or /dev/twa<n>. This |
||
| 84 | can be put in the e.g. dev_sda environment variable, to allow the user |
||
| 85 | to keep sda as the name of the disk. |
||
| 86 | |||
| 87 | To avoid spinning up sleeping disks smartctl will use the --nocheck |
||
| 88 | parameter. If this parameter isn't supported by your version of |
||
| 89 | smartctl then hdparm will be used. Note that hdparm isn't available |
||
| 90 | on all platforms. |
||
| 91 | |||
| 92 | =cut |
||
| 93 | |||
| 94 | use strict; |
||
| 95 | |||
| 96 | my $DEBUG = $ENV{'MUNIN_DEBUG'} || 0;
|
||
| 97 | |||
| 98 | my $smartctl = exists $ENV{smartctl} ? $ENV{smartctl} : '';
|
||
| 99 | |||
| 100 | # If the envvar is not set, look for smartctl |
||
| 101 | if (!$smartctl) {
|
||
| 102 | # Still not found? Check obvious places |
||
| 103 | my @dirs = split(':',$ENV{PATH});
|
||
| 104 | push (@dirs, qw(/usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) ); |
||
| 105 | |||
| 106 | until ($smartctl or @dirs == 0) {
|
||
| 107 | my $dir = shift @dirs; |
||
| 108 | my $path = $dir.'/smartctl'; |
||
| 109 | $smartctl = $path if -x $path; |
||
| 110 | } |
||
| 111 | } elsif (! -x $smartctl) {
|
||
| 112 | # If it is set, verify it |
||
| 113 | warn "Predefined smartctl ($smartctl) is not a executable\n"; |
||
| 114 | undef $smartctl; |
||
| 115 | } |
||
| 116 | |||
| 117 | # Check version of smartctl to determine --nocheck capabilities |
||
| 118 | my $use_nocheck = 0; |
||
| 119 | if ($smartctl and `$smartctl --version` =~ / version (\d+\.\d+) /i) {
|
||
| 120 | $use_nocheck = $1 >= 5.37; |
||
| 121 | warn "[DEBUG] Smartctl supports --nocheck\n" if $DEBUG; |
||
| 122 | } |
||
| 123 | |||
| 124 | # hdparm is used as a fallback |
||
| 125 | my $hdparm = `which hdparm 2>/dev/null`; |
||
| 126 | chomp $hdparm; |
||
| 127 | |||
| 128 | my @drives; |
||
| 129 | |||
| 130 | # Try to get a default set of drives |
||
| 131 | if ($^O eq 'linux') {
|
||
| 132 | # On Linux, we know how to enumerate ide drives. SCSI is not as easy |
||
| 133 | if (-d '/proc/ide') {
|
||
| 134 | opendir(IDE, '/proc/ide'); |
||
| 135 | @drives = grep /hd[a-z]/, readdir IDE; |
||
| 136 | closedir(IDE); |
||
| 137 | } |
||
| 138 | # "SCSI disks" could be both SCSI or SATA - we can't know which |
||
| 139 | # without probing them. |
||
| 140 | } elsif ($^O eq 'freebsd') {
|
||
| 141 | opendir(DEV, '/dev'); |
||
| 142 | 006ef061 | Manuel Schneider | @drives = grep /^(a?da|ad)[0-9]+$/, readdir DEV; |
| 143 | 6dbfc425 | Nikolay Beresnev | closedir(DEV); |
| 144 | } elsif ($^O eq 'solaris') {
|
||
| 145 | @drives = map { s@.*/@@ ; $_ } glob '/dev/rdsk/c*t*d*s2';
|
||
| 146 | } |
||
| 147 | |||
| 148 | @drives = split ' ', $ENV{drives} if exists $ENV{drives};
|
||
| 149 | |||
| 150 | # Sort list of drives |
||
| 151 | @drives = sort @drives; |
||
| 152 | |||
| 153 | warn "[DEBUG] Drives: ",join(', ',@drives),"\n" if $DEBUG;
|
||
| 154 | |||
| 155 | if (defined $ARGV[0]) {
|
||
| 156 | if ($ARGV[0] eq 'autoconf') {
|
||
| 157 | if ($smartctl and -x $smartctl) {
|
||
| 158 | if (@drives) {
|
||
| 159 | my $cmd = command_for_drive_device($drives[0], |
||
| 160 | device_for_drive($drives[0])); |
||
| 161 | if (`$cmd` =~ /Temperature/) {
|
||
| 162 | print "yes\n"; |
||
| 163 | } else {
|
||
| 164 | print "no (first drive not supported, configure the plugin)\n"; |
||
| 165 | } |
||
| 166 | exit 0; |
||
| 167 | } else {
|
||
| 168 | print "no (no drives known)\n"; |
||
| 169 | exit 0; |
||
| 170 | } |
||
| 171 | } else {
|
||
| 172 | print "no (smartctl not found)\n"; |
||
| 173 | exit 0; |
||
| 174 | } |
||
| 175 | } elsif ($ARGV[0] eq 'config') {
|
||
| 176 | print "graph_title HDD temperature\n"; |
||
| 177 | print "graph_args --base 1000 -l 0\n"; |
||
| 178 | print "graph_vlabel temp in ╟C\n"; |
||
| 179 | print "graph_category sensors\n"; |
||
| 180 | print "graph_info This graph shows the temperature in degrees Celsius of the hard drives in the machine.\n"; |
||
| 181 | print "$_.label $_\n" foreach @drives; |
||
| 182 | exit 0; |
||
| 183 | } |
||
| 184 | } |
||
| 185 | |||
| 186 | foreach my $drive (@drives) {
|
||
| 187 | warn "[DEBUG] Processing $drive\n" if $DEBUG; |
||
| 188 | my $fulldev = device_for_drive($drive); |
||
| 189 | |||
| 190 | # Fall back to using hdparm for detecting disks in stand-by only if nocheck |
||
| 191 | # isn't supported (hdparm isn't available on all platforms). |
||
| 192 | if (!$use_nocheck && $hdparm && $fulldev =~ /\/dev\/[sh]d?/) {
|
||
| 193 | if (`$hdparm -C $fulldev 2>/dev/null` =~ /standby/) {
|
||
| 194 | warn "[DEBUG] Drive $fulldev is in standby mode, not checking\n" |
||
| 195 | if $DEBUG; |
||
| 196 | next; |
||
| 197 | } |
||
| 198 | } |
||
| 199 | |||
| 200 | my $cmd = command_for_drive_device($drive, $fulldev, $use_nocheck); |
||
| 201 | warn "[DEBUG] Command for $drive is % $cmd %\n" if $DEBUG; |
||
| 202 | |||
| 203 | my $output = `$cmd`; |
||
| 204 | if ($? ne 0) {
|
||
| 205 | print "$drive.value U\n"; |
||
| 206 | print "$drive.extinfo Command $cmd on drive $drive failed: $?. The plugin needs to have read permission on all monitored devices.\n"; |
||
| 207 | warn "[ERROR] Command $cmd on drive $drive failed: $?. The plugin needs to have read permission on all monitored devices.\n"; |
||
| 208 | next; |
||
| 209 | } |
||
| 210 | if ($output =~ /Current Drive Temperature:\s*(\d+)/) {
|
||
| 211 | print "$drive.value $1\n"; |
||
| 212 | } elsif ($output =~ /^(194 Temperature_Celsius.*)/m) {
|
||
| 213 | my @F = split /\s+/, $1; |
||
| 214 | print "$drive.value $F[9]\n"; |
||
| 215 | } elsif ($output =~ /^(231 Temperature_Celsius.*)/m) {
|
||
| 216 | my @F = split ' ', $1; |
||
| 217 | print "$drive.value $F[9]\n"; |
||
| 218 | } elsif ($output =~ /^(190 Airflow_Temperature_Cel.*)/m) {
|
||
| 219 | my @F = split ' ', $1; |
||
| 220 | print "$drive.value $F[9]\n"; |
||
| 221 | } else {
|
||
| 222 | print "$drive.value U\n"; |
||
| 223 | print "$drive.extinfo Temperature not detected in smartctl output\n"; |
||
| 224 | } |
||
| 225 | } |
||
| 226 | |||
| 227 | |||
| 228 | sub device_for_drive {
|
||
| 229 | my ($drive) = @_; |
||
| 230 | |||
| 231 | my $dev = $drive =~ /(.*)(?:_\d+)/ ? $1 : $drive; |
||
| 232 | |||
| 233 | my $fulldev = '/dev/'; |
||
| 234 | $fulldev .= 'rdsk/' if $^O eq 'solaris'; |
||
| 235 | $fulldev .= exists $ENV{'dev_'.$drive} ? $ENV{'dev_'.$drive} : $dev;
|
||
| 236 | |||
| 237 | return $fulldev; |
||
| 238 | } |
||
| 239 | |||
| 240 | sub command_for_drive_device {
|
||
| 241 | my ($drive, $fulldev, $use_nocheck) = @_; |
||
| 242 | |||
| 243 | my $cmd = $smartctl.' -A '; |
||
| 244 | $cmd .= '--nocheck=standby ' if $use_nocheck; |
||
| 245 | $cmd .= $ENV{'args_'.$drive}.' ' if exists $ENV{'args_'.$drive};
|
||
| 246 | $cmd .= '-d '.$ENV{'type_'.$drive}.' ' if exists $ENV{'type_'.$drive};
|
||
| 247 | $cmd .= $fulldev; |
||
| 248 | |||
| 249 | } |
