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