]>
jfr.im git - munin-plugins.git/blob - hddtemp_smartctl
9 hddtemp_smartctl - Plugin to monitor harddrive temperatures through
14 This plugin needs to run as root or some other user that has access to
15 the harddrive devices.
17 The following environment variables are used
19 smartctl - path to smartctl executable
20 drives - List drives to monitor. E.g. "env.drives hda hdc".
21 type_$dev - device type for one drive, e.g. "env.type_sda 3ware,0"
22 or more typically "env.type_sda ata" if sda is a SATA disk.
23 args_$dev - additional arguments to smartctl for one drive,
24 e.g. "env.args_hda -v 194,10xCelsius". Use this to make
25 the plugin use the --all or -a option if your disk will
26 not return its temperature when only the -A option is
28 dev_$dev - monitoring device for one drive, e.g. twe0
30 If the "smartctl" environment variable is not set the plugin will
31 search your $PATH, /usr/bin, /usr/sbin, /usr/local/bin and
32 /usr/local/sbin for a file called "smartctl", and use that.
34 If the "drives" environment variable is not set, the plugin will
35 attempt to search for drives to probe.
40 #%# capabilities=autoconf
44 Copyright (c) 2005, Lutz Peter Christoph
47 2016-08-27, Gabriele Pohl (contact@dipohl.de)
48 Fix for github issue #690
52 Redistribution and use in source and binary forms, with or without
53 modification, are permitted provided that the following conditions
56 * Redistributions of source code must retain the above copyright
57 notice, this list of conditions and the following disclaimer.
59 * Redistributions in binary form must reproduce the above copyright
60 notice, this list of conditions and the following disclaimer in
61 the documentation and/or other materials provided with the
64 * The name and aliases of Lutz Peter Christoph ("Lupe Christoph",
65 "Lutz Christoph") may not be used to endorse or promote products
66 derived from this software without specific prior written
69 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
70 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
71 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
72 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
73 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
74 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
75 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
76 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
77 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
78 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
79 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
83 Note for users of RAID controllers (smartmontools currently only
84 supports 3ware): you can specify the drives attached to your RAID
85 controller(s) as raiddev_num (e.g. sda_0). Then you must specify the
86 type like this: type_sda_0 3ware,0.
88 Recent versions of the kernel driver use a separate major device
89 number for monitoring purposes, like /dev/twe<n> or /dev/twa<n>. This
90 can be put in the e.g. dev_sda environment variable, to allow the user
91 to keep sda as the name of the disk.
95 use File
::Spec
::Functions
qw(splitdir);
96 use lib
$ENV{'MUNIN_LIBDIR'};
99 my $DEBUG = $ENV{'MUNIN_DEBUG'} || 0;
103 if (exists $ENV{smartctl
}) {
104 $smartctl = $ENV{smartctl
};
105 if (defined $ARGV[0] and $ARGV[0] eq 'autoconf') {
106 # The real "autoconf" section follows later. But here we need to check for requirements, too.
107 if (! -e
$smartctl) {
108 print "no (Predefined smartctl ($smartctl) does not exist)\n";
110 } elsif (! -x
$smartctl) {
111 print "no (Predefined smartctl ($smartctl) is not executable)\n";
115 # immediate failure is allowed outside of "autoconf"
116 die "$smartctl does not exist\n" unless (-e
$smartctl);
117 die "$smartctl is not executable\n" unless (-x
$smartctl);
120 # Not defined in %ENV? Check obvious places
121 my @dirs = split(':', $ENV{PATH
});
122 push (@dirs, qw(/usr/bin /usr/sbin /usr/local/bin /usr/local/sbin) );
124 until ($smartctl or @dirs == 0) {
125 my $dir = shift @dirs;
126 my $path = $dir.'/smartctl';
127 $smartctl = $path if -x
$path;
131 if (defined $ARGV[0] and $ARGV[0] eq 'autoconf') {
132 print "no ('smartctl' executable not found)\n";
135 die "'smartctl' executable not found\n";
142 # Try to get a default set of drives
143 if ($^O eq 'linux') {
144 # On Linux, we know how to enumerate ide drives.
146 if (-d
'/proc/ide') {
147 opendir(IDE
, '/proc/ide');
148 @drivesIDE = grep /hd[a-z]/, readdir IDE
;
152 # Look for SCSI / SATA drives in /sys
154 if (-d
'/sys/block/') {
155 opendir(SCSI
, '/sys/block/');
156 @drivesSCSI = grep /sd[a-z]/, readdir SCSI
;
160 # Look for NVMe drives in /sys
162 if (-d
'/sys/block/') {
163 opendir(NVME
, '/sys/block/');
164 @drivesNVME = grep /nvme[0-9]+n[0-9]+/, readdir NVME
;
168 # Get list of all drives we found
169 @drives=(@drivesIDE,@drivesSCSI,@drivesNVME);
171 } elsif ($^O eq 'freebsd') {
172 opendir(DEV
, '/dev');
173 @drives = grep /^(ada?|da)[0-9]+$/, readdir DEV
;
175 } elsif ($^O eq 'solaris') {
176 @drives = map { s
@.*/@@ ; $_ } glob '/dev
/rdsk/c*t
*d
*s2
';
179 @drives = split ' ', $ENV{drives} if exists $ENV{drives};
181 # Sort list of drives
182 @drives = sort @drives;
184 warn "[DEBUG] Drives: ",join(', ',@drives),"\n" if $DEBUG;
186 if (defined $ARGV[0]) {
187 if ($ARGV[0] eq 'autoconf
') {
189 my $cmd = command_for_drive_device($drives[0],
190 device_for_drive($drives[0]));
191 if (`$cmd` =~ /Temperature/) {
194 print "no (first drive not supported, configure the plugin)\n";
198 print "no (no drives known)\n";
201 } elsif ($ARGV[0] eq 'config
') {
202 print "graph_title HDD temperature\n";
203 print "graph_vlabel Degrees Celsius\n";
204 print "graph_category sensors\n";
205 print "graph_info This graph shows the temperature in degrees Celsius of the hard drives in the machine.\n";
207 my @dirs = splitdir($_);
208 print clean_fieldname($_) . ".label " . $dirs[-1] . "\n";
209 print clean_fieldname($_) . ".max 100\n";
210 print clean_fieldname($_) . ".warning 57\n";
211 print clean_fieldname($_) . ".critical 60\n";
217 foreach my $drive (@drives) {
218 warn "[DEBUG] Processing $drive\n" if $DEBUG;
219 my $fulldev = device_for_drive($drive);
221 my $cmd = command_for_drive_device($drive, $fulldev);
222 warn "[DEBUG] Command for $drive is % $cmd %\n" if $DEBUG;
228 $output =~ s/.*?\n\n//s;
230 $output =~ s/Please specify device type with the -d option.\n//s;
231 $output =~ s/Use smartctl -h to get a usage summary//s;
232 $output =~ s/\n+$//s;
234 if ($cmd_exit != 0) {
235 print "$drive.value U\n";
236 if ($cmd_exit == -1) {
237 warn "[ERROR] Command $cmd on drive $drive failed to execute: $!";
239 my $smartctl_exit = $cmd_exit >> 8;
240 print "$drive.extinfo Command '$cmd' on drive $drive failed with exit($smartctl_exit)\n";
242 warn "[ERROR] Command $cmd on drive $drive failed with exit($smartctl_exit): $output";
246 if ($output =~ /Current Drive Temperature:\s*(\d+)/) {
247 print "$drive.value $1\n";
248 } elsif ($output =~ /^(194 Temperature_(Celsius|Internal).*)/m) {
249 my @F = split /\s+/, $1;
250 print "$drive.value $F[9]\n";
251 } elsif ($output =~ /^(231 Temperature_Celsius.*)/m) {
252 my @F = split ' ', $1;
253 print "$drive.value $F[9]\n";
254 } elsif ($output =~ /^(190 (Airflow_Temperature_Cel|Temperature_Case).*)/m) {
255 my @F = split ' ', $1;
256 print "$drive.value $F[9]\n";
257 } elsif ($output =~ /Temperature:\s*(\d+) Celsius/) {
258 print "$drive.value $1\n";
260 print "$drive.value U\n";
261 print "$drive.extinfo Temperature not detected in smartctl output\n";
266 sub device_for_drive {
269 my $dev = $drive =~ /(.*)(?:_\d+)$/ ? $1 : $drive;
271 my $fulldev = '/dev/';
272 $fulldev .= 'rdsk
/' if $^O eq 'solaris
';
273 $fulldev .= exists $ENV{'dev_
'.$drive} ? $ENV{'dev_
'.$drive} : $dev;
279 sub command_for_drive_device {
280 my ($drive, $fulldev) = @_;
282 my $cmd = $smartctl.' -A
';
283 $cmd .= $ENV{'args_
'.$drive}.' ' if exists $ENV{'args_
'.$drive};
284 $cmd .= '-d
'.$ENV{'type_
'.$drive}.' ' if exists $ENV{'type_
'.$drive};