127
127
#define ARGUSED(x) ((void)(x))
129
const char * smartd_cpp_cvsid = "$Id: smartd.cpp 3075 2010-03-12 22:01:44Z chrfranke $"
129
const char * smartd_cpp_cvsid = "$Id: smartd.cpp 3101 2010-05-04 16:03:18Z chrfranke $"
130
130
CONFIG_H_CVSID EXTERN_H_CVSID;
132
132
extern const char *reportbug;
173
173
// configuration file name
174
#define CONFIGFILENAME "smartd.conf"
177
static const char *configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ;
179
static const char *configfile = "./" CONFIGFILENAME ;
174
static const char * configfile;
181
175
// configuration file "name" if read from stdin
182
176
static const char * const configfile_stdin = "<stdin>";
183
177
// path of alternate configuration file
264
258
bool usage; // Track changes in Usage Attributes
265
259
bool selftest; // Monitor number of selftest errors
266
260
bool errorlog; // Monitor number of ATA errors
261
bool xerrorlog; // Monitor number of ATA errors (Extended Comprehensive error log)
267
262
bool permissive; // Ignore failed SMART commands
268
263
char autosave; // 1=disable, 2=enable Autosave Attributes
269
264
char autoofflinetest; // 1=disable, 2=enable Auto Offline Test
593
589
setmode(fileno(f), O_TEXT); // Allow files with \r\n
592
persistent_dev_state new_state;
596
593
int good = 0, bad = 0;
598
595
while (fgets(line, sizeof(line), f)) {
599
596
const char * s = line + strspn(line, " \t");
600
597
if (!*s || *s == '#')
602
if (!parse_dev_state_line(line, state))
599
if (!parse_dev_state_line(line, new_state))
1412
1412
" -n MODE No check if: never, sleep[,N][,q], standby[,N][,q], idle[,N][,q]\n"
1413
1413
" -H Monitor SMART Health Status, report if failed\n"
1414
1414
" -s REG Do Self-Test at time(s) given by regular expression REG\n"
1415
" -l TYPE Monitor SMART log. Type is one of: error, selftest\n"
1415
" -l TYPE Monitor SMART log. Type is one of: error, selftest, xerror\n"
1416
1416
" -f Monitor 'Usage' Attributes, report failures\n"
1417
1417
" -m ADD Send email warning to address ADD\n"
1418
1418
" -M TYPE Modify email warning behavior (see man page)\n"
1475
1475
PrintOut(LOG_INFO,"\n");
1476
1476
PrintOut(LOG_INFO," -B [+]FILE, --drivedb=[+]FILE\n");
1477
1477
PrintOut(LOG_INFO," Read and replace [add] drive database from FILE\n");
1478
PrintOut(LOG_INFO," [default is +%s", get_drivedb_path_add());
1478
1479
#ifdef SMARTMONTOOLS_DRIVEDBDIR
1479
PrintOut(LOG_INFO," [default is "SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h]\n");
1480
PrintOut(LOG_INFO,"\n");
1481
PrintOut(LOG_INFO," and then %s", get_drivedb_path_default());
1481
PrintOut(LOG_INFO,"\n");
1483
PrintOut(LOG_INFO,"]\n\n");
1482
1484
PrintOut(LOG_INFO," -c NAME|-, --configfile=NAME|-\n");
1483
PrintOut(LOG_INFO," Read configuration file NAME or stdin [default is %s]\n\n", configfile);
1485
PrintOut(LOG_INFO," Read configuration file NAME or stdin\n");
1486
PrintOut(LOG_INFO," [default is %s]\n\n", configfile);
1484
1487
#ifdef HAVE_LIBCAP_NG
1485
1488
PrintOut(LOG_INFO," -C, --capabilities\n");
1486
1489
PrintOut(LOG_INFO," Use capabilities (EXPERIMENTAL).\n"
1545
1548
|| ('a' <= c && c <= 'z'));
1548
// returns <0 on failure
1549
static int ATAErrorCount(ata_device * device, const char * name,
1550
unsigned char fix_firmwarebug)
1551
// Read error count from Summary or Extended Comprehensive SMART error log
1552
// Return -1 on error
1553
static int read_ata_error_count(ata_device * device, const char * name,
1554
unsigned char fix_firmwarebug, bool extended)
1552
struct ata_smart_errorlog log;
1554
if (ataReadErrorLog(device, &log, fix_firmwarebug)){
1555
PrintOut(LOG_INFO,"Device: %s, Read SMART Error Log Failed\n",name);
1559
// return current number of ATA errors
1560
return log.error_log_pointer?log.ata_error_count:0;
1557
ata_smart_errorlog log;
1558
if (ataReadErrorLog(device, &log, fix_firmwarebug)){
1559
PrintOut(LOG_INFO,"Device: %s, Read Summary SMART Error Log failed\n",name);
1562
return (log.error_log_pointer ? log.ata_error_count : 0);
1565
ata_smart_exterrlog logx;
1566
if (!ataReadExtErrorLog(device, &logx, 1 /*first sector only*/)) {
1567
PrintOut(LOG_INFO,"Device: %s, Read Extended Comprehensive SMART Error Log failed\n",name);
1570
// Some disks use the reserved byte as index, see ataprint.cpp.
1571
return (logx.error_log_index || logx.reserved1 ? logx.device_error_count : 0);
1563
1575
// returns <0 if problem. Otherwise, bottom 8 bits are the self test
1723
1735
// do we need to get SMART data?
1724
1736
bool smart_val_ok = false;
1725
if ( cfg.autoofflinetest || cfg.errorlog || cfg.selftest
1737
if ( cfg.autoofflinetest || cfg.selftest
1738
|| cfg.errorlog || cfg.xerrorlog
1726
1739
|| cfg.usagefailed || cfg.prefail || cfg.usage
1727
1740
|| cfg.tempdiff || cfg.tempinfo || cfg.tempcrit
1728
1741
|| cfg.curr_pending_id || cfg.offl_pending_id ) {
1808
1821
// capability check: ATA error log
1822
if (cfg.errorlog || cfg.xerrorlog) {
1812
// start with service disabled, and re-enable it if all works OK
1813
cfg.errorlog = false;
1814
1824
state.ataerrorcount=0;
1817
PrintOut(LOG_INFO, "Device: %s, no SMART Error log (SMART READ DATA failed); disabling -l error\n", name);
1818
else if (!cfg.permissive && !isSmartErrorLogCapable(&state.smartval, &drive))
1819
PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Error log; disabling -l error (override with -T permissive Directive)\n", name);
1820
else if ((val = ATAErrorCount(atadev, name, cfg.fix_firmwarebug)) < 0)
1821
PrintOut(LOG_INFO, "Device: %s, no SMART Error log; remove -l error Directive from smartd.conf\n", name);
1825
if (!(cfg.permissive || (smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) {
1826
PrintOut(LOG_INFO, "Device: %s, no SMART Error Log (%s), ignoring -l [x]error (override with -T permissive)\n",
1827
name, (!smart_val_ok ? "SMART READ DATA failed" : "capability missing"));
1828
cfg.errorlog = cfg.xerrorlog = false;
1823
cfg.errorlog = true;
1824
state.ataerrorcount=val;
1831
int errcnt1 = -1, errcnt2 = -1;
1832
if (cfg.errorlog && (errcnt1 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, false)) < 0) {
1833
PrintOut(LOG_INFO, "Device: %s, no Summary SMART Error Log, ignoring -l error\n", name);
1834
cfg.errorlog = false;
1836
if (cfg.xerrorlog && (errcnt2 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, true)) < 0) {
1837
PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name);
1838
cfg.xerrorlog = false;
1840
if (cfg.errorlog || cfg.xerrorlog) {
1841
if (cfg.errorlog && cfg.xerrorlog && errcnt1 != errcnt2) {
1842
PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n",
1843
name, errcnt1, errcnt2);
1845
// Record max error count
1846
state.ataerrorcount = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
1843
1866
// If no tests available or selected, return
1844
if (!(cfg.errorlog || cfg.selftest || cfg.smartcheck ||
1845
cfg.usagefailed || cfg.prefail || cfg.usage ||
1846
cfg.tempdiff || cfg.tempinfo || cfg.tempcrit )) {
1867
if (!( cfg.smartcheck || cfg.selftest
1868
|| cfg.errorlog || cfg.xerrorlog
1869
|| cfg.usagefailed || cfg.prefail || cfg.usage
1870
|| cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
1847
1871
CloseDevice(atadev, name);
2058
2082
MailWarning(cfg, state, 3, "Device: %s, Self-Test Log error count increased from %d to %d",
2059
2083
name, oldc, newc);
2060
2084
state.must_write = true;
2061
} else if (oldh!=newh) {
2086
else if (newc > 0 && oldh != newh) {
2062
2087
// more recent error
2063
2088
// a 'more recent' error might actually be a smaller hour number,
2064
2089
// if the hour number has wrapped.
2073
2098
state.must_write = true;
2101
// Print info if error entries have disappeared
2103
PrintOut(LOG_INFO, "Device: %s, Self-Test Log error count decreased from %d to %d\n",
2076
2106
// Needed since self-test error count may DECREASE. Hour might
2077
2107
// also have changed.
2078
2108
state.selflogcount= newc;
2764
2794
CheckSelfTestLogs(cfg, state, SelfTestErrorCount(atadev, name, cfg.fix_firmwarebug));
2766
2796
// check if number of ATA errors has increased
2769
int newc, oldc= state.ataerrorcount;
2771
// new number of errors
2772
newc = ATAErrorCount(atadev, name, cfg.fix_firmwarebug);
2797
if (cfg.errorlog || cfg.xerrorlog) {
2799
int errcnt1 = -1, errcnt2 = -1;
2801
errcnt1 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, false);
2803
errcnt2 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, true);
2805
// new number of errors is max of both logs
2806
int newc = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
2774
2808
// did command fail?
2777
2811
MailWarning(cfg, state, 7, "Device: %s, Read SMART Error Log Failed", name);
2779
2813
// has error count increased?
2814
int oldc = state.ataerrorcount;
2780
2815
if (newc>oldc){
2781
2816
PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
2782
2817
name, oldc, newc);
3213
3247
} else if (!strcmp(arg, "error")) {
3214
3248
// track changes in ATA error log
3215
3249
cfg.errorlog = true;
3250
} else if (!strcmp(arg, "xerror")) {
3251
// track changes in Extended Comprehensive SMART error log
3252
cfg.xerrorlog = true;
3506
3543
// If NO monitoring directives are set, then set all of them.
3507
if (!(cfg.smartcheck || cfg.usagefailed || cfg.prefail ||
3508
cfg.usage || cfg.selftest || cfg.errorlog ||
3509
cfg.tempdiff || cfg.tempinfo || cfg.tempcrit )) {
3544
if (!( cfg.smartcheck || cfg.selftest
3545
|| cfg.errorlog || cfg.xerrorlog
3546
|| cfg.usagefailed || cfg.prefail || cfg.usage
3547
|| cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
3511
3549
PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n",
3512
3550
cfg.name.c_str(), cfg.lineno, configfile);
3721
3759
// Parses input line, prints usage message and
3722
3760
// version/license/copyright messages
3723
void ParseOpts(int argc, char **argv){
3761
void ParseOpts(int argc, char **argv)
3763
// Init default configfile path
3765
configfile = SMARTMONTOOLS_SYSCONFDIR"/smartd.conf";
3767
static std::string configfile_str = get_exe_dir() + "/smartd.conf";
3768
configfile = configfile_str.c_str();
3727
3771
// Please update GetValidArgList() if you edit shortopts
3728
3772
static const char shortopts[] = "c:l:q:dDni:p:r:s:A:B:Vh?"
3729
3773
#ifdef HAVE_LIBCAP_NG
3734
3777
// Please update GetValidArgList() if you edit longopts
3735
3778
struct option longopts[] = {
3736
3779
{ "configfile", required_argument, 0, 'c' },
3765
3808
bool badarg = false;
3766
3809
bool no_defaultdb = false; // set true on '-B FILE'
3768
// Parse input options. This horrible construction is so that emacs
3769
// indents properly. Sorry.
3770
while (-1 != (optchar =
3771
getopt_long(argc, argv, shortopts, longopts, NULL)
3811
// Parse input options.
3813
while ((optchar = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
3774
3818
switch(optchar) {
3776
3820
// when to quit