Code

Command line argument bug (Howard Wilkinson)
[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  *  Net Saint - 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         
38 #include "common.h"
39 #include "utils.h"
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <fcntl.h>
43 #include <linux/hdreg.h>
44 #include <linux/types.h>
45 #include <errno.h>
46         
47 #define NR_ATTRIBUTES   30
48         
49 #ifndef TRUE
50 #define TRUE 1
51 #endif  /*  */
52         
53 #define PREFAILURE 2
54 #define ADVISORY 1
55 #define OPERATIONAL 0
56 #define UNKNOWN -1
58 typedef struct threshold_s
59 {
60         __u8 id;
61         __u8 threshold;
62         __u8 reserved[10];
63 }
64 __attribute__ ((packed)) threshold_t;
66 typedef struct thresholds_s
67 {
68         __u16 revision;
69         threshold_t thresholds[NR_ATTRIBUTES];
70         __u8 reserved[18];
71         __u8 vendor[131];
72         __u8 checksum;
73 }
74 __attribute__ ((packed)) thresholds_t;
76 typedef struct value_s
77 {
78         __u8 id;
79         __u16 status;
80         __u8 value;
81         __u8 vendor[8];
82 }
83 __attribute__ ((packed)) value_t;
85 typedef struct values_s
86 {
87         __u16 revision;
88         value_t values[NR_ATTRIBUTES];
89         __u8 offline_status;
90         __u8 vendor1;
91         __u16 offline_timeout;
92         __u8 vendor2;
93         __u8 offline_capability;
94         __u16 smart_capability;
95         __u8 reserved[16];
96         __u8 vendor[125];
97         __u8 checksum;
98 }
99 __attribute__ ((packed)) values_t;
101 struct
103         __u8 value;
104         char *text;
107 offline_status_text[] =
108         {
109                 {0x00, "NeverStarted"},
110                 {0x02, "Completed"},
111                 {0x04, "Suspended"},
112                 {0x05, "Aborted"},
113                 {0x06, "Failed"},
114                 {0, 0}
115         };
117 struct
119         __u8 value;
120         char *text;
123 smart_command[] =
124         {
125                 {SMART_ENABLE, "SMART_ENABLE"},
126                 {SMART_DISABLE, "SMART_DISABLE"},
127                 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
128                 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
129         };
132 /* Index to smart_command table, keep in order */ 
133 enum SmartCommand 
134         { SMART_CMD_ENABLE,
135                 SMART_CMD_DISABLE,
136                 SMART_CMD_IMMEDIATE_OFFLINE,
137                 SMART_CMD_AUTO_OFFLINE 
138         };
140 char *
141 get_offline_text (int status) 
143         int i;
144         for (i = 0; offline_status_text[i].text; i++) {
145                 if (offline_status_text[i].value == status) {
146                         return offline_status_text[i].text;
147                 }
148         }
149         return "unknown";
152 int
153 smart_read_values (int fd, values_t * values) 
155         int e;
156         __u8 args[4 + 512];
157         args[0] = WIN_SMART;
158         args[1] = 0;
159         args[2] = SMART_READ_VALUES;
160         args[3] = 1;
161         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
162                 e = errno;
163                 printf (_("Critical: SMART_READ_VALUES: %s\n"), strerror (errno));
164                 return e;
165         }
166         memcpy (values, args + 4, 512);
167         return 0;
170 int
171 values_not_passed (values_t * p, thresholds_t * t) 
173         value_t * value = p->values;
174         threshold_t * threshold = t->thresholds;
175         int failed = 0;
176         int passed = 0;
177         int i;
178         for (i = 0; i < NR_ATTRIBUTES; i++) {
179                 if (value->id && threshold->id && value->id == threshold->id) {
180                         if (value->value <= threshold->threshold) {
181                                 ++failed;
182                         }
183                         else {
184                                 ++passed;
185                         }
186                 }
187                 ++value;
188                 ++threshold;
189         }
190         return (passed ? -failed : 2);
193 int
194 net_saint (values_t * p, thresholds_t * t) 
196         value_t * value = p->values;
197         threshold_t * threshold = t->thresholds;
198         int status = OPERATIONAL;
199         int prefailure = 0;
200         int advisory = 0;
201         int failed = 0;
202         int passed = 0;
203         int total = 0;
204         int i;
205         for (i = 0; i < NR_ATTRIBUTES; i++) {
206                 if (value->id && threshold->id && value->id == threshold->id) {
207                         if (value->value <= threshold->threshold) {
208                                 ++failed;
209                                 if (value->status & 1) {
210                                         status = PREFAILURE;
211                                         ++prefailure;
212                                 }
213                                 else {
214                                         status = ADVISORY;
215                                         ++advisory;
216                                 }
217                         }
218                         else {
219                                 ++passed;
220                         }
221                         ++total;
222                 }
223                 ++value;
224                 ++threshold;
225         }
226         switch (status) {
227         case PREFAILURE:
228                 printf (_("Critical: %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
229                         prefailure,
230                         prefailure > 1 ? 's' : ' ',
231                         failed,
232                   total);
233                 break;
234         case ADVISORY:
235                 printf (_("Warning: %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
236                         advisory,
237                         advisory > 1 ? "ies" : "y",
238                         failed,
239                         total);
240                 break;
241         case OPERATIONAL:
242                 printf (_("Status: Operational (%d/%d tests passed)\n"), passed, total);
243                 break;
244         default:
245                 printf (_("Error: Status '%d' uknown. %d/%d tests passed\n"), status,
246                                                 passed, total);
247                 status = -1;
248                 break;
249         }
250         return status;
253 void
254 print_value (value_t * p, threshold_t * t) 
256         printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
257                                         p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory   ",
258                                         p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
259                                         p->value > t->threshold ? "Passed" : "Failed");
262 void
263 print_values (values_t * p, thresholds_t * t) 
265         value_t * value = p->values;
266         threshold_t * threshold = t->thresholds;
267         int i;
268         for (i = 0; i < NR_ATTRIBUTES; i++) {
269                 if (value->id && threshold->id && value->id == threshold->id) {
270                         print_value (value++, threshold++);
271                 }
272         }
273         printf
274                 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
275                  p->offline_status,
276                  get_offline_text (p->offline_status & 0x7f),
277                  (p->offline_status & 0x80 ? "Yes" : "No"),
278                  p->offline_timeout / 60);
279         printf
280                 (_("OffLineCapability=%d {%s %s %s}\n"),
281                  p->offline_capability,
282                  p->offline_capability & 1 ? "Immediate" : "",
283                  p->offline_capability & 2 ? "Auto" : "",
284                  p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
285         printf
286                 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
287                  p->revision,
288                  p->checksum,
289                  p->smart_capability,
290                  p->smart_capability & 1 ? "SaveOnStandBy" : "",
291                  p->smart_capability & 2 ? "AutoSave" : "");
294 void
295 print_thresholds (thresholds_t * p) 
297         threshold_t * threshold = p->thresholds;
298         int i;
299         printf ("\n");
300         printf ("SmartRevision=%d\n", p->revision);
301         for (i = 0; i < NR_ATTRIBUTES; i++) {
302                 if (threshold->id) {
303                         printf ("Id=%3d, Threshold=%3d\n", threshold->id,
304                                                         threshold->threshold); }
305                 ++threshold;
306         }
307         printf ("CheckSum=%d\n", p->checksum);
310 int
311 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0,
312                                                                         char show_error) 
314         int e = 0;
315         __u8 args[4];
316         args[0] = WIN_SMART;
317         args[1] = val0;
318         args[2] = smart_command[command].value;
319         args[3] = 0;
320         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
321                 e = errno;
322                 if (show_error) {
323                         printf (_("Critical: %s: %s\n"), smart_command[command].text, strerror (errno));
324                 }
325         }
326         return e;
329 int
330 smart_read_thresholds (int fd, thresholds_t * thresholds) 
332         int e;
333         __u8 args[4 + 512];
334         args[0] = WIN_SMART;
335   args[1] = 0;
336   args[2] = SMART_READ_THRESHOLDS;
337   args[3] = 1;
338         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
339                 e = errno;
340                 printf (_("Critical: SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
341                 return e;
342         }
343         memcpy (thresholds, args + 4, 512);
344         return 0;
347 void
348 show_version () 
350         printf ("check_ide-smart v.1 - FREE Software with NO WARRANTY\n");
351         printf ("Nagios feature - Robert Dale <rdale@digital-mission.com>\n");
352         printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
355 void
356 show_help () 
358         printf (_("\
359 Usage: check_ide-smart [DEVICE] [OPTION]\n\
360  -d, --device=DEVICE\n\
361     Select device DEVICE\n\
362  -i, --immediate\n\
363     Perform immediately offline tests\n\
364  -q, --quiet-check\n\
365     Returns the number of failed tests\n\
366  -1, --auto-on\n\
367     Turn on automatic offline tests\n\
368  -0, --auto-off\n\
369     Turn off automatic offline tests\n\
370  -n, --net-saint\n\
371     Output suitable for Net Saint\n\
372  -h, --help\n\
373  -V, --version\n"));
376 int
377 main (int argc, char *argv[]) 
379         char *device = NULL;
380         int command = -1;
381         int o, longindex;
382         int retval = 0;
384         thresholds_t thresholds;
385         values_t values;
386         int fd;
388         static struct option longopts[] = { 
389                 {"device", required_argument, 0, 'd'}, 
390                 {"immediate", no_argument, 0, 'i'}, 
391                 {"quiet-check", no_argument, 0, 'q'}, 
392                 {"auto-on", no_argument, 0, '1'}, 
393                 {"auto-off", no_argument, 0, '0'}, 
394                 {"net-saint", no_argument, 0, 'n'}, 
395                 {"help", no_argument, 0, 'h'}, 
396                 {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} 
397         };
399         setlocale (LC_ALL, "");
400         bindtextdomain (PACKAGE, LOCALEDIR);
401         textdomain (PACKAGE);
403         while (1) {
404                 
405                 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
406                 
407                 if (o == -1 || o == EOF)
408                         break;
410                 switch (o) {
411                 case 'd':
412                         device = optarg;
413                         break;
414                 case 'q':
415                         command = 3;
416                         break;
417                 case 'i':
418                         command = 2;
419                         break;
420                 case '1':
421                         command = 1;
422                         break;
423                 case '0':
424                         command = 0;
425                         break;
426                 case 'n':
427                         command = 4;
428                         break;
429                 case 'h':
430                         show_help ();
431                         return 0;
432                 case 'V':
433                         show_version ();
434                         return 0;
435                 default:
436                         printf (_("Try `%s --help' for more information.\n"), argv[0]);
437                         return 1;
438                 }
440                 if (optind < argc) {
441                         device = argv[optind];
442                 }
444                 if (!device) {
445                         show_help ();
446                         show_version ();
447                         return -1;
448                 }
450                 fd = open (device, O_RDONLY);
452                 if (fd < 0) {
453                         printf (_("Critical: Couldn't open device: %s\n"), strerror (errno));
454                         return 2;
455                 }
457                 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
458                         printf (_("Critical: SMART_CMD_ENABLE\n"));
459                         return 2;
460                 }
462                 switch (command) {
463                 case 0:
464                         retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
465                         break;
466                 case 1:
467                         retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
468                         break;
469                 case 2:
470                         retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
471                         break;
472                 case 3:
473                         smart_read_values (fd, &values);
474                         smart_read_thresholds (fd, &thresholds);
475                         retval = values_not_passed (&values, &thresholds);
476                         break;
477                 case 4:
478                         smart_read_values (fd, &values);
479                         smart_read_thresholds (fd, &thresholds);
480                         retval = net_saint (&values, &thresholds);
481                         break;
482                 default:
483                         smart_read_values (fd, &values);
484                         smart_read_thresholds (fd, &thresholds);
485                         print_values (&values, &thresholds);
486                         break;
487                 }
488                 close (fd);
489         }
490         return retval;
492