version 1.1.1.1, 2012/02/21 16:32:16
|
version 1.1.1.2, 2012/10/09 09:36:45
|
Line 4
|
Line 4
|
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> |
* Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> |
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> |
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> |
* Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net> |
* Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net> |
* Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net> | * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 108 typedef int pid_t;
|
Line 108 typedef int pid_t;
|
#define SIGQUIT SIGBREAK |
#define SIGQUIT SIGBREAK |
#define SIGQUIT_KEYNAME "CONTROL-Break" |
#define SIGQUIT_KEYNAME "CONTROL-Break" |
#else // _WIN32 |
#else // _WIN32 |
#ifdef __CYGWIN__ |
|
// 2x CONTROL-C simulates missing SIGQUIT via keyboard |
|
#define SIGQUIT_KEYNAME "2x CONTROL-C" |
|
#else // __CYGWIN__ |
|
#define SIGQUIT_KEYNAME "CONTROL-\\" |
#define SIGQUIT_KEYNAME "CONTROL-\\" |
#endif // __CYGWIN__ |
|
#endif // _WIN32 |
#endif // _WIN32 |
|
|
#if defined (__SVR4) && defined (__sun) |
#if defined (__SVR4) && defined (__sun) |
Line 211 static volatile int caughtsigEXIT=0;
|
Line 206 static volatile int caughtsigEXIT=0;
|
|
|
// This function prints either to stdout or to the syslog as needed. |
// This function prints either to stdout or to the syslog as needed. |
static void PrintOut(int priority, const char *fmt, ...) |
static void PrintOut(int priority, const char *fmt, ...) |
__attribute__ ((format(printf, 2, 3))); | __attribute_format_printf(2, 3); |
|
|
// Attribute monitoring flags. |
// Attribute monitoring flags. |
// See monitor_attr_flags below. |
// See monitor_attr_flags below. |
Line 263 struct dev_config
|
Line 258 struct dev_config
|
bool errorlog; // Monitor number of ATA errors |
bool errorlog; // Monitor number of ATA errors |
bool xerrorlog; // Monitor number of ATA errors (Extended Comprehensive error log) |
bool xerrorlog; // Monitor number of ATA errors (Extended Comprehensive error log) |
bool offlinests; // Monitor changes in offline data collection status |
bool offlinests; // Monitor changes in offline data collection status |
|
bool offlinests_ns; // Disable auto standby if in progress |
bool selfteststs; // Monitor changes in self-test execution status |
bool selfteststs; // Monitor changes in self-test execution status |
|
bool selfteststs_ns; // Disable auto standby if in progress |
bool permissive; // Ignore failed SMART commands |
bool permissive; // Ignore failed SMART commands |
char autosave; // 1=disable, 2=enable Autosave Attributes |
char autosave; // 1=disable, 2=enable Autosave Attributes |
char autoofflinetest; // 1=disable, 2=enable Auto Offline Test |
char autoofflinetest; // 1=disable, 2=enable Auto Offline Test |
Line 285 struct dev_config
|
Line 282 struct dev_config
|
bool emailtest; // Send test email? |
bool emailtest; // Send test email? |
|
|
// ATA ONLY |
// ATA ONLY |
|
int set_aam; // disable(-1), enable(1..255->0..254) Automatic Acoustic Management |
|
int set_apm; // disable(-1), enable(2..255->1..254) Advanced Power Management |
|
int set_lookahead; // disable(-1), enable(1) read look-ahead |
|
int set_standby; // set(1..255->0..254) standby timer |
|
bool set_security_freeze; // Freeze ATA security |
|
int set_wcache; // disable(-1), enable(1) write cache |
|
|
bool sct_erc_set; // set SCT ERC to: |
bool sct_erc_set; // set SCT ERC to: |
unsigned short sct_erc_readtime; // ERC read time (deciseconds) |
unsigned short sct_erc_readtime; // ERC read time (deciseconds) |
unsigned short sct_erc_writetime; // ERC write time (deciseconds) |
unsigned short sct_erc_writetime; // ERC write time (deciseconds) |
Line 310 dev_config::dev_config()
|
Line 314 dev_config::dev_config()
|
selftest(false), |
selftest(false), |
errorlog(false), |
errorlog(false), |
xerrorlog(false), |
xerrorlog(false), |
offlinests(false), | offlinests(false), offlinests_ns(false), |
selfteststs(false), | selfteststs(false), selfteststs_ns(false), |
permissive(false), |
permissive(false), |
autosave(0), |
autosave(0), |
autoofflinetest(0), |
autoofflinetest(0), |
Line 326 dev_config::dev_config()
|
Line 330 dev_config::dev_config()
|
tempinfo(0), tempcrit(0), |
tempinfo(0), tempcrit(0), |
emailfreq(0), |
emailfreq(0), |
emailtest(false), |
emailtest(false), |
|
set_aam(0), set_apm(0), |
|
set_lookahead(0), |
|
set_standby(0), |
|
set_security_freeze(false), |
|
set_wcache(0), |
sct_erc_set(false), |
sct_erc_set(false), |
sct_erc_readtime(0), sct_erc_writetime(0), |
sct_erc_readtime(0), sct_erc_writetime(0), |
curr_pending_id(0), offl_pending_id(0), |
curr_pending_id(0), offl_pending_id(0), |
Line 422 struct temp_dev_state
|
Line 431 struct temp_dev_state
|
uint64_t num_sectors; // Number of sectors |
uint64_t num_sectors; // Number of sectors |
ata_smart_values smartval; // SMART data |
ata_smart_values smartval; // SMART data |
ata_smart_thresholds_pvt smartthres; // SMART thresholds |
ata_smart_thresholds_pvt smartthres; // SMART thresholds |
|
bool offline_started; // true if offline data collection was started |
|
bool selftest_started; // true if self-test was started |
|
|
temp_dev_state(); |
temp_dev_state(); |
}; |
}; |
Line 441 temp_dev_state::temp_dev_state()
|
Line 452 temp_dev_state::temp_dev_state()
|
TempPageSupported(false), |
TempPageSupported(false), |
SuppressReport(false), |
SuppressReport(false), |
modese_len(0), |
modese_len(0), |
num_sectors(0) | num_sectors(0), |
| offline_started(false), |
| selftest_started(false) |
{ |
{ |
memset(&smartval, 0, sizeof(smartval)); |
memset(&smartval, 0, sizeof(smartval)); |
memset(&smartthres, 0, sizeof(smartthres)); |
memset(&smartthres, 0, sizeof(smartthres)); |
Line 891 static char *dnsdomain(const char *hostname)
|
Line 904 static char *dnsdomain(const char *hostname)
|
#define EBUFLEN 1024 |
#define EBUFLEN 1024 |
|
|
static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) |
static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) |
__attribute__ ((format (printf, 4, 5))); | __attribute_format_printf(4, 5); |
|
|
// If either address or executable path is non-null then send and log |
// If either address or executable path is non-null then send and log |
// a warning email, or execute executable |
// a warning email, or execute executable |
Line 1245 static void MailWarning(const dev_config & cfg, dev_st
|
Line 1258 static void MailWarning(const dev_config & cfg, dev_st
|
} |
} |
|
|
static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) |
static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) |
__attribute__ ((format (printf, 4, 5))); | __attribute_format_printf(4, 5); |
|
|
static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) |
static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) |
{ |
{ |
Line 1500 static void Directives()
|
Line 1513 static void Directives()
|
" -n MODE No check if: never, sleep[,N][,q], standby[,N][,q], idle[,N][,q]\n" |
" -n MODE No check if: never, sleep[,N][,q], standby[,N][,q], idle[,N][,q]\n" |
" -H Monitor SMART Health Status, report if failed\n" |
" -H Monitor SMART Health Status, report if failed\n" |
" -s REG Do Self-Test at time(s) given by regular expression REG\n" |
" -s REG Do Self-Test at time(s) given by regular expression REG\n" |
" -l TYPE Monitor SMART log or self-test status\n" | " -l TYPE Monitor SMART log or self-test status:\n" |
" Type is one of: error, selftest, xerror, offlinests, selfteststs\n" | " error, selftest, xerror, offlinests[,ns], selfteststs[,ns]\n" |
" -l scterc,R,W Set SCT Error Recovery Control\n" |
" -l scterc,R,W Set SCT Error Recovery Control\n" |
|
" -e Change device setting: aam,[N|off], apm,[N|off], lookahead,[on|off],\n" |
|
" security-freeze, standby,[N|off], wcache,[on|off]\n" |
" -f Monitor 'Usage' Attributes, report failures\n" |
" -f Monitor 'Usage' Attributes, report failures\n" |
" -m ADD Send email warning to address ADD\n" |
" -m ADD Send email warning to address ADD\n" |
" -M TYPE Modify email warning behavior (see man page)\n" |
" -M TYPE Modify email warning behavior (see man page)\n" |
Line 1683 static int SelfTestErrorCount(ata_device * device, con
|
Line 1698 static int SelfTestErrorCount(ata_device * device, con
|
#define SELFTEST_ERRORCOUNT(x) (x & 0xff) |
#define SELFTEST_ERRORCOUNT(x) (x & 0xff) |
#define SELFTEST_ERRORHOURS(x) ((x >> 8) & 0xffff) |
#define SELFTEST_ERRORHOURS(x) ((x >> 8) & 0xffff) |
|
|
|
// Check offline data collection status |
|
static inline bool is_offl_coll_in_progress(unsigned char status) |
|
{ |
|
return ((status & 0x7f) == 0x03); |
|
} |
|
|
|
// Check self-test execution status |
|
static inline bool is_self_test_in_progress(unsigned char status) |
|
{ |
|
return ((status >> 4) == 0xf); |
|
} |
|
|
// Log offline data collection status |
// Log offline data collection status |
static void log_offline_data_coll_status(const char * name, unsigned char status) |
static void log_offline_data_coll_status(const char * name, unsigned char status) |
{ |
{ |
Line 1775 static void finish_device_scan(dev_config & cfg, dev_s
|
Line 1802 static void finish_device_scan(dev_config & cfg, dev_s
|
state.scheduled_test_next_check = time(0); |
state.scheduled_test_next_check = time(0); |
} |
} |
|
|
|
// Common function to format result message for ATA setting |
|
static void format_set_result_msg(std::string & msg, const char * name, bool ok, |
|
int set_option = 0, bool has_value = false) |
|
{ |
|
if (!msg.empty()) |
|
msg += ", "; |
|
msg += name; |
|
if (!ok) |
|
msg += ":--"; |
|
else if (set_option < 0) |
|
msg += ":off"; |
|
else if (has_value) |
|
msg += strprintf(":%d", set_option-1); |
|
else if (set_option > 0) |
|
msg += ":on"; |
|
} |
|
|
|
|
// TODO: Add '-F swapid' directive |
// TODO: Add '-F swapid' directive |
const bool fix_swapped_id = false; |
const bool fix_swapped_id = false; |
|
|
Line 1956 static int ATADeviceScan(dev_config & cfg, dev_state &
|
Line 2000 static int ATADeviceScan(dev_config & cfg, dev_state &
|
PrintOut(LOG_CRIT, "Device: %s, can't monitor Temperature, ignoring -W Directive\n", name); |
PrintOut(LOG_CRIT, "Device: %s, can't monitor Temperature, ignoring -W Directive\n", name); |
cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0; |
cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0; |
} |
} |
|
|
|
// Report ignored '-r' or '-R' directives |
|
for (int id = 1; id <= 255; id++) { |
|
if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) { |
|
char opt = (!cfg.monitor_attr_flags.is_set(id, MONITOR_RAW) ? 'r' : 'R'); |
|
const char * excl = (cfg.monitor_attr_flags.is_set(id, |
|
(opt == 'r' ? MONITOR_AS_CRIT : MONITOR_RAW_AS_CRIT)) ? "!" : ""); |
|
|
|
int idx = ata_find_attr_index(id, state.smartval); |
|
if (idx < 0) |
|
PrintOut(LOG_INFO,"Device: %s, no Attribute %d, ignoring -%c %d%s\n", name, id, opt, id, excl); |
|
else { |
|
bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(state.smartval.vendor_attributes[idx].flags); |
|
if (!((prefail && cfg.prefail) || (!prefail && cfg.usage))) |
|
PrintOut(LOG_INFO,"Device: %s, not monitoring %s Attributes, ignoring -%c %d%s\n", name, |
|
(prefail ? "Prefailure" : "Usage"), opt, id, excl); |
|
} |
|
} |
|
} |
} |
} |
|
|
// enable/disable automatic on-line testing |
// enable/disable automatic on-line testing |
Line 2077 static int ATADeviceScan(dev_config & cfg, dev_state &
|
Line 2140 static int ATADeviceScan(dev_config & cfg, dev_state &
|
} |
} |
} |
} |
|
|
|
// Apply ATA settings |
|
std::string msg; |
|
|
|
if (cfg.set_aam) |
|
format_set_result_msg(msg, "AAM", (cfg.set_aam > 0 ? |
|
ata_set_features(atadev, ATA_ENABLE_AAM, cfg.set_aam-1) : |
|
ata_set_features(atadev, ATA_DISABLE_AAM)), cfg.set_aam, true); |
|
|
|
if (cfg.set_apm) |
|
format_set_result_msg(msg, "APM", (cfg.set_apm > 0 ? |
|
ata_set_features(atadev, ATA_ENABLE_APM, cfg.set_apm-1) : |
|
ata_set_features(atadev, ATA_DISABLE_APM)), cfg.set_apm, true); |
|
|
|
if (cfg.set_lookahead) |
|
format_set_result_msg(msg, "Rd-ahead", ata_set_features(atadev, |
|
(cfg.set_lookahead > 0 ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD)), |
|
cfg.set_lookahead); |
|
|
|
if (cfg.set_wcache) |
|
format_set_result_msg(msg, "Wr-cache", ata_set_features(atadev, |
|
(cfg.set_wcache > 0? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE)), cfg.set_wcache); |
|
|
|
if (cfg.set_security_freeze) |
|
format_set_result_msg(msg, "Security freeze", |
|
ata_nodata_command(atadev, ATA_SECURITY_FREEZE_LOCK)); |
|
|
|
if (cfg.set_standby) |
|
format_set_result_msg(msg, "Standby", |
|
ata_nodata_command(atadev, ATA_IDLE, cfg.set_standby-1), cfg.set_standby, true); |
|
|
|
// Report as one log entry |
|
if (!msg.empty()) |
|
PrintOut(LOG_INFO, "Device: %s, ATA settings applied: %s\n", name, msg.c_str()); |
|
|
// set SCT Error Recovery Control if requested |
// set SCT Error Recovery Control if requested |
if (cfg.sct_erc_set) { |
if (cfg.sct_erc_set) { |
if (!isSCTErrorRecoveryControlCapable(&drive)) |
if (!isSCTErrorRecoveryControlCapable(&drive)) |
Line 2155 static int SCSIDeviceScan(dev_config & cfg, dev_state
|
Line 2252 static int SCSIDeviceScan(dev_config & cfg, dev_state
|
version = inqBuf[2]; |
version = inqBuf[2]; |
avail_len = inqBuf[4] + 5; |
avail_len = inqBuf[4] + 5; |
len = (avail_len < req_len) ? avail_len : req_len; |
len = (avail_len < req_len) ? avail_len : req_len; |
// peri_dt = inqBuf[0] & 0x1f; |
|
if (len < 36) { |
if (len < 36) { |
PrintOut(LOG_INFO, "Device: %s, INQUIRY response less than 36 bytes; " |
PrintOut(LOG_INFO, "Device: %s, INQUIRY response less than 36 bytes; " |
"skip device\n", device); |
"skip device\n", device); |
return 2; |
return 2; |
} |
} |
|
|
|
int pdt = inqBuf[0] & 0x1f; |
|
|
|
if (! ((0 == pdt) || (4 == pdt) || (5 == pdt) || (7 == pdt) || |
|
(0xe == pdt))) { |
|
PrintOut(LOG_INFO, "Device: %s, not a disk like device [PDT=0x%x], " |
|
"skip\n", device, pdt); |
|
return 2; |
|
} |
lu_id[0] = '\0'; |
lu_id[0] = '\0'; |
if ((version >= 0x4) && (version < 0x8)) { |
if ((version >= 0x4) && (version < 0x8)) { |
/* SPC-2 to SPC-5 */ |
/* SPC-2 to SPC-5 */ |
Line 2307 static int SCSIDeviceScan(dev_config & cfg, dev_state
|
Line 2412 static int SCSIDeviceScan(dev_config & cfg, dev_state
|
PrintOut(LOG_INFO, "Device: %s, attribute log not yet supported for SCSI; ignoring -A option.\n", device); |
PrintOut(LOG_INFO, "Device: %s, attribute log not yet supported for SCSI; ignoring -A option.\n", device); |
} |
} |
|
|
|
// Make sure that init_standby_check() ignores SCSI devices |
|
cfg.offlinests_ns = cfg.selfteststs_ns = false; |
|
|
// close file descriptor |
// close file descriptor |
CloseDevice(scsidev, device); |
CloseDevice(scsidev, device); |
|
|
Line 2686 static int DoATASelfTest(const dev_config & cfg, dev_s
|
Line 2794 static int DoATASelfTest(const dev_config & cfg, dev_s
|
return retval; |
return retval; |
} |
} |
|
|
if (testtype != 'O') | // Report recent test start to do_disable_standby_check() |
// Log next self-test execution status | // and force log of next test status |
state.smartval.self_test_exec_status = 0xff; | if (testtype == 'O') |
| state.offline_started = true; |
| else |
| state.selftest_started = true; |
|
|
PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname); |
PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname); |
return 0; |
return 0; |
Line 3063 static int ATACheckDevice(const dev_config & cfg, dev_
|
Line 3174 static int ATACheckDevice(const dev_config & cfg, dev_
|
if (cfg.offlinests) { |
if (cfg.offlinests) { |
if ( curval.offline_data_collection_status |
if ( curval.offline_data_collection_status |
!= state.smartval.offline_data_collection_status |
!= state.smartval.offline_data_collection_status |
|
|| state.offline_started // test was started in previous call |
|| (firstpass && (debugmode || (curval.offline_data_collection_status & 0x7d)))) |
|| (firstpass && (debugmode || (curval.offline_data_collection_status & 0x7d)))) |
log_offline_data_coll_status(name, curval.offline_data_collection_status); |
log_offline_data_coll_status(name, curval.offline_data_collection_status); |
} |
} |
Line 3070 static int ATACheckDevice(const dev_config & cfg, dev_
|
Line 3182 static int ATACheckDevice(const dev_config & cfg, dev_
|
// Log changes of self-test execution status |
// Log changes of self-test execution status |
if (cfg.selfteststs) { |
if (cfg.selfteststs) { |
if ( curval.self_test_exec_status != state.smartval.self_test_exec_status |
if ( curval.self_test_exec_status != state.smartval.self_test_exec_status |
|
|| state.selftest_started // test was started in previous call |
|| (firstpass && (debugmode || curval.self_test_exec_status != 0x00))) |
|| (firstpass && (debugmode || curval.self_test_exec_status != 0x00))) |
log_self_test_exec_status(name, curval.self_test_exec_status); |
log_self_test_exec_status(name, curval.self_test_exec_status); |
} |
} |
Line 3078 static int ATACheckDevice(const dev_config & cfg, dev_
|
Line 3191 static int ATACheckDevice(const dev_config & cfg, dev_
|
state.smartval = curval; |
state.smartval = curval; |
} |
} |
} |
} |
|
state.offline_started = state.selftest_started = false; |
|
|
// check if number of selftest errors has increased (note: may also DECREASE) |
// check if number of selftest errors has increased (note: may also DECREASE) |
if (cfg.selftest) |
if (cfg.selftest) |
Line 3192 static int SCSICheckDevice(const dev_config & cfg, dev
|
Line 3306 static int SCSICheckDevice(const dev_config & cfg, dev
|
return 0; |
return 0; |
} |
} |
|
|
|
// 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled |
|
static int standby_disable_state = 0; |
|
|
|
static void init_disable_standby_check(dev_config_vector & configs) |
|
{ |
|
// Check for '-l offlinests,ns' or '-l selfteststs,ns' directives |
|
bool sts1 = false, sts2 = false; |
|
for (unsigned i = 0; i < configs.size() && !(sts1 || sts2); i++) { |
|
const dev_config & cfg = configs.at(i); |
|
if (cfg.offlinests_ns) |
|
sts1 = true; |
|
if (cfg.selfteststs_ns) |
|
sts2 = true; |
|
} |
|
|
|
// Check for support of disable auto standby |
|
// Reenable standby if smartd.conf was reread |
|
if (sts1 || sts2 || standby_disable_state == 3) { |
|
if (!smi()->disable_system_auto_standby(false)) { |
|
if (standby_disable_state == 3) |
|
PrintOut(LOG_CRIT, "System auto standby enable failed: %s\n", smi()->get_errmsg()); |
|
if (sts1 || sts2) { |
|
PrintOut(LOG_INFO, "Disable auto standby not supported, ignoring ',ns' from %s%s%s\n", |
|
(sts1 ? "-l offlinests,ns" : ""), (sts1 && sts2 ? " and " : ""), (sts2 ? "-l selfteststs,ns" : "")); |
|
sts1 = sts2 = false; |
|
} |
|
} |
|
} |
|
|
|
standby_disable_state = (sts1 || sts2 ? 1 : 0); |
|
} |
|
|
|
static void do_disable_standby_check(const dev_config_vector & configs, const dev_state_vector & states) |
|
{ |
|
if (!standby_disable_state) |
|
return; |
|
|
|
// Check for just started or still running self-tests |
|
bool running = false; |
|
for (unsigned i = 0; i < configs.size() && !running; i++) { |
|
const dev_config & cfg = configs.at(i); const dev_state & state = states.at(i); |
|
|
|
if ( ( cfg.offlinests_ns |
|
&& (state.offline_started || |
|
is_offl_coll_in_progress(state.smartval.offline_data_collection_status))) |
|
|| ( cfg.selfteststs_ns |
|
&& (state.selftest_started || |
|
is_self_test_in_progress(state.smartval.self_test_exec_status))) ) |
|
running = true; |
|
// state.offline/selftest_started will be reset after next logging of test status |
|
} |
|
|
|
// Disable/enable auto standby and log state changes |
|
if (!running) { |
|
if (standby_disable_state != 1) { |
|
if (!smi()->disable_system_auto_standby(false)) |
|
PrintOut(LOG_CRIT, "Self-test(s) completed, system auto standby enable failed: %s\n", |
|
smi()->get_errmsg()); |
|
else |
|
PrintOut(LOG_INFO, "Self-test(s) completed, system auto standby enabled\n"); |
|
standby_disable_state = 1; |
|
} |
|
} |
|
else if (!smi()->disable_system_auto_standby(true)) { |
|
if (standby_disable_state != 2) { |
|
PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disable rejected: %s\n", |
|
smi()->get_errmsg()); |
|
standby_disable_state = 2; |
|
} |
|
} |
|
else { |
|
if (standby_disable_state != 3) { |
|
PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disabled\n"); |
|
standby_disable_state = 3; |
|
} |
|
} |
|
} |
|
|
// Checks the SMART status of all ATA and SCSI devices |
// Checks the SMART status of all ATA and SCSI devices |
static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector & states, |
static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector & states, |
smart_device_list & devices, bool firstpass, bool allow_selftests) |
smart_device_list & devices, bool firstpass, bool allow_selftests) |
Line 3205 static void CheckDevicesOnce(const dev_config_vector &
|
Line 3397 static void CheckDevicesOnce(const dev_config_vector &
|
else if (dev->is_scsi()) |
else if (dev->is_scsi()) |
SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests); |
SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests); |
} |
} |
|
|
|
do_disable_standby_check(configs, states); |
} |
} |
|
|
// Set if Initialize() was called |
// Set if Initialize() was called |
Line 3368 static void printoutvaliddirectiveargs(int priority, c
|
Line 3562 static void printoutvaliddirectiveargs(int priority, c
|
break; |
break; |
case 'F': |
case 'F': |
PrintOut(priority, "none, samsung, samsung2, samsung3"); |
PrintOut(priority, "none, samsung, samsung2, samsung3"); |
|
case 'e': |
|
PrintOut(priority, "aam,[N|off], apm,[N|off], lookahead,[on|off], " |
|
"security-freeze, standby,[N|off], wcache,[on|off]"); |
break; |
break; |
} |
} |
} |
} |
Line 3560 static int ParseToken(char * token, dev_config & cfg)
|
Line 3757 static int ParseToken(char * token, dev_config & cfg)
|
} else if (!strcmp(arg, "offlinests")) { |
} else if (!strcmp(arg, "offlinests")) { |
// track changes in offline data collection status |
// track changes in offline data collection status |
cfg.offlinests = true; |
cfg.offlinests = true; |
|
} else if (!strcmp(arg, "offlinests,ns")) { |
|
// track changes in offline data collection status, disable auto standby |
|
cfg.offlinests = cfg.offlinests_ns = true; |
} else if (!strcmp(arg, "selfteststs")) { |
} else if (!strcmp(arg, "selfteststs")) { |
// track changes in self-test execution status |
// track changes in self-test execution status |
cfg.selfteststs = true; |
cfg.selfteststs = true; |
|
} else if (!strcmp(arg, "selfteststs,ns")) { |
|
// track changes in self-test execution status, disable auto standby |
|
cfg.selfteststs = cfg.selfteststs_ns = true; |
} else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) { |
} else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) { |
// set SCT Error Recovery Control |
// set SCT Error Recovery Control |
unsigned rt = ~0, wt = ~0; int nc = -1; |
unsigned rt = ~0, wt = ~0; int nc = -1; |
Line 3780 static int ParseToken(char * token, dev_config & cfg)
|
Line 3983 static int ParseToken(char * token, dev_config & cfg)
|
badarg = 1; |
badarg = 1; |
} |
} |
break; |
break; |
|
|
|
case 'e': |
|
// Various ATA settings |
|
if (!(arg = strtok(NULL, delim))) { |
|
missingarg = true; |
|
} |
|
else { |
|
char arg2[16+1]; unsigned val; |
|
int n1 = -1, n2 = -1, n3 = -1, len = strlen(arg); |
|
if (sscanf(arg, "%16[^,=]%n%*[,=]%n%u%n", arg2, &n1, &n2, &val, &n3) >= 1 |
|
&& (n1 == len || n2 > 0)) { |
|
bool on = (n2 > 0 && !strcmp(arg+n2, "on")); |
|
bool off = (n2 > 0 && !strcmp(arg+n2, "off")); |
|
if (n3 != len) |
|
val = ~0U; |
|
|
|
if (!strcmp(arg2, "aam")) { |
|
if (off) |
|
cfg.set_aam = -1; |
|
else if (val <= 254) |
|
cfg.set_aam = val + 1; |
|
else |
|
badarg = true; |
|
} |
|
else if (!strcmp(arg2, "apm")) { |
|
if (off) |
|
cfg.set_apm = -1; |
|
else if (1 <= val && val <= 254) |
|
cfg.set_apm = val + 1; |
|
else |
|
badarg = true; |
|
} |
|
else if (!strcmp(arg2, "lookahead")) { |
|
if (off) |
|
cfg.set_lookahead = -1; |
|
else if (on) |
|
cfg.set_lookahead = 1; |
|
else |
|
badarg = true; |
|
} |
|
else if (!strcmp(arg, "security-freeze")) { |
|
cfg.set_security_freeze = true; |
|
} |
|
else if (!strcmp(arg2, "standby")) { |
|
if (off) |
|
cfg.set_standby = 0 + 1; |
|
else if (val <= 255) |
|
cfg.set_standby = val + 1; |
|
else |
|
badarg = true; |
|
} |
|
else if (!strcmp(arg2, "wcache")) { |
|
if (off) |
|
cfg.set_wcache = -1; |
|
else if (on) |
|
cfg.set_wcache = 1; |
|
else |
|
badarg = true; |
|
} |
|
else |
|
badarg = true; |
|
} |
|
else |
|
badarg = true; |
|
} |
|
break; |
|
|
default: |
default: |
// Directive not recognized |
// Directive not recognized |
PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n", |
PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n", |
Line 3812 static int ParseToken(char * token, dev_config & cfg)
|
Line 4082 static int ParseToken(char * token, dev_config & cfg)
|
// |
// |
// Return values are: |
// Return values are: |
// 1: parsed a normal line |
// 1: parsed a normal line |
// 0: found comment or blank line | // 0: found DEFAULT setting or comment or blank line |
// -1: found SCANDIRECTIVE line |
// -1: found SCANDIRECTIVE line |
// -2: found an error |
// -2: found an error |
// |
// |
// Note: this routine modifies *line from the caller! |
// Note: this routine modifies *line from the caller! |
static int ParseConfigLine(dev_config_vector & conf_entries, int /*entry*/, int lineno, /*const*/ char * line) | static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf, int lineno, /*const*/ char * line) |
{ |
{ |
char *token=NULL; |
|
char *name=NULL; |
|
const char *delim = " \n\t"; |
const char *delim = " \n\t"; |
int devscan=0; |
|
|
|
// get first token: device name. If a comment, skip line |
// get first token: device name. If a comment, skip line |
if (!(name=strtok(line,delim)) || *name=='#') { | const char * name = strtok(line, delim); |
| if (!name || *name == '#') |
return 0; |
return 0; |
} |
|
|
|
// Have we detected the SCANDIRECTIVE directive? | // Check device name for DEFAULT or DEVICESCAN |
if (!strcmp(SCANDIRECTIVE,name)){ | int retval; |
devscan=1; | if (!strcmp("DEFAULT", name)) { |
| retval = 0; |
| // Restart with empty defaults |
| default_conf = dev_config(); |
} |
} |
| else { |
// We've got a legit entry, make space to store it | retval = (!strcmp(SCANDIRECTIVE, name) ? -1 : 1); |
conf_entries.push_back( dev_config() ); | // Init new entry with current defaults |
dev_config & cfg = conf_entries.back(); | conf_entries.push_back(default_conf); |
| } |
| dev_config & cfg = (retval ? conf_entries.back() : default_conf); |
|
|
cfg.name = name; // Later replaced by dev->get_info().info_name |
cfg.name = name; // Later replaced by dev->get_info().info_name |
cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name |
cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name |
|
cfg.lineno = lineno; |
|
|
// Store line number, and by default check for both device types. |
|
cfg.lineno=lineno; |
|
|
|
// parse tokens one at a time from the file. |
// parse tokens one at a time from the file. |
while ((token=strtok(NULL,delim))){ | while (char * token = strtok(0, delim)) { |
int retval=ParseToken(token,cfg); | int rc = ParseToken(token, cfg); |
| if (rc < 0) |
if (retval==0) | |
// No tokens left: | |
break; | |
| |
if (retval>0) { | |
// Parsed token | |
#if (0) | |
PrintOut(LOG_INFO,"Parsed token %s\n",token); | |
#endif | |
continue; | |
} | |
| |
if (retval<0) { | |
// error found on the line |
// error found on the line |
return -2; |
return -2; |
} | |
| if (rc == 0) |
| // No tokens left |
| break; |
| |
| // PrintOut(LOG_INFO,"Parsed token %s\n",token); |
} |
} |
| |
| // Don't perform checks below for DEFAULT entries |
| if (retval == 0) |
| return retval; |
| |
// If NO monitoring directives are set, then set all of them. |
// If NO monitoring directives are set, then set all of them. |
if (!( cfg.smartcheck || cfg.selftest |
if (!( cfg.smartcheck || cfg.selftest |
|| cfg.errorlog || cfg.xerrorlog |
|| cfg.errorlog || cfg.xerrorlog |
Line 3904 static int ParseConfigLine(dev_config_vector & conf_en
|
Line 4170 static int ParseConfigLine(dev_config_vector & conf_en
|
cfg.emailaddress.clear(); |
cfg.emailaddress.clear(); |
} |
} |
|
|
if (devscan) | return retval; |
return -1; | |
else | |
return 1; | |
} |
} |
|
|
// Parses a configuration file. Return values are: |
// Parses a configuration file. Return values are: |
Line 3942 static int ParseConfigFile(dev_config_vector & conf_en
|
Line 4205 static int ParseConfigFile(dev_config_vector & conf_en
|
else // read from stdin ('-c -' option) |
else // read from stdin ('-c -' option) |
f.open(stdin); |
f.open(stdin); |
|
|
|
// Start with empty defaults |
|
dev_config default_conf; |
|
|
// No configuration file found -- use fake one |
// No configuration file found -- use fake one |
int entry = 0; |
int entry = 0; |
if (!f) { |
if (!f) { |
char fakeconfig[] = SCANDIRECTIVE" -a"; // TODO: Remove this hack, build cfg_entry. |
char fakeconfig[] = SCANDIRECTIVE" -a"; // TODO: Remove this hack, build cfg_entry. |
|
|
if (ParseConfigLine(conf_entries, entry, 0, fakeconfig) != -1) | if (ParseConfigLine(conf_entries, default_conf, 0, fakeconfig) != -1) |
throw std::logic_error("Internal error parsing "SCANDIRECTIVE); |
throw std::logic_error("Internal error parsing "SCANDIRECTIVE); |
return 0; |
return 0; |
} |
} |
Line 3979 static int ParseConfigFile(dev_config_vector & conf_en
|
Line 4245 static int ParseConfigFile(dev_config_vector & conf_en
|
// are we at the end of the file? |
// are we at the end of the file? |
if (!code){ |
if (!code){ |
if (cont) { |
if (cont) { |
scandevice = ParseConfigLine(conf_entries, entry, contlineno, fullline); | scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline); |
// See if we found a SCANDIRECTIVE directive |
// See if we found a SCANDIRECTIVE directive |
if (scandevice==-1) |
if (scandevice==-1) |
return 0; |
return 0; |
Line 4033 static int ParseConfigFile(dev_config_vector & conf_en
|
Line 4299 static int ParseConfigFile(dev_config_vector & conf_en
|
} |
} |
|
|
// Not a continuation line. Parse it |
// Not a continuation line. Parse it |
scandevice = ParseConfigLine(conf_entries, entry, contlineno, fullline); | scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline); |
|
|
// did we find a scandevice directive? |
// did we find a scandevice directive? |
if (scandevice==-1) |
if (scandevice==-1) |
Line 4580 static void RegisterDevices(const dev_config_vector &
|
Line 4846 static void RegisterDevices(const dev_config_vector &
|
} |
} |
} |
} |
} |
} |
|
|
|
init_disable_standby_check(configs); |
} |
} |
|
|
|
|
Line 4645 static int main_worker(int argc, char **argv)
|
Line 4913 static int main_worker(int argc, char **argv)
|
// Should we (re)read the config file? |
// Should we (re)read the config file? |
if (firstpass || caughtsigHUP){ |
if (firstpass || caughtsigHUP){ |
if (!firstpass) { |
if (!firstpass) { |
#ifdef __CYGWIN__ |
|
// Workaround for missing SIGQUIT via keyboard on Cygwin |
|
if (caughtsigHUP==2) { |
|
// Simulate SIGQUIT if another SIGINT arrives soon |
|
caughtsigHUP=0; |
|
sleep(1); |
|
if (caughtsigHUP==2) { |
|
caughtsigEXIT=SIGQUIT; |
|
continue; |
|
} |
|
caughtsigHUP=2; |
|
} |
|
#endif |
|
// Write state files |
// Write state files |
if (!state_path_prefix.empty()) |
if (!state_path_prefix.empty()) |
write_all_dev_states(configs, states); |
write_all_dev_states(configs, states); |