~ubuntu-branches/ubuntu/raring/smartmontools/raring

« back to all changes in this revision

Viewing changes to smartd.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Giuseppe Iuculano
  • Date: 2010-07-13 13:16:54 UTC
  • mfrom: (2.2.13 sid)
  • Revision ID: james.westby@ubuntu.com-20100713131654-k5wd1maqujl2uufp
Tags: 5.39.1+svn3124-1
* [1e46e09] Set state and attribute file directory to
  /var/lib/smartmontools/ (Closes: #582158)
* [e20147c] Don't warn about being disabled unless verbose (Closes: #583386)
* [3390c07] Fixed example path in man pages (Closes: #588134)
* [e9583e0] Imported Upstream version 5.39.1+svn3124
* [789e123] Refreshed patches
* [cbecf14] Bump to Standards-Version 3.9.0, no changes needed

Show diffs side-by-side

added added

removed removed

Lines of Context:
126
126
 
127
127
#define ARGUSED(x) ((void)(x))
128
128
 
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;
131
131
 
132
132
extern const char *reportbug;
171
171
                                    ;
172
172
 
173
173
// configuration file name
174
 
#define CONFIGFILENAME "smartd.conf"
175
 
 
176
 
#ifndef _WIN32
177
 
static const char *configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ;
178
 
#else
179
 
static const char *configfile = "./" CONFIGFILENAME ;
180
 
#endif
 
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
305
300
  usage(false),
306
301
  selftest(false),
307
302
  errorlog(false),
 
303
  xerrorlog(false),
308
304
  permissive(false),
309
305
  autosave(0),
310
306
  autoofflinetest(0),
593
589
  setmode(fileno(f), O_TEXT); // Allow files with \r\n
594
590
#endif
595
591
 
 
592
  persistent_dev_state new_state;
596
593
  int good = 0, bad = 0;
597
594
  char line[256];
598
595
  while (fgets(line, sizeof(line), f)) {
599
596
    const char * s = line + strspn(line, " \t");
600
597
    if (!*s || *s == '#')
601
598
      continue;
602
 
    if (!parse_dev_state_line(line, state))
 
599
    if (!parse_dev_state_line(line, new_state))
603
600
      bad++;
604
601
    else
605
602
      good++;
612
609
    }
613
610
    pout("%s: %d invalid line(s) ignored\n", path, bad);
614
611
  }
 
612
 
 
613
  // This sets the values missing in the file to 0.
 
614
  state = new_state;
615
615
  return true;
616
616
}
617
617
 
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());
1480
1482
#endif
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'));
1546
1549
}
1547
1550
 
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)
1551
1555
{
1552
 
  struct ata_smart_errorlog log;
1553
 
  
1554
 
  if (ataReadErrorLog(device, &log, fix_firmwarebug)){
1555
 
    PrintOut(LOG_INFO,"Device: %s, Read SMART Error Log Failed\n",name);
1556
 
    return -1;
1557
 
  }
1558
 
  
1559
 
  // return current number of ATA errors
1560
 
  return log.error_log_pointer?log.ata_error_count:0;
 
1556
  if (!extended) {
 
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);
 
1560
      return -1;
 
1561
    }
 
1562
    return (log.error_log_pointer ? log.ata_error_count : 0);
 
1563
  }
 
1564
  else {
 
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);
 
1568
      return -1;
 
1569
    }
 
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);
 
1572
  }
1561
1573
}
1562
1574
 
1563
1575
// returns <0 if problem.  Otherwise, bottom 8 bits are the self test
1722
1734
 
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         ) {
1806
1819
  }
1807
1820
  
1808
1821
  // capability check: ATA error log
