Code

The "--serverip" and "--requestedip" options now accept host names, too.
[nagiosplug.git] / plugins / check_ide_smart.c
1 /******************************************************************************
2 * Nagios check_ide_smart plugin
3 *
4 * License: GPL
5 *
6 *  ide-smart 1.3 - IDE S.M.A.R.T. checking tool
7 *  Copyright (C)  1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
8 *                 1998      Gadi Oxman <gadio@netvision.net.il>
9
10 * Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
11 * Copyright (c) 2000-2006 nagios-plugins team
12 *
13 * Last Modified: $Date$
14 *
15 * Description:
16 *
17 * This file contains the check_ide_smart plugin
18 *
19 *  This plugin checks a local hard drive with the (Linux specific) SMART interface
20 *
21 *
22 * License Information:
23 *
24 * This program is free software; you can redistribute it and/or modify
25 * it under the terms of the GNU General Public License as published by
26 * the Free Software Foundation; either version 2 of the License, or
27 * (at your option) any later version.
28 *
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32 * GNU General Public License for more details.
33 *
34 * You should have received a copy of the GNU General Public License
35 * along with this program; if not, write to the Free Software
36 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
37  *
38  * $Id$
39  */
41 const char *progname = "check_ide_smart";
42 const char *revision = "$Revision$";
43 const char *copyright = "2000-2006";
44 const char *email = "nagiosplug-devel@lists.sourceforge.net";
45         
46 #include "common.h"
47 #include "utils.h"
49 void print_help (void);
50 void print_usage (void);
52 #include <sys/stat.h>
53 #include <sys/ioctl.h>
54 #include <fcntl.h>
55 #include <linux/hdreg.h>
56 #include <linux/types.h>
57 #include <errno.h>
58         
59 #define NR_ATTRIBUTES   30
60         
61 #ifndef TRUE
62 #define TRUE 1
63 #endif  /*  */
64         
65 #define PREFAILURE 2
66 #define ADVISORY 1
67 #define OPERATIONAL 0
68 #define UNKNOWN -1
70 typedef struct threshold_s
71 {
72         __u8 id;
73         __u8 threshold;
74         __u8 reserved[10];
75 }
76 __attribute__ ((packed)) threshold_t;
78 typedef struct thresholds_s
79 {
80         __u16 revision;
81         threshold_t thresholds[NR_ATTRIBUTES];
82         __u8 reserved[18];
83         __u8 vendor[131];
84         __u8 checksum;
85 }
86 __attribute__ ((packed)) thresholds_t;
88 typedef struct value_s
89 {
90         __u8 id;
91         __u16 status;
92         __u8 value;
93         __u8 vendor[8];
94 }
95 __attribute__ ((packed)) value_t;
97 typedef struct values_s
98 {
99         __u16 revision;
100         value_t values[NR_ATTRIBUTES];
101         __u8 offline_status;
102         __u8 vendor1;
103         __u16 offline_timeout;
104         __u8 vendor2;
105         __u8 offline_capability;
106         __u16 smart_capability;
107         __u8 reserved[16];
108         __u8 vendor[125];
109         __u8 checksum;
111 __attribute__ ((packed)) values_t;
113 struct
115         __u8 value;
116         char *text;
119 offline_status_text[] =
120         {
121                 {0x00, "NeverStarted"},
122                 {0x02, "Completed"},
123                 {0x04, "Suspended"},
124                 {0x05, "Aborted"},
125                 {0x06, "Failed"},
126                 {0, 0}
127         };
129 struct
131         __u8 value;
132         char *text;
135 smart_command[] =
136         {
137                 {SMART_ENABLE, "SMART_ENABLE"},
138                 {SMART_DISABLE, "SMART_DISABLE"},
139                 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
140                 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
141         };
144 /* Index to smart_command table, keep in order */ 
145 enum SmartCommand 
146         { SMART_CMD_ENABLE,
147                 SMART_CMD_DISABLE,
148                 SMART_CMD_IMMEDIATE_OFFLINE,
149                 SMART_CMD_AUTO_OFFLINE 
150         };
152 void print_values (values_t * p, thresholds_t * t);
153 int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error); 
155 int
156 main (int argc, char *argv[]) 
158         char *device = NULL;
159         int command = -1;
160         int o, longindex;
161         int retval = 0;
163         thresholds_t thresholds;
164         values_t values;
165         int fd;
167         static struct option longopts[] = { 
168                 {"device", required_argument, 0, 'd'}, 
169                 {"immediate", no_argument, 0, 'i'}, 
170                 {"quiet-check", no_argument, 0, 'q'}, 
171                 {"auto-on", no_argument, 0, '1'}, 
172                 {"auto-off", no_argument, 0, '0'}, 
173                 {"nagios", no_argument, 0, 'n'}, 
174                 {"help", no_argument, 0, 'h'}, 
175                 {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} 
176         };
178         setlocale (LC_ALL, "");
179         bindtextdomain (PACKAGE, LOCALEDIR);
180         textdomain (PACKAGE);
182         while (1) {
183                 
184                 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
186                 if (o == -1 || o == EOF || o == 1)
187                         break;
189                 switch (o) {
190                 case 'd':
191                         device = optarg;
192                         break;
193                 case 'q':
194                         command = 3;
195                         break;
196                 case 'i':
197                         command = 2;
198                         break;
199                 case '1':
200                         command = 1;
201                         break;
202                 case '0':
203                         command = 0;
204                         break;
205                 case 'n':
206                         command = 4;
207                         break;
208                 case 'h':
209                         print_help ();
210                         return STATE_OK;
211                 case 'V':
212                         print_revision (progname, revision);
213                         return STATE_OK;
214                 default:
215                         usage5 ();
216                 }
217         }
219         if (optind < argc) {
220                 device = argv[optind];
221         }
223         if (!device) {
224                 print_help ();
225                 return STATE_OK;
226         }
228         fd = open (device, O_RDONLY);
230         if (fd < 0) {
231                 printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno));
232                 return STATE_CRITICAL;
233         }
235         if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
236                 printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
237                 return STATE_CRITICAL;
238         }
240         switch (command) {
241         case 0:
242                 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
243                 break;
244         case 1:
245                 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
246                 break;
247         case 2:
248                 retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
249                 break;
250         case 3:
251                 smart_read_values (fd, &values);
252                 smart_read_thresholds (fd, &thresholds);
253                 retval = values_not_passed (&values, &thresholds);
254                 break;
255         case 4:
256                 smart_read_values (fd, &values);
257                 smart_read_thresholds (fd, &thresholds);
258                 retval = nagios (&values, &thresholds);
259                 break;
260         default:
261                 smart_read_values (fd, &values);
262                 smart_read_thresholds (fd, &thresholds);
263                 print_values (&values, &thresholds);
264                 break;
265         }
266         close (fd);
267         return retval;
272 char *
273 get_offline_text (int status) 
275         int i;
276         for (i = 0; offline_status_text[i].text; i++) {
277                 if (offline_status_text[i].value == status) {
278                         return offline_status_text[i].text;
279                 }
280         }
281         return "UNKNOW";
286 int
287 smart_read_values (int fd, values_t * values) 
289         int e;
290         __u8 args[4 + 512];
291         args[0] = WIN_SMART;
292         args[1] = 0;
293         args[2] = SMART_READ_VALUES;
294         args[3] = 1;
295         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
296                 e = errno;
297                 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
298                 return e;
299         }
300         memcpy (values, args + 4, 512);
301         return 0;
306 int
307 values_not_passed (values_t * p, thresholds_t * t) 
309         value_t * value = p->values;
310         threshold_t * threshold = t->thresholds;
311         int failed = 0;
312         int passed = 0;
313         int i;
314         for (i = 0; i < NR_ATTRIBUTES; i++) {
315                 if (value->id && threshold->id && value->id == threshold->id) {
316                         if (value->value <= threshold->threshold) {
317                                 ++failed;
318                         }
319                         else {
320                                 ++passed;
321                         }
322                 }
323                 ++value;
324                 ++threshold;
325         }
326         return (passed ? -failed : 2);
331 int
332 nagios (values_t * p, thresholds_t * t) 
334         value_t * value = p->values;
335         threshold_t * threshold = t->thresholds;
336         int status = OPERATIONAL;
337         int prefailure = 0;
338         int advisory = 0;
339         int failed = 0;
340         int passed = 0;
341         int total = 0;
342         int i;
343         for (i = 0; i < NR_ATTRIBUTES; i++) {
344                 if (value->id && threshold->id && value->id == threshold->id) {
345                         if (value->value <= threshold->threshold) {
346                                 ++failed;
347                                 if (value->status & 1) {
348                                         status = PREFAILURE;
349                                         ++prefailure;
350                                 }
351                                 else {
352                                         status = ADVISORY;
353                                         ++advisory;
354                                 }
355                         }
356                         else {
357                                 ++passed;
358                         }
359                         ++total;
360                 }
361                 ++value;
362                 ++threshold;
363         }
364         switch (status) {
365         case PREFAILURE:
366                 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
367                         prefailure,
368                         prefailure > 1 ? 's' : ' ',
369                         failed,
370                   total);
371                 status=STATE_CRITICAL;
372                 break;
373         case ADVISORY:
374                 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
375                         advisory,
376                         advisory > 1 ? "ies" : "y",
377                         failed,
378                         total);
379                 status=STATE_WARNING;
380                 break;
381         case OPERATIONAL:
382                 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
383                 status=STATE_OK;
384                 break;
385         default:
386                 printf (_("ERROR - Status '%d' unkown. %d/%d tests passed\n"), status,
387                                                 passed, total);
388                 status = STATE_UNKNOWN;
389                 break;
390         }
391         return status;
396 void
397 print_value (value_t * p, threshold_t * t) 
399         printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
400                                         p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory   ",
401                                         p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
402                                         p->value > t->threshold ? "Passed" : "Failed");
407 void
408 print_values (values_t * p, thresholds_t * t)
410         value_t * value = p->values;
411         threshold_t * threshold = t->thresholds;
412         int i;
413         for (i = 0; i < NR_ATTRIBUTES; i++) {
414                 if (value->id && threshold->id && value->id == threshold->id) {
415                         print_value (value++, threshold++);
416                 }
417         }
418         printf
419                 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
420                  p->offline_status,
421                  get_offline_text (p->offline_status & 0x7f),
422                  (p->offline_status & 0x80 ? "Yes" : "No"),
423                  p->offline_timeout / 60);
424         printf
425                 (_("OffLineCapability=%d {%s %s %s}\n"),
426                  p->offline_capability,
427                  p->offline_capability & 1 ? "Immediate" : "",
428                  p->offline_capability & 2 ? "Auto" : "",
429                  p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
430         printf
431                 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
432                  p->revision,
433                  p->checksum,
434                  p->smart_capability,
435                  p->smart_capability & 1 ? "SaveOnStandBy" : "",
436                  p->smart_capability & 2 ? "AutoSave" : "");
440 int
441 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error) 
443         int e = 0;
444         __u8 args[4];
445         args[0] = WIN_SMART;
446         args[1] = val0;
447         args[2] = smart_command[command].value;
448         args[3] = 0;
449         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
450                 e = errno;
451                 if (show_error) {
452                         printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
453                 }
454         }
455         return e;
460 int
461 smart_read_thresholds (int fd, thresholds_t * thresholds) 
463         int e;
464         __u8 args[4 + 512];
465         args[0] = WIN_SMART;
466   args[1] = 0;
467   args[2] = SMART_READ_THRESHOLDS;
468   args[3] = 1;
469         if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
470                 e = errno;
471                 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
472                 return e;
473         }
474         memcpy (thresholds, args + 4, 512);
475         return 0;
479 void
480 print_help (void)
482         print_revision (progname, revision);
484         printf ("Nagios feature - 1999 Robert Dale <rdale@digital-mission.com>\n");
485         printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
486         printf (COPYRIGHT, copyright, email);
488         printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php]."));
489  
490   printf ("\n\n");
491   
492   print_usage ();
494   printf (_(UT_HELP_VRSN));
495         
496   printf (" %s\n", "-d, --device=DEVICE");
497   printf ("    %s\n", _("Select device DEVICE"));
498   printf ("    %s\n", _("Note: if the device is selected with this option, _no_ other options are accepted"));
499   printf (" %s\n", "-i, --immediate");
500   printf ("    %s\n", _("Perform immediately offline tests"));
501   printf (" %s\n", "-q, --quiet-check");
502   printf ("    %s\n", _("Returns the number of failed tests"));
503   printf (" %s\n", "-1, --auto-on");
504   printf ("    %s\n", _("Turn on automatic offline tests"));
505   printf (" %s\n", "-0, --auto-off");
506   printf ("    %s\n", _("Turn off automatic offline tests"));
507   printf (" %s\n", "-n, --nagios");
508   printf ("    %s\n\n", _("Output suitable for Nagios"));
509   printf (_(UT_SUPPORT));
512  /* todo : add to the long nanual as example
513  *
514  *     Run with:  check_ide-smart --nagios [-d] <DRIVE>
515  *     Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
516  *
517  *       - Returns 0 on no errors
518  *       - Returns 1 on advisories
519  *       - Returns 2 on prefailure
520  *       - Returns -1 not too often
521  */
524 void
525 print_usage (void)
527   printf (_("Usage:"));
528   printf ("%s [-d <device>] [-i <immediate>] [-q quiet] [-1 <auto-on>]",progname);
529   printf (" [-O <auto-off>] [-n <nagios>]\n");