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