1809
 
  if (cfg.errorlog) {
1810
 
    int val;
 
1822
  if (cfg.errorlog || cfg.xerrorlog) {
1811
1823
 
1812
 
    // start with service disabled, and re-enable it if all works OK
1813
 
    cfg.errorlog = false;
1814
1824
    state.ataerrorcount=0;
1815
 
 
1816
 
    if (!smart_val_ok)
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;
 
1829
    }
1822
1830
    else {
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;
 
1835
      }
 
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;
 
1839
      }
 
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);
 
1844
        }
 
1845
        // Record max error count
 
1846
        state.ataerrorcount = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
 
1847
      }
1825
1848
    }
1826
1849
  }
1827
1850
  
1841
1864
  }
1842
1865
 
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);
1848
1872
    return 3;
1849
1873
  }
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) {
 
2085
    }
 
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.
2072
2097
                   name, newh);
2073
2098
      state.must_write = true;
2074
2099
    }
2075
 
    
 
2100
 
 
2101
    // Print info if error entries have disappeared
 
2102
    if (oldc > newc)
 
2103
      PrintOut(LOG_INFO, "Device: %s, Self-Test Log error count decreased from %d to %d\n",
 
2104
               name, oldc, newc);
 
2105
 
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));
2765
2795
 
2766
2796
  // check if number of ATA errors has increased
2767
 
  if (cfg.errorlog) {
2768
 
 
2769
 
    int newc, oldc= state.ataerrorcount;
2770
 
 
2771
 
    // new number of errors
2772
 
    newc = ATAErrorCount(atadev, name, cfg.fix_firmwarebug);
 
2797
  if (cfg.errorlog || cfg.xerrorlog) {
 
2798
 
 
2799
    int errcnt1 = -1, errcnt2 = -1;
 
2800
    if (cfg.errorlog)
 
2801
      errcnt1 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, false);
 
2802
    if (cfg.xerrorlog)
 
2803
      errcnt2 = read_ata_error_count(atadev, name, cfg.fix_firmwarebug, true);
 
2804
 
 
2805
    // new number of errors is max of both logs
 
2806
    int newc = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
2773
2807
 
2774
2808
    // did command fail?
2775
2809
    if (newc<0)
2777
2811
      MailWarning(cfg, state, 7, "Device: %s, Read SMART Error Log Failed", name);
2778
2812
 
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);
2784
2819
                   name, oldc, newc);
2785
2820
      state.must_write = true;
2786
2821
    }
2787
 
    
2788
 
    // this last line is probably not needed, count always increases
 
2822
 
2789
2823
    if (newc>=0)
2790
2824
      state.ataerrorcount=newc;
2791
2825
  }
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;
3216
3253
    } else {
3217
3254
      badarg = 1;
3218
3255
    }
3504
3541
  }
3505
3542
  
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)) {
3510
3548
    
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);
3720
3758
 
3721
3759
// Parses input line, prints usage message and
3722
3760
// version/license/copyright messages
3723
 
void ParseOpts(int argc, char **argv){
3724
 
  int optchar;
3725
 
  char *tailptr;
3726
 
  long lchecktime;
 
3761
void ParseOpts(int argc, char **argv)
 
3762
{
 
3763
  // Init default configfile path
 
3764
#ifndef _WIN32
 
3765
  configfile = SMARTMONTOOLS_SYSCONFDIR"/smartd.conf";
 
3766
#else
 
3767
  static std::string configfile_str = get_exe_dir() + "/smartd.conf";
 
3768
  configfile = configfile_str.c_str();
 
3769
#endif
 
3770
 
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
3730
3774
                                                          "C"
3731
3775
#endif
3732
3776
                                                             ;
3733
 
  char *arg;
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'
3767
3810
 
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)
3772
 
                )) {
3773
 
    
 
3811
  // Parse input options.
 
3812
  int optchar;
 
3813
  while ((optchar = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
 
3814
    char *arg;
 
3815
    char *tailptr;
 
3816
    long lchecktime;
 
3817
 
3774
3818
    switch(optchar) {
3775
3819
    case 'q':
3776
3820
      // when to quit