Diff for /embedaddon/smartmontools/smartd.cpp between versions 1.1.1.1 and 1.1.1.2

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);

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>