1 /*****************************************************************************
3 * Nagios check_ide_smart plugin
4 * 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 * Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
10 * Copyright (c) 2000-2007 Nagios Plugins Development Team
14 * This file contains the check_ide_smart plugin
16 * This plugin checks a local hard drive with the (Linux specific) SMART
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";
43 void print_help (void);
44 void print_usage (void);
47 #include <sys/ioctl.h>
50 #include <linux/hdreg.h>
51 #include <linux/types.h>
53 #define OPEN_MODE O_RDONLY
54 #endif /* __linux__ */
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__ */
74 #define NR_ATTRIBUTES 30
85 typedef struct threshold_s
91 __attribute__ ((packed
)) threshold_t
;
93 typedef struct thresholds_s
96 threshold_t thresholds
[NR_ATTRIBUTES
];
101 __attribute__ ((packed
)) thresholds_t
;
103 typedef struct value_s
110 __attribute__ ((packed
)) value_t
;
112 typedef struct values_s
115 value_t values
[NR_ATTRIBUTES
];
118 __u16 offline_timeout
;
120 __u8 offline_capability
;
121 __u16 smart_capability
;
126 __attribute__ ((packed
)) values_t
;
134 offline_status_text
[] =
136 {0x00, "NeverStarted"},
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 */
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
[])
184 thresholds_t thresholds
;
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'},
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
);
209 o
= getopt_long (argc
, argv
, "+d:iq10nhV", longopts
, &longindex
);
211 if (o
== -1 || o
== EOF
|| o
== 1)
237 print_revision (progname
, NP_VERSION
);
245 device
= argv
[optind
];
253 fd
= open (device
, OPEN_MODE
);
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
;
267 retval
= smart_cmd_simple (fd
, SMART_CMD_AUTO_OFFLINE
, 0, TRUE
);
270 retval
= smart_cmd_simple (fd
, SMART_CMD_AUTO_OFFLINE
, 0xF8, TRUE
);
273 retval
= smart_cmd_simple (fd
, SMART_CMD_IMMEDIATE_OFFLINE
, 0, TRUE
);
276 smart_read_values (fd
, &values
);
277 smart_read_thresholds (fd
, &thresholds
);
278 retval
= values_not_passed (&values
, &thresholds
);
281 smart_read_values (fd
, &values
);
282 smart_read_thresholds (fd
, &thresholds
);
283 retval
= nagios (&values
, &thresholds
);
286 smart_read_values (fd
, &values
);
287 smart_read_thresholds (fd
, &thresholds
);
288 print_values (&values
, &thresholds
);
298 get_offline_text (int status
)
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
;
312 smart_read_values (int fd
, values_t
* values
)
319 args
[2] = SMART_READ_VALUES
;
321 if (ioctl (fd
, HDIO_DRIVE_CMD
, &args
)) {
323 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno
));
326 memcpy (values
, args
+ 4, 512);
327 #endif /* __linux__ */
330 unsigned char inbuf
[DEV_BSIZE
];
332 memset(&req
, 0, sizeof(req
));
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
)
350 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno
));
354 (void)memcpy(values
, inbuf
, 512);
355 #endif /* __NetBSD__ */
362 values_not_passed (values_t
* p
, thresholds_t
* t
)
364 value_t
* value
= p
->values
;
365 threshold_t
* threshold
= t
->thresholds
;
369 for (i
= 0; i
< NR_ATTRIBUTES
; i
++) {
370 if (value
->id
&& threshold
->id
&& value
->id
== threshold
->id
) {
371 if (value
->value
<= threshold
->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
;
398 for (i
= 0; i
< NR_ATTRIBUTES
; i
++) {
399 if (value
->id
&& threshold
->id
&& value
->id
== threshold
->id
) {
400 if (value
->value
<= threshold
->threshold
) {
402 if (value
->status
& 1) {
421 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"),
423 prefailure
> 1 ? 's' : ' ',
426 status
=STATE_CRITICAL
;
429 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"),
431 advisory
> 1 ? "ies" : "y",
434 status
=STATE_WARNING
;
437 printf (_("OK - Operational (%d/%d tests passed)\n"), passed
, total
);
441 printf (_("ERROR - Status '%d' unkown. %d/%d tests passed\n"), status
,
443 status
= STATE_UNKNOWN
;
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");
463 print_values (values_t
* p
, thresholds_t
* t
)
465 value_t
* value
= p
->values
;
466 threshold_t
* threshold
= t
->thresholds
;
468 for (i
= 0; i
< NR_ATTRIBUTES
; i
++) {
469 if (value
->id
&& threshold
->id
&& value
->id
== threshold
->id
) {
470 print_value (value
++, threshold
++);
474 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"),
476 get_offline_text (p
->offline_status
& 0x7f),
477 (p
->offline_status
& 0x80 ? "Yes" : "No"),
478 p
->offline_timeout
/ 60);
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");
486 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
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
)
503 args
[2] = smart_command
[command
].value
;
505 if (ioctl (fd
, HDIO_DRIVE_CMD
, &args
)) {
508 printf (_("CRITICAL - %s: %s\n"), smart_command
[command
].text
, strerror (errno
));
511 #endif /* __linux__ */
515 memset(&req
, 0, sizeof(req
));
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
)
526 if (req
.cylinder
!= WDSMART_CYL
)
532 printf (_("CRITICAL - %s: %s\n"), smart_command
[command
].text
, strerror (errno
));
535 #endif /* __NetBSD__ */
542 smart_read_thresholds (int fd
, thresholds_t
* thresholds
)
549 args
[2] = SMART_READ_THRESHOLDS
;
551 if (ioctl (fd
, HDIO_DRIVE_CMD
, &args
)) {
553 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno
));
556 memcpy (thresholds
, args
+ 4, 512);
557 #endif /* __linux__ */
560 unsigned char inbuf
[DEV_BSIZE
];
562 memset(&req
, 0, sizeof(req
));
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
)
580 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno
));
584 (void)memcpy(thresholds
, inbuf
, 512);
585 #endif /* __NetBSD__ */
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]."));
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"));
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
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");