Code

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