check_procs: ignore plugin parent process
[monitoring-plugins.git] / plugins / check_ide_smart.c
blob0a8009ab3908284c542c34da7914a6d3e9f916eb
1 /*****************************************************************************
2 *
3 * Nagios check_ide_smart plugin
4 * ide-smart 1.3 - IDE S.M.A.R.T. checking tool
5 *
6 * License: GPL
7 * Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
8 * 1998 Gadi Oxman <gadio@netvision.net.il>
9 * Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
10 * Copyright (c) 2000-2007 Nagios Plugins Development Team
12 * Description:
14 * This file contains the check_ide_smart plugin
16 * This plugin checks a local hard drive with the (Linux specific) SMART
17 * interface
20 * This program is free software: you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 *****************************************************************************/
36 const char *progname = "check_ide_smart";
37 const char *copyright = "1998-2007";
38 const char *email = "nagiosplug-devel@lists.sourceforge.net";
40 #include "common.h"
41 #include "utils.h"
43 void print_help (void);
44 void print_usage (void);
46 #include <sys/stat.h>
47 #include <sys/ioctl.h>
48 #include <fcntl.h>
49 #ifdef __linux__
50 #include <linux/hdreg.h>
51 #include <linux/types.h>
53 #define OPEN_MODE O_RDONLY
54 #endif /* __linux__ */
55 #ifdef __NetBSD__
56 #include <sys/device.h>
57 #include <sys/param.h>
58 #include <sys/sysctl.h>
59 #include <sys/videoio.h> /* for __u8 and friends */
60 #include <sys/scsiio.h>
61 #include <sys/ataio.h>
62 #include <dev/ata/atareg.h>
63 #include <dev/ic/wdcreg.h>
65 #define SMART_ENABLE WDSM_ENABLE_OPS
66 #define SMART_DISABLE WDSM_DISABLE_OPS
67 #define SMART_IMMEDIATE_OFFLINE WDSM_EXEC_OFFL_IMM
68 #define SMART_AUTO_OFFLINE 0xdb /* undefined in NetBSD headers */
70 #define OPEN_MODE O_RDWR
71 #endif /* __NetBSD__ */
72 #include <errno.h>
74 #define NR_ATTRIBUTES 30
76 #ifndef TRUE
77 #define TRUE 1
78 #endif /* */
80 #define PREFAILURE 2
81 #define ADVISORY 1
82 #define OPERATIONAL 0
83 #define UNKNOWN -1
85 typedef struct threshold_s
87 __u8 id;
88 __u8 threshold;
89 __u8 reserved[10];
91 __attribute__ ((packed)) threshold_t;
93 typedef struct thresholds_s
95 __u16 revision;
96 threshold_t thresholds[NR_ATTRIBUTES];
97 __u8 reserved[18];
98 __u8 vendor[131];
99 __u8 checksum;
101 __attribute__ ((packed)) thresholds_t;
103 typedef struct value_s
105 __u8 id;
106 __u16 status;
107 __u8 value;
108 __u8 vendor[8];
110 __attribute__ ((packed)) value_t;
112 typedef struct values_s
114 __u16 revision;
115 value_t values[NR_ATTRIBUTES];
116 __u8 offline_status;
117 __u8 vendor1;
118 __u16 offline_timeout;
119 __u8 vendor2;
120 __u8 offline_capability;
121 __u16 smart_capability;
122 __u8 reserved[16];
123 __u8 vendor[125];
124 __u8 checksum;
126 __attribute__ ((packed)) values_t;
128 struct
130 __u8 value;
131 char *text;
134 offline_status_text[] =
136 {0x00, "NeverStarted"},
137 {0x02, "Completed"},
138 {0x04, "Suspended"},
139 {0x05, "Aborted"},
140 {0x06, "Failed"},
141 {0, 0}
144 struct
146 __u8 value;
147 char *text;
150 smart_command[] =
152 {SMART_ENABLE, "SMART_ENABLE"},
153 {SMART_DISABLE, "SMART_DISABLE"},
154 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
155 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}
159 /* Index to smart_command table, keep in order */
160 enum SmartCommand
161 { SMART_CMD_ENABLE,
162 SMART_CMD_DISABLE,
163 SMART_CMD_IMMEDIATE_OFFLINE,
164 SMART_CMD_AUTO_OFFLINE
167 char *get_offline_text (int);
168 int smart_read_values (int, values_t *);
169 int values_not_passed (values_t *, thresholds_t *);
170 int nagios (values_t *, thresholds_t *);
171 void print_value (value_t *, threshold_t *);
172 void print_values (values_t *, thresholds_t *);
173 int smart_cmd_simple (int, enum SmartCommand, __u8, char);
174 int smart_read_thresholds (int, thresholds_t *);
177 main (int argc, char *argv[])
179 char *device = NULL;
180 int command = -1;
181 int o, longindex;
182 int retval = 0;
184 thresholds_t thresholds;
185 values_t values;
186 int fd;
188 static struct option longopts[] = {
189 {"device", required_argument, 0, 'd'},
190 {"immediate", no_argument, 0, 'i'},
191 {"quiet-check", no_argument, 0, 'q'},
192 {"auto-on", no_argument, 0, '1'},
193 {"auto-off", no_argument, 0, '0'},
194 {"nagios", no_argument, 0, 'n'},
195 {"help", no_argument, 0, 'h'},
196 {"version", no_argument, 0, 'V'},
197 {0, 0, 0, 0}
200 /* Parse extra opts if any */
201 argv=np_extra_opts (&argc, argv, progname);
203 setlocale (LC_ALL, "");
204 bindtextdomain (PACKAGE, LOCALEDIR);
205 textdomain (PACKAGE);
207 while (1) {
209 o = getopt_long (argc, argv, "+d:iq10nhV", longopts, &longindex);
211 if (o == -1 || o == EOF || o == 1)
212 break;
214 switch (o) {
215 case 'd':
216 device = optarg;
217 break;
218 case 'q':
219 command = 3;
220 break;
221 case 'i':
222 command = 2;
223 break;
224 case '1':
225 command = 1;
226 break;
227 case '0':
228 command = 0;
229 break;
230 case 'n':
231 command = 4;
232 break;
233 case 'h':
234 print_help ();
235 return STATE_OK;
236 case 'V':
237 print_revision (progname, NP_VERSION);
238 return STATE_OK;
239 default:
240 usage5 ();
244 if (optind < argc) {
245 device = argv[optind];
248 if (!device) {
249 print_help ();
250 return STATE_OK;
253 fd = open (device, OPEN_MODE);
255 if (fd < 0) {
256 printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno));
257 return STATE_CRITICAL;
260 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, TRUE)) {
261 printf (_("CRITICAL - SMART_CMD_ENABLE\n"));
262 return STATE_CRITICAL;
265 switch (command) {
266 case 0:
267 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0, TRUE);
268 break;
269 case 1:
270 retval = smart_cmd_simple (fd, SMART_CMD_AUTO_OFFLINE, 0xF8, TRUE);
271 break;
272 case 2:
273 retval = smart_cmd_simple (fd, SMART_CMD_IMMEDIATE_OFFLINE, 0, TRUE);
274 break;
275 case 3:
276 smart_read_values (fd, &values);
277 smart_read_thresholds (fd, &thresholds);
278 retval = values_not_passed (&values, &thresholds);
279 break;
280 case 4:
281 smart_read_values (fd, &values);
282 smart_read_thresholds (fd, &thresholds);
283 retval = nagios (&values, &thresholds);
284 break;
285 default:
286 smart_read_values (fd, &values);
287 smart_read_thresholds (fd, &thresholds);
288 print_values (&values, &thresholds);
289 break;
291 close (fd);
292 return retval;
297 char *
298 get_offline_text (int status)
300 int i;
301 for (i = 0; offline_status_text[i].text; i++) {
302 if (offline_status_text[i].value == status) {
303 return offline_status_text[i].text;
306 return "UNKNOW";
312 smart_read_values (int fd, values_t * values)
314 #ifdef __linux__
315 int e;
316 __u8 args[4 + 512];
317 args[0] = WIN_SMART;
318 args[1] = 0;
319 args[2] = SMART_READ_VALUES;
320 args[3] = 1;
321 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
322 e = errno;
323 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
324 return e;
326 memcpy (values, args + 4, 512);
327 #endif /* __linux__ */
328 #ifdef __NetBSD__
329 struct atareq req;
330 unsigned char inbuf[DEV_BSIZE];
332 memset(&req, 0, sizeof(req));
333 req.timeout = 1000;
334 memset(&inbuf, 0, sizeof(inbuf));
336 req.flags = ATACMD_READ;
337 req.features = WDSM_RD_DATA;
338 req.command = WDCC_SMART;
339 req.databuf = (char *)inbuf;
340 req.datalen = sizeof(inbuf);
341 req.cylinder = WDSMART_CYL;
343 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
344 if (req.retsts != ATACMD_OK)
345 errno = ENODEV;
348 if (errno != 0) {
349 int e = errno;
350 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno));
351 return e;
354 (void)memcpy(values, inbuf, 512);
355 #endif /* __NetBSD__ */
356 return 0;
362 values_not_passed (values_t * p, thresholds_t * t)
364 value_t * value = p->values;
365 threshold_t * threshold = t->thresholds;
366 int failed = 0;
367 int passed = 0;
368 int i;
369 for (i = 0; i < NR_ATTRIBUTES; i++) {
370 if (value->id && threshold->id && value->id == threshold->id) {
371 if (value->value <= threshold->threshold) {
372 ++failed;
374 else {
375 ++passed;
378 ++value;
379 ++threshold;
381 return (passed ? -failed : 2);
387 nagios (values_t * p, thresholds_t * t)
389 value_t * value = p->values;
390 threshold_t * threshold = t->thresholds;
391 int status = OPERATIONAL;
392 int prefailure = 0;
393 int advisory = 0;
394 int failed = 0;
395 int passed = 0;
396 int total = 0;
397 int i;
398 for (i = 0; i < NR_ATTRIBUTES; i++) {
399 if (value->id && threshold->id && value->id == threshold->id) {
400 if (value->value <= threshold->threshold) {
401 ++failed;
402 if (value->status & 1) {
403 status = PREFAILURE;
404 ++prefailure;
406 else {
407 status = ADVISORY;
408 ++advisory;
411 else {
412 ++passed;
414 ++total;
416 ++value;
417 ++threshold;
419 switch (status) {
420 case PREFAILURE:
421 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
422 prefailure,
423 prefailure > 1 ? 's' : ' ',
424 failed,
425 total);
426 status=STATE_CRITICAL;
427 break;
428 case ADVISORY:
429 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
430 advisory,
431 advisory > 1 ? "ies" : "y",
432 failed,
433 total);
434 status=STATE_WARNING;
435 break;
436 case OPERATIONAL:
437 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total);
438 status=STATE_OK;
439 break;
440 default:
441 printf (_("ERROR - Status '%d' unkown. %d/%d tests passed\n"), status,
442 passed, total);
443 status = STATE_UNKNOWN;
444 break;
446 return status;
451 void
452 print_value (value_t * p, threshold_t * t)
454 printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
455 p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
456 p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
457 p->value > t->threshold ? "Passed" : "Failed");
462 void
463 print_values (values_t * p, thresholds_t * t)
465 value_t * value = p->values;
466 threshold_t * threshold = t->thresholds;
467 int i;
468 for (i = 0; i < NR_ATTRIBUTES; i++) {
469 if (value->id && threshold->id && value->id == threshold->id) {
470 print_value (value++, threshold++);
473 printf
474 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
475 p->offline_status,
476 get_offline_text (p->offline_status & 0x7f),
477 (p->offline_status & 0x80 ? "Yes" : "No"),
478 p->offline_timeout / 60);
479 printf
480 (_("OffLineCapability=%d {%s %s %s}\n"),
481 p->offline_capability,
482 p->offline_capability & 1 ? "Immediate" : "",
483 p->offline_capability & 2 ? "Auto" : "",
484 p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
485 printf
486 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
487 p->revision,
488 p->checksum,
489 p->smart_capability,
490 p->smart_capability & 1 ? "SaveOnStandBy" : "",
491 p->smart_capability & 2 ? "AutoSave" : "");
496 smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, char show_error)
498 int e = 0;
499 #ifdef __linux__
500 __u8 args[4];
501 args[0] = WIN_SMART;
502 args[1] = val0;
503 args[2] = smart_command[command].value;
504 args[3] = 0;
505 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
506 e = errno;
507 if (show_error) {
508 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
511 #endif /* __linux__ */
512 #ifdef __NetBSD__
513 struct atareq req;
515 memset(&req, 0, sizeof(req));
516 req.timeout = 1000;
517 req.flags = ATACMD_READREG;
518 req.features = smart_command[command].value;
519 req.command = WDCC_SMART;
520 req.cylinder = WDSMART_CYL;
521 req.sec_count = val0;
523 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
524 if (req.retsts != ATACMD_OK)
525 errno = ENODEV;
526 if (req.cylinder != WDSMART_CYL)
527 errno = ENODEV;
530 if (errno != 0) {
531 e = errno;
532 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno));
533 return e;
535 #endif /* __NetBSD__ */
536 return e;
542 smart_read_thresholds (int fd, thresholds_t * thresholds)
544 #ifdef __linux__
545 int e;
546 __u8 args[4 + 512];
547 args[0] = WIN_SMART;
548 args[1] = 0;
549 args[2] = SMART_READ_THRESHOLDS;
550 args[3] = 1;
551 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) {
552 e = errno;
553 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
554 return e;
556 memcpy (thresholds, args + 4, 512);
557 #endif /* __linux__ */
558 #ifdef __NetBSD__
559 struct atareq req;
560 unsigned char inbuf[DEV_BSIZE];
562 memset(&req, 0, sizeof(req));
563 req.timeout = 1000;
564 memset(&inbuf, 0, sizeof(inbuf));
566 req.flags = ATACMD_READ;
567 req.features = WDSM_RD_THRESHOLDS;
568 req.command = WDCC_SMART;
569 req.databuf = (char *)inbuf;
570 req.datalen = sizeof(inbuf);
571 req.cylinder = WDSMART_CYL;
573 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
574 if (req.retsts != ATACMD_OK)
575 errno = ENODEV;
578 if (errno != 0) {
579 int e = errno;
580 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno));
581 return e;
584 (void)memcpy(thresholds, inbuf, 512);
585 #endif /* __NetBSD__ */
586 return 0;
590 void
591 print_help (void)
593 print_revision (progname, NP_VERSION);
595 printf ("Nagios feature - 1999 Robert Dale <rdale@digital-mission.com>\n");
596 printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
597 printf (COPYRIGHT, copyright, email);
599 printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php]."));
601 printf ("\n\n");
603 print_usage ();
605 printf (UT_HELP_VRSN);
606 printf (UT_EXTRA_OPTS);
608 printf (" %s\n", "-d, --device=DEVICE");
609 printf (" %s\n", _("Select device DEVICE"));
610 printf (" %s\n", _("Note: if the device is selected with this option, _no_ other options are accepted"));
611 printf (" %s\n", "-i, --immediate");
612 printf (" %s\n", _("Perform immediately offline tests"));
613 printf (" %s\n", "-q, --quiet-check");
614 printf (" %s\n", _("Returns the number of failed tests"));
615 printf (" %s\n", "-1, --auto-on");
616 printf (" %s\n", _("Turn on automatic offline tests"));
617 printf (" %s\n", "-0, --auto-off");
618 printf (" %s\n", _("Turn off automatic offline tests"));
619 printf (" %s\n", "-n, --nagios");
620 printf (" %s\n", _("Output suitable for Nagios"));
622 printf (UT_SUPPORT);
625 /* todo : add to the long nanual as example
627 * Run with: check_ide-smart --nagios [-d] <DRIVE>
628 * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
630 * - Returns 0 on no errors
631 * - Returns 1 on advisories
632 * - Returns 2 on prefailure
633 * - Returns -1 not too often
637 void
638 print_usage (void)
640 printf ("%s\n", _("Usage:"));
641 printf ("%s [-d <device>] [-i <immediate>] [-q quiet] [-1 <auto-on>]",progname);
642 printf (" [-O <auto-off>] [-n <nagios>]\n");