Code

changed Error: by CRITICAL -
[nagiosplug.git] / plugins / check_ide-smart.c
1 /*
2  *  check_ide-smart v.1 - hacked version of ide-smart for Nagios
3  *  Copyright (C) 2000 Robert Dale <rdale@digital-mission.com>
4  *
5  *  Nagios - http://www.nagios.org
6  *
7  *  Notes:
8  *         ide-smart has the same functionality as before. Some return
9  *         values were changed, otherwise the --net-saint option was added.
10  *
11  *         Run with:  check_ide-smart --net-saint [-d] <DRIVE>
12  *         Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
13  *
14  *           - Returns 0 on no errors
15  *           - Returns 1 on advisories
16  *           - Returns 2 on prefailure
17  *           - Returns -1 not too often
18  *
19  *  ide-smart 1.3 - IDE S.M.A.R.T. checking tool
20  *  Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
21  *                1998      Gadi Oxman <gadio@netvision.net.il>
22  *
23  *  This program is free software; you can redistribute it and/or modify
24  *  it under the terms of the GNU General Public License as published by
25  *  the Free Software Foundation; either version 2 of the License, or
26  *  (at your option) any later version.
27  *
28  *  This program is distributed in the hope that it will be useful,
29  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
30  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31  *  GNU General Public License for more details.
32  *
33  *  You should have received a copy of the GNU General Public License
34  *  along with this program; if not, write to the Free Software
35  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36  *
37  * $Id$
38  */
39         
40 #include "common.h"
41 #include "utils.h"
42 #include <sys/stat.h>
43 #include <sys/ioctl.h>
44 #include <fcntl.h>
45 #include <linux/hdreg.h>
46 #include <linux/types.h>
47 #include <errno.h>
48         
49 #define NR_ATTRIBUTES   30
50         
51 #ifndef TRUE
52 #define TRUE 1
53 #endif  /*  */
54         
55 #define PREFAILURE 2
56 #define ADVISORY 1
57 #define OPERATIONAL 0
58 #define UNKNOWN -1
60 typedef struct threshold_s
61 {
62         __u8 id;
63         __u8 threshold;
64         __u8 reserved[10];
65 }
66 __attribute__ ((packed)) threshold_t;
68 typedef struct thresholds_s
69 {
70         __u16 revision;
71         threshold_t thresholds[NR_ATTRIBUTES];
72         __u8 reserved[18];
73         __u8 vendor[131];
74         __u8 checksum;
75 }
76 __attribute__ ((packed)) thresholds_t;
78 typedef struct value_s
79 {
80         __u8 id;
81         __u16 status;
82         __u8 value;
83         __u8 vendor[8];
84 }
85 __attribute__ ((packed)) value_t;
87 typedef struct values_s
88 {
89         __u16 revision;
90         value_t values[NR_ATTRIBUTES];
91         __u8 offline_status;
92         __u8 vendor1;
93         __u16 offline_timeout;
94         __u8 vendor2;
95         __u8 offline_capability;
96         __u16 smart_capability;
97         __u8 reserved[16];
98         __u8 vendor[125];
99         __u8 checksum;
101 __attribute__ ((packed)) values_t;
103 struct
105         __u8 value;
106         char *text;
109 offline_status_text[] =
110         {
111                 {0x00, "NeverStarted"},
112                 {0x02, "Completed"},
113                 {0x04, "Suspended"},
114                 {0x05, "Aborted"},
115                 {0x06, "Failed"},
116                 {0, 0}
117         };
119 struct
121         __u8 value;
122         char *text;
125 smart_command[] =
126         {
127                 {SMART_ENABLE, "SMART_ENABLE"},
128                 {SMART_DISABLE, "SMART_DISABLE"},
129                 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
130                 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
131         };
134 /* Index to smart_command table, keep in order */ 
135 enum SmartCommand 
136         { SMART_CMD_ENABLE,
137                 SMART_CMD_DISABLE,
138                 SMART_CMD_IMMEDIATE_OFFLINE,
139                 SMART_CMD_AUTO_OFFLINE 
140         };
144 char *
145 get_offline_text (int status) 
147         int i;
148         for (i = 0; offline_status_text[i].text; i++) {
149                 if (offline_status_text[i].value == status) {
150                         return offline_status_text[i].text;
151                 }
152         }
153         return "UNKNOW";
158 int
159 smart_read_values (int fd, values_t * values) 
161         int e;
162         __u8 args[4 + 512];
163         args[0] = WIN_SMART;
164         args[1] = 0;
165         args[2] = SMART_READ_VALUES;
166         args[3] = 1;
167         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
168                 e = errno;
169                 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
170                 return e;
171         }
172         memcpy (values, args + 4, 512);
173         return 0;
178 int
179 values_not_passed (values_t * p, thresholds_t * t) 
181         value_t * value = p->values;
182         threshold_t * threshold = t->thresholds;
183         int failed = 0;
184         int passed = 0;
185         int i;
186         for (i = 0; i < NR_ATTRIBUTES; i++) {
187                 if (value->id && threshold->id && value->id == threshold->id) {
188                         if (value->value <= threshold->threshold) {
189                                 ++failed;
190                         }
191                         else {
192                                 ++passed;
193                         }
194                 }
195                 ++value;
196                 ++threshold;
197         }
198         return (passed ? -failed : 2);
203 int
204 net_saint (values_t * p, thresholds_t * t) 
206         value_t * value = p->values;
207         threshold_t * threshold = t->thresholds;
208         int status = OPERATIONAL;
209         int prefailure = 0;
210         int advisory = 0;
211         int failed = 0;
212         int passed = 0;
213         int total = 0;
214         int i;
215         for (i = 0; i < NR_ATTRIBUTES; i++) {
216                 if (value->id && threshold->id && value->id == threshold->id) {
217                         if (value->value <= threshold->threshold) {
218                                 ++failed;
219                                 if (value->status & 1) {
220                                         status = PREFAILURE;
221                                         ++prefailure;
222                                 }
223                                 else {
224                                         status = ADVISORY;
225                                         ++advisory;
226                                 }
227                         }
228                         else {
229                                 ++passed;
230                         }
231                         ++total;
232                 }
233                 ++value;
234                 ++threshold;
235         }
236         switch (status) {
237         case PREFAILURE:
238                 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
239                         prefailure,
240                         prefailure > 1 ? 's' : ' ',
241                         failed,
242                   total);
243                 break;
244         case ADVISORY:
245                 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
246                         advisory,
247                         advisory > 1 ? "ies" : "y",
248                         failed,
249                         total);
250                 break;
251         case OPERATIONAL:
252                 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
253                 break;
254         default:
255                 printf (_("ERROR - Status '%d' uknown. %d/%d tests passed\n"), status,
256                                                 passed, total);
257                 status = -1;
258                 break;
259         }
260         return status;
265 void
266 print_value (value_t * p, threshold_t * t) 
268         printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
269                                         p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory   ",
270                                         p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
271                                         p->value > t->threshold ? "Passed" : "Failed");
276 void
277 print_values (values_t * p, thresholds_t * t) 
279         value_t * value = p->values;
280         threshold_t * threshold = t->thresholds;
281         int i;
282         for (i = 0; i < NR_ATTRIBUTES; i++) {
283                 if (value->id && threshold->id && value->id == threshold->id) {
284                         print_value (value++, threshold++);
285                 }
286         }
287         printf
288                 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
289                  p->offline_status,
290                  get_offline_text (p->offline_status & 0x7f),
291                  (p->offline_status & 0x80 ? "Yes" : "No"),
292                  p->offline_timeout / 60);
293         printf
294                 (_("OffLineCapability=%d {%s %s %s}\n"),
295                  p->offline_capability,
296                  p->offline_capability & 1 ? "Immediate" : "",
297                  p->offline_capability & 2 ? "Auto" : "",
298                  p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
299         printf
300                 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
301                  p->revision,
302                  p->checksum,
303                  p->smart_capability,
304                  p->smart_capability & 1 ? "SaveOnStandBy" : "",
305                  p->smart_capability & 2 ? "AutoSave" : "");
310 void
311 print_thresholds (thresholds_t * p) 
313         threshold_t * threshold = p->thresholds;
314         int i;
315         printf ("\n");
316         printf ("SmartRevision=%d\n", p->revision);
317         for (i = 0; i < NR_ATTRIBUTES; i++) {
318                 if (threshold->id) {
319                         printf ("Id=%3d, Threshold=%3d\n", threshold->id,
320                                                         threshold->threshold); }
321                 ++threshold;
322         }
323         printf ("CheckSum=%d\n", p->checksum);
326 int
327 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0,
328                                                                         char show_error) 
330         int e = 0;
331         __u8 args[4];
332         args[0] = WIN_SMART;
333         args[1] = val0;
334         args[2] = smart_command[command].value;
335         args[3] = 0;
336         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
337                 e = errno;
338                 if (show_error) {
339                         printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
340                 }
341         }
342         return e;
347 int
348 smart_read_thresholds (int fd, thresholds_t * thresholds) 
350         int e;
351         __u8 args[4 + 512];
352         args[0] = WIN_SMART;
353   args[1] = 0;
354   args[2] = SMART_READ_THRESHOLDS;
355   args[3] = 1;
356         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
357                 e = errno;
358                 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
359                 return e;
360         }
361         memcpy (thresholds, args + 4, 512);
362         return 0;
367 void
368 show_version () 
370         printf ("check_ide-smart v.1 - FREE Software with NO WARRANTY\n");
371         printf ("Nagios feature - Robert Dale <rdale@digital-mission.com>\n");
372         printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
377 void
378 show_help () 
380         printf (_("\
381 Usage: check_ide-smart [DEVICE] [OPTION]\n\
382  -d, --device=DEVICE\n\
383     Select device DEVICE\n\
384  -i, --immediate\n\
385     Perform immediately offline tests\n\
386  -q, --quiet-check\n\
387     Returns the number of failed tests\n\
388  -1, --auto-on\n\
389     Turn on automatic offline tests\n\
390  -0, --auto-off\n\
391     Turn off automatic offline tests\n\
392  -n, --net-saint\n\
393     Output suitable for Net Saint\n\
394  -h, --help\n\
395  -V, --version\n"));
400 int
401 main (int argc, char *argv[]) 
403         char *device = NULL;
404         int command = -1;
405         int o, longindex;
406         int retval = 0;
408         thresholds_t thresholds;
409         values_t values;
410         int fd;
412         static struct option longopts[] = { 
413                 {"device", required_argument, 0, 'd'}, 
414                 {"immediate", no_argument, 0, 'i'}, 
415                 {"quiet-check", no_argument, 0, 'q'}, 
416                 {"auto-on", no_argument, 0, '1'}, 
417                 {"auto-off", no_argument, 0, '0'}, 
418                 {"net-saint", no_argument, 0, 'n'}, 
419                 {"help", no_argument, 0, 'h'}, 
420                 {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} 
421         };
423         setlocale (LC_ALL, "");
424         bindtextdomain (PACKAGE, LOCALEDIR);
425         textdomain (PACKAGE);
427         while (1) {
428                 
429                 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
430                 
431                 if (o == -1 || o == EOF)
432                         break;
434                 switch (o) {
435                 case 'd':
436                         device = optarg;
437                         break;
438                 case 'q':
439                         command = 3;
440                         break;
441                 case 'i':
442                         command = 2;
443                         break;
444                 case '1':
445                         command = 1;
446                         break;
447                 case '0':
448                         command = 0;
449                         break;
450                 case 'n':
451                         command = 4;
452                         break;
453                 case 'h':
454                         show_help ();
455                         return 0;
456                 case 'V':
457                         show_version ();
458                         return 0;
459                 default:
460                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
461                         print_usage ();
462                         exit (STATE_UNKNOWN);
463                 }
465                 if (optind < argc) {
466                         device = argv[optind];
467                 }
469                 if (!device) {
470                         show_help ();
471                         show_version ();
472                         return -1;
473                 }
475                 fd = open (device, O_RDONLY);
477                 if (fd < 0) {
478                         printf (_("CRITICAL - Couldn't open device: %s\n"), strerror (errno));
479                         return 2;
480                 }
482                 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
483                         printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
484                         return 2;
485                 }
487                 switch (command) {
488                 case 0:
489                         retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
490                         break;
491                 case 1:
492                         retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
493                         break;
494                 case 2:
495                         retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
496                         break;
497                 case 3:
498                         smart_read_values (fd, &values);
499                         smart_read_thresholds (fd, &thresholds);
500                         retval = values_not_passed (&values, &thresholds);
501                         break;
502                 case 4:
503                         smart_read_values (fd, &values);
504                         smart_read_thresholds (fd, &thresholds);
505                         retval = net_saint (&values, &thresholds);
506                         break;
507                 default:
508                         smart_read_values (fd, &values);
509                         smart_read_thresholds (fd, &thresholds);
510                         print_values (&values, &thresholds);
511                         break;
512                 }
513                 close (fd);
514         }
515         return retval;