Subversion Repositories vnag

Rev

Rev 77 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * VNag - Nagios Framework for PHP
5
 * Developed by Daniel Marschall, ViaThinkSoft <www.viathinksoft.com>
6
 * Licensed under the terms of the Apache 2.0 license
7
 *
77 daniel-mar 8
 * Revision 2023-10-13
2 daniel-mar 9
 */
10
 
11
declare(ticks=1);
12
 
13
class SmartCheck extends VNag {
49 daniel-mar 14
        protected $argType = null;
15
 
2 daniel-mar 16
        public function __construct() {
17
                parent::__construct();
18
 
19
                if ($this->is_http_mode()) {
20
                        // Don't allow the standard arguments via $_REQUEST
21
                        $this->registerExpectedStandardArguments('');
22
                } else {
23
                        $this->registerExpectedStandardArguments('Vhtv');
24
                }
25
 
26
                $this->getHelpManager()->setPluginName('vnag_smart');
79 daniel-mar 27
                $this->getHelpManager()->setVersion('2023-10-13');
2 daniel-mar 28
                $this->getHelpManager()->setShortDescription('This plugin checks the contents of the SMART data and warns when a harddisk has failed.');
29
                $this->getHelpManager()->setCopyright('Copyright (C) 2011-$CURYEAR$ Daniel Marschall, ViaThinkSoft.');
49 daniel-mar 30
                $this->getHelpManager()->setSyntax('$SCRIPTNAME$ [-T <type>]');
2 daniel-mar 31
                $this->getHelpManager()->setFootNotes('If you encounter bugs, please contact ViaThinkSoft at www.viathinksoft.com');
49 daniel-mar 32
 
33
                // TODO: also add a command to check a single drive   [ -d /dev/sda,/dev/sdb ]
34
                // Individual (non-standard) arguments:
50 daniel-mar 35
                $this->addExpectedArgument($this->argType = new VNagArgument('T', 'type', VNagArgument::VALUE_REQUIRED, 'type', 'Explicit drive type e.g. for RAID devices "sat+cciss,0" for drive 0.'));
2 daniel-mar 36
        }
37
 
38
        private function check_smart($dev) {
39
                if (!`which which`) {
40
                        throw new VNagException("Program 'which' is not installed on your system");
41
                }
42
 
43
                if (!`which smartctl`) {
44
                        throw new VNagException("Program 'smartctl' (usually included in package smartmontools) is not installed on your system");
45
                }
46
 
28 daniel-mar 47
                $code = 0;
48
                $out = array();
49 daniel-mar 49
 
50
                if ($this->argType->getValue() != '') {
53 daniel-mar 51
                        // Note: Requires root
52
                        exec('smartctl --all '.escapeshellarg($dev).' -d '.escapeshellarg($this->argType->getValue()), $out, $code);
49 daniel-mar 53
                } else {
53 daniel-mar 54
                        // Note: Requires root
55
                        exec('smartctl --all '.escapeshellarg($dev), $out, $code);
49 daniel-mar 56
                }
2 daniel-mar 57
                $cont = implode("\n", $out);
58
 
59
                $msg = array();
60
                $status = -1;
61
 
62
                if (stripos($cont, 'device lacks SMART capability') !== false)  {
63
                        // At my system (Debian 9), I get exit code 4 (which is not fully accurate)
64
                        $msg[] = 'Device lacks SMART capability';
65
                        #$status = VNag::STATUS_UNKNOWN;
66
                } else if ($code == 0) {
67
                        $status = VNag::STATUS_OK;
68
                } else {
69
                        if ($code & 1) {
77 daniel-mar 70
                                throw new VNagException("smartctl reports 'command line did not parse' (code $code).");
2 daniel-mar 71
                        }
72
                        if ($code & 2) {
73
                                $msg[] = "Device open failed. It is either completely defective, or in low-power mode.";
74
                                $status = max($status, VNag::STATUS_CRITICAL);
75
                        }
76
                        if ($code & 4) {
77
                                $msg[] = "SMART command failed or checksum is wrong.";
78
                                $status = max($status, VNag::STATUS_WARNING);
79
                        }
80
                        if ($code & 8) {
81
                                $msg[] = "SMART status returns 'DISK FAILING'";
82
                                $status = max($status, VNag::STATUS_CRITICAL);
83
                        }
84
                        if ($code & 16) {
85
                                $msg[] = "SMART found prefail attributes below threshold";
86
                                $status = max($status, VNag::STATUS_WARNING);
87
                        }
88
                        if ($code & 32) {
89
                                $msg[] = "SMART status is 'OK' but usage/prefail attributes have been below threshold in the past.";
90
                                $status = max($status, VNag::STATUS_WARNING);
91
                        }
92
                        if ($code & 64) {
93
                                $msg[] = "The device error log contains records of errors.";
94
                                $status = max($status, VNag::STATUS_WARNING);
95
                        }
96
                        if ($code & 128) {
97
                                $msg[] = "The self-test logs contains records of errors.";
98
                                $status = max($status, VNag::STATUS_WARNING);
99
                        }
100
                }
101
 
102
                $messages = implode(", ", $msg);
103
                if ($messages != '') $messages = ": $messages";
104
 
105
                if ($status == VNag::STATUS_CRITICAL) {
106
                        $this->addVerboseMessage("$dev (Critical)$messages", VNag::VERBOSITY_SUMMARY);
107
                } else if ($status == VNag::STATUS_WARNING) {
108
                        $this->addVerboseMessage("$dev (Warning)$messages", VNag::VERBOSITY_SUMMARY);
109
                } else if ($status == VNag::STATUS_OK) {
110
                        $this->addVerboseMessage("$dev (OK)$messages", VNag::VERBOSITY_ADDITIONAL_INFORMATION);
111
                } else {
112
                        $status = VNag::STATUS_UNKNOWN;
113
                        $this->addVerboseMessage("$dev (Unknown)$messages", VNag::VERBOSITY_SUMMARY);
114
                }
115
                $this->setStatus($status);
116
                return $status;
117
        }
118
 
119
        protected function cbRun() {
120
                $devices = array();
121
                $devices = array_merge($devices, glob('/dev/sd?'));
122
                $devices = array_merge($devices, glob('/dev/hd?'));
123
 
49 daniel-mar 124
                if (count($devices) == 0) {
77 daniel-mar 125
                        throw new VNagException("No SDx or HDx drives found");
49 daniel-mar 126
                }
127
 
128
                if (strpos($this->argType->getValue(),'cciss') !== false) {
129
                        $devices = array($devices[0]); // we just need a "fake" drive; the drive number is given as parameter to cciss
130
                }
131
 
2 daniel-mar 132
                $count_total = 0;
133
                $count_ok = 0;
134
                $count_warning = 0;
135
                $count_critical = 0;
136
                $count_unknown = 0;
137
                foreach ($devices as $dev) {
138
                        $count_total++;
139
                        switch ($this->check_smart($dev)) {
140
                                case VNag::STATUS_OK:
141
                                        $count_ok++;
142
                                        break;
143
                                case VNag::STATUS_WARNING:
144
                                        $count_warning++;
145
                                        break;
146
                                case VNag::STATUS_CRITICAL:
147
                                        $count_critical++;
148
                                        break;
149
                                case VNag::STATUS_UNKNOWN:
150
                                        $count_unknown++;
151
                                        break;
152
                        }
153
                }
154
 
155
                $this->setHeadline(sprintf('Checked %d drives (%d OK, %d warning, %d critical, %d unknown)', $count_total, $count_ok, $count_warning, $count_critical, $count_unknown));
156
        }
157
}