Code

Fixed tests (Mathew Ericson - 738604)
[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. cheking 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 <stdio.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <fcntl.h>
43 #include <string.h>
44 #include <unistd.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
59         typedef struct threshold_s
60 {
61         __u8 id;
62         __u8 threshold;
63         __u8 reserved[10];
64 }
65 __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;
75 typedef struct value_s
76 {
77         __u8 id;
78         __u16 status;
79         __u8 value;
80         __u8 vendor[8];
81 }
82 __attribute__ ((packed)) value_t;
83 typedef struct values_s
84 {
85         __u16 revision;
86         value_t values[NR_ATTRIBUTES];
87         __u8 offline_status;
88         __u8 vendor1;
89         __u16 offline_timeout;
90         __u8 vendor2;
91         __u8 offline_capability;
92         __u16 smart_capability;
93         __u8 reserved[16];
94         __u8 vendor[125];
95         __u8 checksum;
96 }
97 __attribute__ ((packed)) values_t;
98 struct
99 {
100         __u8 value;
101         char *text;
102  }
103 offline_status_text[] =
105          {
106         0x00, "NeverStarted"}
107         ,  {
108         0x02, "Completed"}
109         ,  {
110         0x04, "Suspended"}
111         ,  {
112         0x05, "Aborted"}
113         ,  {
114         0x06, "Failed"}
115         ,  {
116         0, 0}
117 };
118 struct
120         __u8 value;
121         char *text;
122  }
123 smart_command[] =
125          {
126         SMART_ENABLE, "SMART_ENABLE"}
127         ,  {
128         SMART_DISABLE, "SMART_DISABLE"}
129         ,  {
130         SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"}
131         ,  {
132         SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
133 , };
136 /* Index to smart_command table, keep in order */ 
137 enum SmartCommand 
138 { SMART_CMD_ENABLE, SMART_CMD_DISABLE, SMART_CMD_IMMEDIATE_OFFLINE,
139                 SMART_CMD_AUTO_OFFLINE 
140 };
141 char *
142 get_offline_text (int status) 
144         int i;
145         for (i = 0; offline_status_text[i].text; i++) {
146                 if (offline_status_text[i].value == status) {
147                         return offline_status_text[i].text;
148                 }
149         }
150         return "unknown";
152 int
153 smart_read_values (int fd, values_t * values) 
155         __u8 args[4 + 512] = {
156         WIN_SMART, 0, SMART_READ_VALUES, 1,};
157         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
158                 int e = errno;
159                 printf ("Critical: SMART_READ_VALUES: %s\n", strerror (errno));
160                 return e;
161         }
162         memcpy (values, args + 4, 512);
163         return 0;
165 int
166 values_not_passed (values_t * p, thresholds_t * t) 
168         value_t * value = p->values;
169         threshold_t * threshold = t->thresholds;
170         int failed = 0;
171         int passed = 0;
172         int i;
173         for (i = 0; i < NR_ATTRIBUTES; i++) {
174                 if (value->id && threshold->id && value->id == threshold->id) {
175                         if (value->value <= threshold->threshold) {
176                                 ++failed;
177                         }
178                         else {
179                                 ++passed;
180                         }
181                 }
182                 ++value;
183                 ++threshold;
184         }
185         return (passed ? -failed : 2);
187 int
188 net_saint (values_t * p, thresholds_t * t) 
190         value_t * value = p->values;
191         threshold_t * threshold = t->thresholds;
192         int status = OPERATIONAL;
193         int prefailure = 0;
194         int advisory = 0;
195         int failed = 0;
196         int passed = 0;
197         int total = 0;
198         int i;
199         for (i = 0; i < NR_ATTRIBUTES; i++) {
200                 if (value->id && threshold->id && value->id == threshold->id) {
201                         if (value->value <= threshold->threshold) {
202                                 ++failed;
203                                 if (value->status & 1) {
204                                         status = PREFAILURE;
205                                         ++prefailure;
206                                 }
207                                 else {
208                                         status = ADVISORY;
209                                         ++advisory;
210                                 }
211                         }
212                         else {
213                                 ++passed;
214                         }
215                         ++total;
216                 }
217                 ++value;
218                 ++threshold;
219         }
220         switch (status) {
221         case PREFAILURE:
222                 printf ("Critical: %d Harddrive PreFailure%cDetected! " 
223                                                  "%d/%d tests failed.\n", prefailure, prefailure > 1 ? 's' : ' ',
224                                                  failed, total);
225                 break;
226         case ADVISORY:
227                 printf ("Warning: %d Harddrive Advisor%s Detected. " 
228                                                  "%d/%d tests failed.\n", advisory, advisory > 1 ? "ies" : "y",
229                                                  failed, total);
230                 break;
231         case OPERATIONAL:
232                 printf ("Status: Operational (%d/%d tests passed)\n", passed, total);
233                 break;
234         default:
235                 printf ("Error: Status '%d' uknown. %d/%d tests passed\n", status,
236                                                  passed, total);
237                 status = -1;
238                 break;
239         }
240         return status;
242 void
243 print_value (value_t * p, threshold_t * t) 
245         printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
246                                          p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory   ",
247                                          p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
248                                          p->value > t->threshold ? "Passed" : "Failed");
250 void
251 print_values (values_t * p, thresholds_t * t) 
253         value_t * value = p->values;
254         threshold_t * threshold = t->thresholds;
255         int i;
256         for (i = 0; i < NR_ATTRIBUTES; i++) {
257                 if (value->id && threshold->id && value->id == threshold->id) {
258                         print_value (value++, threshold++);
259                 }
260         }
261         printf
262                 ("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n",
263                  p->offline_status, get_offline_text (p->offline_status & 0x7f),
264                  (p->offline_status & 0x80 ? "Yes" : "No"), p->offline_timeout / 60);
265         printf ("OffLineCapability=%d {%s %s %s}\n", p->offline_capability,
266                                          p->offline_capability & 1 ? "Immediate" : "",
267                                          p->offline_capability & 2 ? "Auto" : "",
268                                          p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
269         printf ("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n",
270                                          p->revision, p->checksum, p->smart_capability,
271                                          p->smart_capability & 1 ? "SaveOnStandBy" : "",
272                                          p->smart_capability & 2 ? "AutoSave" : "");
274 void
275 print_thresholds (thresholds_t * p) 
277         threshold_t * threshold = p->thresholds;
278         int i;
279         printf ("\n");
280         printf ("SmartRevision=%d\n", p->revision);
281         for (i = 0; i < NR_ATTRIBUTES; i++) {
282                 if (threshold->id) {
283                         printf ("Id=%3d, Threshold=%3d\n", threshold->id,
284                                                          threshold->threshold); }
285                 ++threshold;
286         }
287         printf ("CheckSum=%d\n", p->checksum);
289 int
290 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0,
291                                                                         char show_error) 
293         __u8 args[4] = {
294         WIN_SMART, val0, smart_command[command].value, 0};
295         int e = 0;
296         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
297                 e = errno;
298                 if (show_error) {
299                         printf ("Critical: %s: %s\n", smart_command[command].text,
300                                                          strerror (errno)); }
301         }
302         return e;
304 int
305 smart_read_thresholds (int fd, thresholds_t * thresholds) 
307         __u8 args[4 + 512] = {
308         WIN_SMART, 0, SMART_READ_THRESHOLDS, 1,};
309         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
310                 int e = errno;
311                 printf ("Critical: SMART_READ_THRESHOLDS: %s\n", strerror (errno));
312                 return e;
313         }
314         memcpy (thresholds, args + 4, 512);
315         return 0;
317 void
318 show_version () 
320         printf ("check_ide-smart v.1 - FREE Software with NO WARRANTY\n");
321         printf ("Nagios feature - Robert Dale <rdale@digital-mission.com>\n");
322         printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
324 void
325 show_help () 
327         printf ("Usage: check_ide-smart [DEVICE] [OPTION]\n" 
328                                          "         -d, --device=DEVICE  Select device DEVICE\n" 
329                                          "         -i, --immediate      Perform immediately offline tests\n" 
330                                          "         -q, --quiet-check    Returns the number of failed tests\n" 
331                                          "         -1, --auto-on        Turn on automatic offline tests\n" 
332                                          "         -0, --auto-off       Turn off automatic offline tests\n" 
333                                          "         -n, --net-saint      Output suitable for Net Saint\n" 
334                                          "         -h, --help\n"  "        -V, --version\n");
336 int
337 main (int argc, char *argv[]) 
339         char *device = NULL;
340         int command = -1;
341         int o, longindex;
342         int retval = 0;
343         
344         const struct option longopts[] = { 
345                         {"device", required_argument, 0, 'd'}, 
346                 {"immediate", no_argument, 0, 'i'}, 
347                 {"quiet-check", no_argument, 0, 'q'}, 
348                 {"auto-on", no_argument, 0, '1'}, 
349                 {"auto-off", no_argument, 0, '0'}, 
350                 {"net-saint", no_argument, 0, 'n'}, 
351                 {"help", no_argument, 0, 'h'}, 
352                 {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} 
353         };
354         
355                 while (1) {
356                 
357                         o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
358                 
359                         if (o == -1 || o == EOF)
360                         break;
361                 switch (o) {
362                 case 'd':
363                         device = optarg;
364                         break;
365                 case 'q':
366                         command = 3;
367                         break;
368                 case 'i':
369                         command = 2;
370                         break;
371                 case '1':
372                         command = 1;
373                         break;
374                 case '0':
375                         command = 0;
376                         break;
377                 case 'n':
378                         command = 4;
379                         break;
380                 case 'h':
381                         show_help ();
382                         return 0;
383                 case 'V':
384                         show_version ();
385                         return 0;
386                 default:
387                         printf ("Try `%s --help' for more information.\n", argv[0]);
388                         return 1;
389                 }
390                 if (optind < argc) {
391                         device = argv[optind];
392                 }
393                 if (!device) {
394                         show_help ();
395                         show_version ();
396                         return -1;
397                 }
398                 if (1) {
399                         thresholds_t thresholds;
400                         values_t values;
401                         int fd = open (device, O_RDONLY);
402                         if (fd < 0) {
403                                 printf ("Critical: Couldn't open device: %s\n", strerror (errno));
404                                 return 2;
405                         }
406                         if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
407                                 printf ("Critical: SMART_CMD_ENABLE\n");
408                                 return 2;
409                         }
410                         switch (command) {
411                         case 0:
412                                 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
413                                 break;
414                         case 1:
415                                 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
416                                 break;
417                         case 2:
418                                 retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
419                                 break;
420                         case 3:
421                                 smart_read_values (fd, &values);
422                                 smart_read_thresholds (fd, &thresholds);
423                                 retval = values_not_passed (&values, &thresholds);
424                                 break;
425                         case 4:
426                                 smart_read_values (fd, &values);
427                                 smart_read_thresholds (fd, &thresholds);
428                                 retval = net_saint (&values, &thresholds);
429                                 break;
430                         default:
431                                 smart_read_values (fd, &values);
432                                 smart_read_thresholds (fd, &thresholds);
433                                 print_values (&values, &thresholds);
434                                 break;
435                         }
436                         close (fd);
437                 }
438                 return retval;
439         }
440