Code

The "-e" option now accepts a comma-delimited list of expected status
[nagiosplug.git] / plugins / check_ide_smart.c
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
11
12 * Last Modified: $Date$
13
14 * Description:
15
16 * This file contains the check_ide_smart plugin
17
18 * This plugin checks a local hard drive with the (Linux specific) SMART
19 * interface
20
21
22 * This program is free software: you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation, either version 3 of the License, or
25 * (at your option) any later version.
26
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30 * GNU General Public License for more details.
31
32 * You should have received a copy of the GNU General Public License
33 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
34
35 * $Id$
36
37 *****************************************************************************/
39 const char *progname = "check_ide_smart";
40 const char *revision = "$Revision$";
41 const char *copyright = "1998-2007";
42 const char *email = "nagiosplug-devel@lists.sourceforge.net";
43         
44 #include "common.h"
45 #include "utils.h"
47 void print_help (void);
48 void print_usage (void);
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <fcntl.h>
53 #include <linux/hdreg.h>
54 #include <linux/types.h>
55 #include <errno.h>
56         
57 #define NR_ATTRIBUTES   30
58         
59 #ifndef TRUE
60 #define TRUE 1
61 #endif  /*  */
62         
63 #define PREFAILURE 2
64 #define ADVISORY 1
65 #define OPERATIONAL 0
66 #define UNKNOWN -1
68 typedef struct threshold_s
69 {
70         __u8 id;
71         __u8 threshold;
72         __u8 reserved[10];
73 }
74 __attribute__ ((packed)) threshold_t;
76 typedef struct thresholds_s
77 {
78         __u16 revision;
79         threshold_t thresholds[NR_ATTRIBUTES];
80         __u8 reserved[18];
81         __u8 vendor[131];
82         __u8 checksum;
83 }
84 __attribute__ ((packed)) thresholds_t;
86 typedef struct value_s
87 {
88         __u8 id;
89         __u16 status;
90         __u8 value;
91         __u8 vendor[8];
92 }
93 __attribute__ ((packed)) value_t;
95 typedef struct values_s
96 {
97         __u16 revision;
98         value_t values[NR_ATTRIBUTES];
99         __u8 offline_status;
100         __u8 vendor1;
101         __u16 offline_timeout;
102         __u8 vendor2;
103         __u8 offline_capability;
104         __u16 smart_capability;
105         __u8 reserved[16];
106         __u8 vendor[125];
107         __u8 checksum;
109 __attribute__ ((packed)) values_t;
111 struct
113         __u8 value;
114         char *text;
117 offline_status_text[] =
118         {
119                 {0x00, "NeverStarted"},
120                 {0x02, "Completed"},
121                 {0x04, "Suspended"},
122                 {0x05, "Aborted"},
123                 {0x06, "Failed"},
124                 {0, 0}
125         };
127 struct
129         __u8 value;
130         char *text;
133 smart_command[] =
134         {
135                 {SMART_ENABLE, "SMART_ENABLE"},
136                 {SMART_DISABLE, "SMART_DISABLE"},
137                 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
138                 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
139         };
142 /* Index to smart_command table, keep in order */ 
143 enum SmartCommand 
144         { SMART_CMD_ENABLE,
145                 SMART_CMD_DISABLE,
146                 SMART_CMD_IMMEDIATE_OFFLINE,
147                 SMART_CMD_AUTO_OFFLINE 
148         };
150 void print_values (values_t * p, thresholds_t * t);
151 int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error); 
153 int
154 main (int argc, char *argv[]) 
156         char *device = NULL;
157         int command = -1;
158         int o, longindex;
159         int retval = 0;
161         thresholds_t thresholds;
162         values_t values;
163         int fd;
165         /* Parse extra opts if any */
166         argv=np_extra_opts (&argc, argv, progname);
168         static struct option longopts[] = { 
169                 {"device", required_argument, 0, 'd'}, 
170                 {"immediate", no_argument, 0, 'i'}, 
171                 {"quiet-check", no_argument, 0, 'q'}, 
172                 {"auto-on", no_argument, 0, '1'}, 
173                 {"auto-off", no_argument, 0, '0'}, 
174                 {"nagios", no_argument, 0, 'n'}, 
175                 {"help", no_argument, 0, 'h'}, 
176                 {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} 
177         };
179         setlocale (LC_ALL, "");
180         bindtextdomain (PACKAGE, LOCALEDIR);
181         textdomain (PACKAGE);
183         while (1) {
184                 
185                 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
187                 if (o == -1 || o == EOF || o == 1)
188                         break;
190                 switch (o) {
191                 case 'd':
192                         device = optarg;
193                         break;
194                 case 'q':
195                         command = 3;
196                         break;
197                 case 'i':
198                         command = 2;
199                         break;
200                 case '1':
201                         command = 1;
202                         break;
203                 case '0':
204                         command = 0;
205                         break;
206                 case 'n':
207                         command = 4;
208                         break;
209                 case 'h':
210                         print_help ();
211                         return STATE_OK;
212                 case 'V':
213                         print_revision (progname, revision);
214                         return STATE_OK;
215                 default:
216                         usage5 ();
217                 }
218         }
220         if (optind < argc) {
221                 device = argv[optind];
222         }
224         if (!device) {
225                 print_help ();
226                 return STATE_OK;
227         }
229         fd = open (device, O_RDONLY);
231         if (fd < 0) {
232                 printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno));
233                 return STATE_CRITICAL;
234         }
236         if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
237                 printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
238                 return STATE_CRITICAL;
239         }
241         switch (command) {
242         case 0:
243                 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
244                 break;
245         case 1:
246                 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
247                 break;
248         case 2:
249                 retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
250                 break;
251         case 3:
252                 smart_read_values (fd, &values);
253                 smart_read_thresholds (fd, &thresholds);
254                 retval = values_not_passed (&values, &thresholds);
255                 break;
256         case 4:
257                 smart_read_values (fd, &values);
258                 smart_read_thresholds (fd, &thresholds);
259                 retval = nagios (&values, &thresholds);
260                 break;
261         default:
262                 smart_read_values (fd, &values);
263                 smart_read_thresholds (fd, &thresholds);
264                 print_values (&values, &thresholds);
265                 break;
266         }
267         close (fd);
268         return retval;
273 char *
274 get_offline_text (int status) 
276         int i;
277         for (i = 0; offline_status_text[i].text; i++) {
278                 if (offline_status_text[i].value == status) {
279                         return offline_status_text[i].text;
280                 }
281         }
282         return "UNKNOW";
287 int
288 smart_read_values (int fd, values_t * values) 
290         int e;
291         __u8 args[4 + 512];
292         args[0] = WIN_SMART;
293         args[1] = 0;
294         args[2] = SMART_READ_VALUES;
295         args[3] = 1;
296         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
297                 e = errno;
298                 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
299                 return e;
300         }
301         memcpy (values, args + 4, 512);
302         return 0;
307 int
308 values_not_passed (values_t * p, thresholds_t * t) 
310         value_t * value = p->values;
311         threshold_t * threshold = t->thresholds;
312         int failed = 0;
313         int passed = 0;
314         int i;
315         for (i = 0; i < NR_ATTRIBUTES; i++) {
316                 if (value->id && threshold->id && value->id == threshold->id) {
317                         if (value->value <= threshold->threshold) {
318                                 ++failed;
319                         }
320                         else {
321                                 ++passed;
322                         }
323                 }
324                 ++value;
325                 ++threshold;
326         }
327         return (passed ? -failed : 2);
332 int
333 nagios (values_t * p, thresholds_t * t) 
335         value_t * value = p->values;
336         threshold_t * threshold = t->thresholds;
337         int status = OPERATIONAL;
338         int prefailure = 0;
339         int advisory = 0;
340         int failed = 0;
341         int passed = 0;
342         int total = 0;
343         int i;
344         for (i = 0; i < NR_ATTRIBUTES; i++) {
345                 if (value->id && threshold->id && value->id == threshold->id) {
346                         if (value->value <= threshold->threshold) {
347                                 ++failed;
348                                 if (value->status & 1) {
349                                         status = PREFAILURE;
350                                         ++prefailure;
351                                 }
352                                 else {
353                                         status = ADVISORY;
354                                         ++advisory;
355                                 }
356                         }
357                         else {
358                                 ++passed;
359                         }
360                         ++total;
361                 }
362                 ++value;
363                 ++threshold;
364         }
365         switch (status) {
366         case PREFAILURE:
367                 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
368                         prefailure,
369                         prefailure > 1 ? 's' : ' ',
370                         failed,
371                   total);
372                 status=STATE_CRITICAL;
373                 break;
374         case ADVISORY:
375                 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
376                         advisory,
377                         advisory > 1 ? "ies" : "y",
378                         failed,
379                         total);
380                 status=STATE_WARNING;
381                 break;
382         case OPERATIONAL:
383                 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
384                 status=STATE_OK;
385                 break;
386         default:
387                 printf (_("ERROR - Status '%d' unkown. %d/%d tests passed\n"), status,
388                                                 passed, total);
389                 status = STATE_UNKNOWN;
390                 break;
391         }
392         return status;
397 void
398 print_value (value_t * p, threshold_t * t) 
400         printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
401                                         p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory   ",
402                                         p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
403                                         p->value > t->threshold ? "Passed" : "Failed");
408 void
409 print_values (values_t * p, thresholds_t * t)
411         value_t * value = p->values;
412         threshold_t * threshold = t->thresholds;
413         int i;
414         for (i = 0; i < NR_ATTRIBUTES; i++) {
415                 if (value->id && threshold->id && value->id == threshold->id) {
416                         print_value (value++, threshold++);
417                 }
418         }
419         printf
420                 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
421                  p->offline_status,
422                  get_offline_text (p->offline_status & 0x7f),
423                  (p->offline_status & 0x80 ? "Yes" : "No"),
424                  p->offline_timeout / 60);
425         printf
426                 (_("OffLineCapability=%d {%s %s %s}\n"),
427                  p->offline_capability,
428                  p->offline_capability & 1 ? "Immediate" : "",
429                  p->offline_capability & 2 ? "Auto" : "",
430                  p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
431         printf
432                 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
433                  p->revision,
434                  p->checksum,
435                  p->smart_capability,
436                  p->smart_capability & 1 ? "SaveOnStandBy" : "",
437                  p->smart_capability & 2 ? "AutoSave" : "");
441 int
442 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error) 
444         int e = 0;
445         __u8 args[4];
446         args[0] = WIN_SMART;
447         args[1] = val0;
448         args[2] = smart_command[command].value;
449         args[3] = 0;
450         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
451                 e = errno;
452                 if (show_error) {
453                         printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
454                 }
455         }
456         return e;
461 int
462 smart_read_thresholds (int fd, thresholds_t * thresholds) 
464         int e;
465         __u8 args[4 + 512];
466         args[0] = WIN_SMART;
467   args[1] = 0;
468   args[2] = SMART_READ_THRESHOLDS;
469   args[3] = 1;
470         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
471                 e = errno;
472                 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
473                 return e;
474         }
475         memcpy (thresholds, args + 4, 512);
476         return 0;
480 void
481 print_help (void)
483         print_revision (progname, revision);
485         printf ("Nagios feature - 1999 Robert Dale <rdale@digital-mission.com>\n");
486         printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
487         printf (COPYRIGHT, copyright, email);
489         printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php]."));
491   printf ("\n\n");
493   print_usage ();
495   printf (_(UT_HELP_VRSN));
496   printf (_(UT_EXTRA_OPTS));
498   printf (" %s\n", "-d, --device=DEVICE");
499   printf ("    %s\n", _("Select device DEVICE"));
500   printf ("    %s\n", _("Note: if the device is selected with this option, _no_ other options are accepted"));
501   printf (" %s\n", "-i, --immediate");
502   printf ("    %s\n", _("Perform immediately offline tests"));
503   printf (" %s\n", "-q, --quiet-check");
504   printf ("    %s\n", _("Returns the number of failed tests"));
505   printf (" %s\n", "-1, --auto-on");
506   printf ("    %s\n", _("Turn on automatic offline tests"));
507   printf (" %s\n", "-0, --auto-off");
508   printf ("    %s\n", _("Turn off automatic offline tests"));
509   printf (" %s\n", "-n, --nagios");
510   printf ("    %s\n", _("Output suitable for Nagios"));
512 #ifdef NP_EXTRA_OPTS
513   printf ("\n");
514   printf ("%s\n", _("Notes:"));
515   printf (_(UT_EXTRA_OPTS_NOTES));
516 #endif
518   printf (_(UT_SUPPORT));
521  /* todo : add to the long nanual as example
522  *
523  *     Run with:  check_ide-smart --nagios [-d] <DRIVE>
524  *     Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
525  *
526  *       - Returns 0 on no errors
527  *       - Returns 1 on advisories
528  *       - Returns 2 on prefailure
529  *       - Returns -1 not too often
530  */
533 void
534 print_usage (void)
536   printf (_("Usage:"));
537   printf ("%s [-d <device>] [-i <immediate>] [-q quiet] [-1 <auto-on>]",progname);
538   printf (" [-O <auto-off>] [-n <nagios>]\n");