Code

644dc4881c0c48d0b363fb9e7ff27ea06f890585
[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  */
40 const char *progname = "check_ide_smart";
41 const char *revision = "$Revision$";
42 const char *copyright = "2000-2004";
43 const char *email = "nagiosplug-devel@lists.sourceforge.net";
44         
45 #include "common.h"
46 #include "utils.h"
48 #include <sys/stat.h>
49 #include <sys/ioctl.h>
50 #include <fcntl.h>
51 #include <linux/hdreg.h>
52 #include <linux/types.h>
53 #include <errno.h>
54         
55 #define NR_ATTRIBUTES   30
56         
57 #ifndef TRUE
58 #define TRUE 1
59 #endif  /*  */
60         
61 #define PREFAILURE 2
62 #define ADVISORY 1
63 #define OPERATIONAL 0
64 #define UNKNOWN -1
66 typedef struct threshold_s
67 {
68         __u8 id;
69         __u8 threshold;
70         __u8 reserved[10];
71 }
72 __attribute__ ((packed)) threshold_t;
74 typedef struct thresholds_s
75 {
76         __u16 revision;
77         threshold_t thresholds[NR_ATTRIBUTES];
78         __u8 reserved[18];
79         __u8 vendor[131];
80         __u8 checksum;
81 }
82 __attribute__ ((packed)) thresholds_t;
84 typedef struct value_s
85 {
86         __u8 id;
87         __u16 status;
88         __u8 value;
89         __u8 vendor[8];
90 }
91 __attribute__ ((packed)) value_t;
93 typedef struct values_s
94 {
95         __u16 revision;
96         value_t values[NR_ATTRIBUTES];
97         __u8 offline_status;
98         __u8 vendor1;
99         __u16 offline_timeout;
100         __u8 vendor2;
101         __u8 offline_capability;
102         __u16 smart_capability;
103         __u8 reserved[16];
104         __u8 vendor[125];
105         __u8 checksum;
107 __attribute__ ((packed)) values_t;
109 struct
111         __u8 value;
112         char *text;
115 offline_status_text[] =
116         {
117                 {0x00, "NeverStarted"},
118                 {0x02, "Completed"},
119                 {0x04, "Suspended"},
120                 {0x05, "Aborted"},
121                 {0x06, "Failed"},
122                 {0, 0}
123         };
125 struct
127         __u8 value;
128         char *text;
131 smart_command[] =
132         {
133                 {SMART_ENABLE, "SMART_ENABLE"},
134                 {SMART_DISABLE, "SMART_DISABLE"},
135                 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
136                 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
137         };
140 /* Index to smart_command table, keep in order */ 
141 enum SmartCommand 
142         { SMART_CMD_ENABLE,
143                 SMART_CMD_DISABLE,
144                 SMART_CMD_IMMEDIATE_OFFLINE,
145                 SMART_CMD_AUTO_OFFLINE 
146         };
149 int
150 main (int argc, char *argv[]) 
152         char *device = NULL;
153         int command = -1;
154         int o, longindex;
155         int retval = 0;
157         thresholds_t thresholds;
158         values_t values;
159         int fd;
161         static struct option longopts[] = { 
162                 {"device", required_argument, 0, 'd'}, 
163                 {"immediate", no_argument, 0, 'i'}, 
164                 {"quiet-check", no_argument, 0, 'q'}, 
165                 {"auto-on", no_argument, 0, '1'}, 
166                 {"auto-off", no_argument, 0, '0'}, 
167                 {"net-saint", no_argument, 0, 'n'}, 
168                 {"help", no_argument, 0, 'h'}, 
169                 {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} 
170         };
172         setlocale (LC_ALL, "");
173         bindtextdomain (PACKAGE, LOCALEDIR);
174         textdomain (PACKAGE);
176         while (1) {
177                 
178                 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
179                 
180                 if (o == -1 || o == EOF)
181                         break;
183                 switch (o) {
184                 case 'd':
185                         device = optarg;
186                         break;
187                 case 'q':
188                         command = 3;
189                         break;
190                 case 'i':
191                         command = 2;
192                         break;
193                 case '1':
194                         command = 1;
195                         break;
196                 case '0':
197                         command = 0;
198                         break;
199                 case 'n':
200                         command = 4;
201                         break;
202                 case 'h':
203                         print_help ();
204                         return STATE_OK;
205                 case 'V':
206                         print_revision (progname, revision);
207                         return STATE_OK;
208                 default:
209                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
210                         print_usage ();
211                         exit (STATE_UNKNOWN);
212                 }
214                 if (optind < argc) {
215                         device = argv[optind];
216                 }
218                 if (!device) {
219                         show_help ();
220                         show_version ();
221                         return -1;
222                 }
224                 fd = open (device, O_RDONLY);
226                 if (fd < 0) {
227                         printf (_("CRITICAL - Couldn't open device: %s\n"), strerror (errno));
228                         return 2;
229                 }
231                 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
232                         printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
233                         return 2;
234                 }
236                 switch (command) {
237                 case 0:
238                         retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
239                         break;
240                 case 1:
241                         retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
242                         break;
243                 case 2:
244                         retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
245                         break;
246                 case 3:
247                         smart_read_values (fd, &values);
248                         smart_read_thresholds (fd, &thresholds);
249                         retval = values_not_passed (&values, &thresholds);
250                         break;
251                 case 4:
252                         smart_read_values (fd, &values);
253                         smart_read_thresholds (fd, &thresholds);
254                         retval = net_saint (&values, &thresholds);
255                         break;
256                 default:
257                         smart_read_values (fd, &values);
258                         smart_read_thresholds (fd, &thresholds);
259                         print_values (&values, &thresholds);
260                         break;
261                 }
262                 close (fd);
263         }
264         return retval;
269 char *
270 get_offline_text (int status) 
272         int i;
273         for (i = 0; offline_status_text[i].text; i++) {
274                 if (offline_status_text[i].value == status) {
275                         return offline_status_text[i].text;
276                 }
277         }
278         return "UNKNOW";
283 int
284 smart_read_values (int fd, values_t * values) 
286         int e;
287         __u8 args[4 + 512];
288         args[0] = WIN_SMART;
289         args[1] = 0;
290         args[2] = SMART_READ_VALUES;
291         args[3] = 1;
292         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
293                 e = errno;
294                 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
295                 return e;
296         }
297         memcpy (values, args + 4, 512);
298         return 0;
303 int
304 values_not_passed (values_t * p, thresholds_t * t) 
306         value_t * value = p->values;
307         threshold_t * threshold = t->thresholds;
308         int failed = 0;
309         int passed = 0;
310         int i;
311         for (i = 0; i < NR_ATTRIBUTES; i++) {
312                 if (value->id && threshold->id && value->id == threshold->id) {
313                         if (value->value <= threshold->threshold) {
314                                 ++failed;
315                         }
316                         else {
317                                 ++passed;
318                         }
319                 }
320                 ++value;
321                 ++threshold;
322         }
323         return (passed ? -failed : 2);
328 int
329 net_saint (values_t * p, thresholds_t * t) 
331         value_t * value = p->values;
332         threshold_t * threshold = t->thresholds;
333         int status = OPERATIONAL;
334         int prefailure = 0;
335         int advisory = 0;
336         int failed = 0;
337         int passed = 0;
338         int total = 0;
339         int i;
340         for (i = 0; i < NR_ATTRIBUTES; i++) {
341                 if (value->id && threshold->id && value->id == threshold->id) {
342                         if (value->value <= threshold->threshold) {
343                                 ++failed;
344                                 if (value->status & 1) {
345                                         status = PREFAILURE;
346                                         ++prefailure;
347                                 }
348                                 else {
349                                         status = ADVISORY;
350                                         ++advisory;
351                                 }
352                         }
353                         else {
354                                 ++passed;
355                         }
356                         ++total;
357                 }
358                 ++value;
359                 ++threshold;
360         }
361         switch (status) {
362         case PREFAILURE:
363                 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
364                         prefailure,
365                         prefailure > 1 ? 's' : ' ',
366                         failed,
367                   total);
368                 break;
369         case ADVISORY:
370                 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
371                         advisory,
372                         advisory > 1 ? "ies" : "y",
373                         failed,
374                         total);
375                 break;
376         case OPERATIONAL:
377                 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
378                 break;
379         default:
380                 printf (_("ERROR - Status '%d' uknown. %d/%d tests passed\n"), status,
381                                                 passed, total);
382                 status = -1;
383                 break;
384         }
385         return status;
390 void
391 print_value (value_t * p, threshold_t * t) 
393         printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
394                                         p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory   ",
395                                         p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
396                                         p->value > t->threshold ? "Passed" : "Failed");
401 void
402 print_values (values_t * p, thresholds_t * t) 
404         value_t * value = p->values;
405         threshold_t * threshold = t->thresholds;
406         int i;
407         for (i = 0; i < NR_ATTRIBUTES; i++) {
408                 if (value->id && threshold->id && value->id == threshold->id) {
409                         print_value (value++, threshold++);
410                 }
411         }
412         printf
413                 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
414                  p->offline_status,
415                  get_offline_text (p->offline_status & 0x7f),
416                  (p->offline_status & 0x80 ? "Yes" : "No"),
417                  p->offline_timeout / 60);
418         printf
419                 (_("OffLineCapability=%d {%s %s %s}\n"),
420                  p->offline_capability,
421                  p->offline_capability & 1 ? "Immediate" : "",
422                  p->offline_capability & 2 ? "Auto" : "",
423                  p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
424         printf
425                 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
426                  p->revision,
427                  p->checksum,
428                  p->smart_capability,
429                  p->smart_capability & 1 ? "SaveOnStandBy" : "",
430                  p->smart_capability & 2 ? "AutoSave" : "");
435 void
436 print_thresholds (thresholds_t * p) 
438         threshold_t * threshold = p->thresholds;
439         int i;
440         printf ("\n");
441         printf ("SmartRevision=%d\n", p->revision);
442         for (i = 0; i < NR_ATTRIBUTES; i++) {
443                 if (threshold->id) {
444                         printf ("Id=%3d, Threshold=%3d\n", threshold->id,
445                                                         threshold->threshold); }
446                 ++threshold;
447         }
448         printf ("CheckSum=%d\n", p->checksum);
451 int
452 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0,
453                                                                         char show_error) 
455         int e = 0;
456         __u8 args[4];
457         args[0] = WIN_SMART;
458         args[1] = val0;
459         args[2] = smart_command[command].value;
460         args[3] = 0;
461         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
462                 e = errno;
463                 if (show_error) {
464                         printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
465                 }
466         }
467         return e;
472 int
473 smart_read_thresholds (int fd, thresholds_t * thresholds) 
475         int e;
476         __u8 args[4 + 512];
477         args[0] = WIN_SMART;
478   args[1] = 0;
479   args[2] = SMART_READ_THRESHOLDS;
480   args[3] = 1;
481         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
482                 e = errno;
483                 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
484                 return e;
485         }
486         memcpy (thresholds, args + 4, 512);
487         return 0;
492 void
493 print_help () 
495         print_revision (progname, revision);
497         printf ("Nagios feature - 1999 Robert Dale <rdale@digital-mission.com>\n");
498         printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
499         printf (COPYRIGHT, copyright, email);
500         
501         printf ("\
502 Usage: %s [DEVICE] [OPTION]\n\
503  -d, --device=DEVICE\n\
504     Select device DEVICE\n\
505  -i, --immediate\n\
506     Perform immediately offline tests\n\
507  -q, --quiet-check\n\
508     Returns the number of failed tests\n\
509  -1, --auto-on\n\
510     Turn on automatic offline tests\n\
511  -0, --auto-off\n\
512     Turn off automatic offline tests\n\
513  -n, --net-saint\n\
514     Output suitable for Net Saint\n", progname);
519 void
520 print_usage (void)
522         printf ("Usage: %s \n"), progname);