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