Merge branch 'master' of ssh://tonvoon@nagiosplug.git.sourceforge.net/gitroot/nagiosp...
[monitoring-plugins.git] / plugins / check_ide_smart.c
blobb942461b25e621b9dca005a30b40c3e5efc6c3ab
1 /*****************************************************************************
2 *
3 * Nagios check_ide_smart plugin
4 * ide-smart 1.3 - IDE S.M.A.R.T. checking tool
5 *
6 * License: GPL
7 * Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
8 * 1998 Gadi Oxman <gadio@netvision.net.il>
9 * Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
10 * Copyright (c) 2000-2007 Nagios Plugins Development Team
12 * Description:
14 * This file contains the check_ide_smart plugin
16 * This plugin checks a local hard drive with the (Linux specific) SMART
17 * interface
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 *****************************************************************************/
36 const char *progname = "check_ide_smart";
37 const char *copyright = "1998-2007";
38 const char *email = "nagiosplug-devel@lists.sourceforge.net";
40 #include "common.h"
41 #include "utils.h"
43 void print_help (void);
44 void print_usage (void);
46 #include <sys/stat.h>
47 #include <sys/ioctl.h>
48 #include <fcntl.h>
49 #include <linux/hdreg.h>
50 #include <linux/types.h>
51 #include <errno.h>
53 #define NR_ATTRIBUTES 30
55 #ifndef TRUE
56 #define TRUE 1
57 #endif /* */
59 #define PREFAILURE 2
60 #define ADVISORY 1
61 #define OPERATIONAL 0
62 #define UNKNOWN -1
64 typedef struct threshold_s
66 __u8 id;
67 __u8 threshold;
68 __u8 reserved[10];
70 __attribute__ ((packed)) threshold_t;
72 typedef struct thresholds_s
74 __u16 revision;
75 threshold_t thresholds[NR_ATTRIBUTES];
76 __u8 reserved[18];
77 __u8 vendor[131];
78 __u8 checksum;
80 __attribute__ ((packed)) thresholds_t;
82 typedef struct value_s
84 __u8 id;
85 __u16 status;
86 __u8 value;
87 __u8 vendor[8];
89 __attribute__ ((packed)) value_t;
91 typedef struct values_s
93 __u16 revision;
94 value_t values[NR_ATTRIBUTES];
95 __u8 offline_status;
96 __u8 vendor1;
97 __u16 offline_timeout;
98 __u8 vendor2;
99 __u8 offline_capability;
100 __u16 smart_capability;
101 __u8 reserved[16];
102 __u8 vendor[125];
103 __u8 checksum;
105 __attribute__ ((packed)) values_t;
107 struct
109 __u8 value;
110 char *text;
113 offline_status_text[] =
115 {0x00, "NeverStarted"},
116 {0x02, "Completed"},
117 {0x04, "Suspended"},
118 {0x05, "Aborted"},
119 {0x06, "Failed"},
120 {0, 0}
123 struct
125 __u8 value;
126 char *text;
129 smart_command[] =
131 {SMART_ENABLE, "SMART_ENABLE"},
132 {SMART_DISABLE, "SMART_DISABLE"},
133 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
134 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
138 /* Index to smart_command table, keep in order */
139 enum SmartCommand
140 { SMART_CMD_ENABLE,
141 SMART_CMD_DISABLE,
142 SMART_CMD_IMMEDIATE_OFFLINE,
143 SMART_CMD_AUTO_OFFLINE
146 void print_values (values_t * p, thresholds_t * t);
147 int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error);
150 main (int argc, char *argv[])
152 char *device = NULL;
153 int command = -1;
154 int o, longindex;
155 int retval = 0;
157 thresholds_t thresholds;
158 values_t values;
159 int fd;
161 static struct option longopts[] = {
162 {"device", required_argument, 0, 'd'},
163 {"immediate", no_argument, 0, 'i'},
164 {"quiet-check", no_argument, 0, 'q'},
165 {"auto-on", no_argument, 0, '1'},
166 {"auto-off", no_argument, 0, '0'},
167 {"nagios", no_argument, 0, 'n'},
168 {"help", no_argument, 0, 'h'},
169 {"version", no_argument, 0, 'V'},
170 {0, 0, 0, 0}
173 /* Parse extra opts if any */
174 argv=np_extra_opts (&argc, argv, progname);
176 setlocale (LC_ALL, "");
177 bindtextdomain (PACKAGE, LOCALEDIR);
178 textdomain (PACKAGE);
180 while (1) {
182 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
184 if (o == -1 || o == EOF || o == 1)
185 break;
187 switch (o) {
188 case 'd':
189 device = optarg;
190 break;
191 case 'q':
192 command = 3;
193 break;
194 case 'i':
195 command = 2;
196 break;
197 case '1':
198 command = 1;
199 break;
200 case '0':
201 command = 0;
202 break;
203 case 'n':
204 command = 4;
205 break;
206 case 'h':
207 print_help ();
208 return STATE_OK;
209 case 'V':
210 print_revision (progname, NP_VERSION);
211 return STATE_OK;
212 default:
213 usage5 ();
217 if (optind < argc) {
218 device = argv[optind];
221 if (!device) {
222 print_help ();
223 return STATE_OK;
226 fd = open (device, O_RDONLY);
228 if (fd < 0) {
229 printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno));
230 return STATE_CRITICAL;
233 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
234 printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
235 return STATE_CRITICAL;
238 switch (command) {
239 case 0:
240 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
241 break;
242 case 1:
243 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
244 break;
245 case 2:
246 retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
247 break;
248 case 3:
249 smart_read_values (fd, &values);
250 smart_read_thresholds (fd, &thresholds);
251 retval = values_not_passed (&values, &thresholds);
252 break;
253 case 4:
254 smart_read_values (fd, &values);
255 smart_read_thresholds (fd, &thresholds);
256 retval = nagios (&values, &thresholds);
257 break;
258 default:
259 smart_read_values (fd, &values);
260 smart_read_thresholds (fd, &thresholds);
261 print_values (&values, &thresholds);
262 break;
264 close (fd);
265 return retval;
270 char *
271 get_offline_text (int status)
273 int i;
274 for (i = 0; offline_status_text[i].text; i++) {
275 if (offline_status_text[i].value == status) {
276 return offline_status_text[i].text;
279 return "UNKNOW";
285 smart_read_values (int fd, values_t * values)
287 int e;
288 __u8 args[4 + 512];
289 args[0] = WIN_SMART;
290 args[1] = 0;
291 args[2] = SMART_READ_VALUES;
292 args[3] = 1;
293 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
294 e = errno;
295 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
296 return e;
298 memcpy (values, args + 4, 512);
299 return 0;
305 values_not_passed (values_t * p, thresholds_t * t)
307 value_t * value = p->values;
308 threshold_t * threshold = t->thresholds;
309 int failed = 0;
310 int passed = 0;
311 int i;
312 for (i = 0; i < NR_ATTRIBUTES; i++) {
313 if (value->id && threshold->id && value->id == threshold->id) {
314 if (value->value <= threshold->threshold) {
315 ++failed;
317 else {
318 ++passed;
321 ++value;
322 ++threshold;
324 return (passed ? -failed : 2);
330 nagios (values_t * p, thresholds_t * t)
332 value_t * value = p->values;
333 threshold_t * threshold = t->thresholds;
334 int status = OPERATIONAL;
335 int prefailure = 0;
336 int advisory = 0;
337 int failed = 0;
338 int passed = 0;
339 int total = 0;
340 int i;
341 for (i = 0; i < NR_ATTRIBUTES; i++) {
342 if (value->id && threshold->id && value->id == threshold->id) {
343 if (value->value <= threshold->threshold) {
344 ++failed;
345 if (value->status & 1) {
346 status = PREFAILURE;
347 ++prefailure;
349 else {
350 status = ADVISORY;
351 ++advisory;
354 else {
355 ++passed;
357 ++total;
359 ++value;
360 ++threshold;
362 switch (status) {
363 case PREFAILURE:
364 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
365 prefailure,
366 prefailure > 1 ? 's' : ' ',
367 failed,
368 total);
369 status=STATE_CRITICAL;
370 break;
371 case ADVISORY:
372 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
373 advisory,
374 advisory > 1 ? "ies" : "y",
375 failed,
376 total);
377 status=STATE_WARNING;
378 break;
379 case OPERATIONAL:
380 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
381 status=STATE_OK;
382 break;
383 default:
384 printf (_("ERROR - Status '%d' unkown. %d/%d tests passed\n"), status,
385 passed, total);
386 status = STATE_UNKNOWN;
387 break;
389 return status;
394 void
395 print_value (value_t * p, threshold_t * t)
397 printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
398 p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
399 p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
400 p->value > t->threshold ? "Passed" : "Failed");
405 void
406 print_values (values_t * p, thresholds_t * t)
408 value_t * value = p->values;
409 threshold_t * threshold = t->thresholds;
410 int i;
411 for (i = 0; i < NR_ATTRIBUTES; i++) {
412 if (value->id && threshold->id && value->id == threshold->id) {
413 print_value (value++, threshold++);
416 printf
417 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
418 p->offline_status,
419 get_offline_text (p->offline_status & 0x7f),
420 (p->offline_status & 0x80 ? "Yes" : "No"),
421 p->offline_timeout / 60);
422 printf
423 (_("OffLineCapability=%d {%s %s %s}\n"),
424 p->offline_capability,
425 p->offline_capability & 1 ? "Immediate" : "",
426 p->offline_capability & 2 ? "Auto" : "",
427 p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
428 printf
429 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
430 p->revision,
431 p->checksum,
432 p->smart_capability,
433 p->smart_capability & 1 ? "SaveOnStandBy" : "",
434 p->smart_capability & 2 ? "AutoSave" : "");
439 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error)
441 int e = 0;
442 __u8 args[4];
443 args[0] = WIN_SMART;
444 args[1] = val0;
445 args[2] = smart_command[command].value;
446 args[3] = 0;
447 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
448 e = errno;
449 if (show_error) {
450 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
453 return e;
459 smart_read_thresholds (int fd, thresholds_t * thresholds)
461 int e;
462 __u8 args[4 + 512];
463 args[0] = WIN_SMART;
464 args[1] = 0;
465 args[2] = SMART_READ_THRESHOLDS;
466 args[3] = 1;
467 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
468 e = errno;
469 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
470 return e;
472 memcpy (thresholds, args + 4, 512);
473 return 0;
477 void
478 print_help (void)
480 print_revision (progname, NP_VERSION);
482 printf ("Nagios feature - 1999 Robert Dale <rdale@digital-mission.com>\n");
483 printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
484 printf (COPYRIGHT, copyright, email);
486 printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php]."));
488 printf ("\n\n");
490 print_usage ();
492 printf (UT_HELP_VRSN);
493 printf (UT_EXTRA_OPTS);
495 printf (" %s\n", "-d, --device=DEVICE");
496 printf (" %s\n", _("Select device DEVICE"));
497 printf (" %s\n", _("Note: if the device is selected with this option, _no_ other options are accepted"));
498 printf (" %s\n", "-i, --immediate");
499 printf (" %s\n", _("Perform immediately offline tests"));
500 printf (" %s\n", "-q, --quiet-check");
501 printf (" %s\n", _("Returns the number of failed tests"));
502 printf (" %s\n", "-1, --auto-on");
503 printf (" %s\n", _("Turn on automatic offline tests"));
504 printf (" %s\n", "-0, --auto-off");
505 printf (" %s\n", _("Turn off automatic offline tests"));
506 printf (" %s\n", "-n, --nagios");
507 printf (" %s\n", _("Output suitable for Nagios"));
509 printf (UT_SUPPORT);
512 /* todo : add to the long nanual as example
514 * Run with: check_ide-smart --nagios [-d] <DRIVE>
515 * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
517 * - Returns 0 on no errors
518 * - Returns 1 on advisories
519 * - Returns 2 on prefailure
520 * - Returns -1 not too often
524 void
525 print_usage (void)
527 printf ("%s\n", _("Usage:"));
528 printf ("%s [-d <device>] [-i <immediate>] [-q quiet] [-1 <auto-on>]",progname);
529 printf (" [-O <auto-off>] [-n <nagios>]\n");