From 5ce5706cc7bd40af14ec978e3cc406bb59f5739a Mon Sep 17 00:00:00 2001
From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Sun, 5 Jul 2009 17:16:44 +0000
Subject: [PATCH] smartctl: Add '-l xerror,error' and '-l xselftest,selftest'.

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@2819 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG     |  5 ++++-
 sm5/ataprint.cpp  | 36 +++++++++++++++++++++++++++++-------
 sm5/ataprint.h    |  4 +++-
 sm5/smartctl.8.in | 18 ++++++++++++++----
 sm5/smartctl.cpp  | 40 +++++++++++++++++++++++++++++-----------
 5 files changed, 79 insertions(+), 24 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 3659535c0..6f71441d7 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.815 2009/07/04 23:24:37 manfred99 Exp $
+$Id: CHANGELOG,v 1.816 2009/07/05 17:16:38 chrfranke Exp $
 
 The most recent version of this file is:
 http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup
@@ -41,6 +41,9 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] smartctl: Add '-l xerror,error' and '-l xselftest,selftest' to print
+       the old logs if the extended logs are not supported.
+
   [MS] knowndrives.cpp updates:
        - Western Digital AV-GP series
        - Transcend Solid-State Drive and Transcend Solid-State Drive V series
diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp
index d2e0a0e9a..12363f375 100644
--- a/sm5/ataprint.cpp
+++ b/sm5/ataprint.cpp
@@ -44,7 +44,7 @@
 #include "utility.h"
 #include "knowndrives.h"
 
-const char *ataprint_c_cvsid="$Id: ataprint.cpp,v 1.212 2009/06/20 17:58:33 chrfranke Exp $"
+const char *ataprint_c_cvsid="$Id: ataprint.cpp,v 1.213 2009/07/05 17:16:38 chrfranke Exp $"
 ATACMDNAMES_H_CVSID ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // for passing global control variables
@@ -2151,10 +2151,12 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Print SMART Extendend Comprehensive Error Log
+  bool do_smart_error_log = options.smart_error_log;
   if (options.smart_ext_error_log) {
+    bool ok = false;
     unsigned nsectors = GetNumLogSectors(gplogdir, 0x03, true);
     if (!nsectors)
-      pout("SMART Extended Comprehensive Error Log (GP Log 0x03) does not exist\n");
+      pout("SMART Extended Comprehensive Error Log (GP Log 0x03) not supported\n");
     else if (nsectors >= 256)
       pout("SMART Extended Comprehensive Error Log size %u not supported\n", nsectors);
     else {
@@ -2162,13 +2164,22 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       ata_smart_exterrlog * log_03 = (ata_smart_exterrlog *)log_03_buf.data();
       if (!ataReadExtErrorLog(device, log_03, nsectors))
         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-      else
+      else {
         PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log);
+        ok = true;
+      }
+    }
+
+    if (!ok) {
+      if (options.retry_error_log)
+        do_smart_error_log = true;
+      else if (!do_smart_error_log)
+        pout("Try '-l [xerror,]error' to read traditional SMART Error Log\n");
     }
   }
 
   // Print SMART error log
-  if (options.smart_error_log) {
+  if (do_smart_error_log) {
     if (!isSmartErrorLogCapable(&smartval, &drive)){
       pout("Warning: device does not support Error Logging\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
@@ -2186,10 +2197,12 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Print SMART Extendend Self-test Log
+  bool do_smart_selftest_log = options.smart_selftest_log;
   if (options.smart_ext_selftest_log) {
+    bool ok = false;
     unsigned nsectors = GetNumLogSectors(gplogdir, 0x07, true);
     if (!nsectors)
-      pout("SMART Extended Self-test Log (GP Log 0x07) does not exist\n");
+      pout("SMART Extended Self-test Log (GP Log 0x07) not supported\n");
     else if (nsectors >= 256)
       pout("SMART Extended Self-test Log size %u not supported\n", nsectors);
     else {
@@ -2197,13 +2210,22 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       ata_smart_extselftestlog * log_07 = (ata_smart_extselftestlog *)log_07_buf.data();
       if (!ataReadExtSelfTestLog(device, log_07, nsectors))
         failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-      else
+      else {
         PrintSmartExtSelfTestLog(log_07, nsectors, options.smart_ext_selftest_log);
+        ok = true;
+      }
+    }
+
+    if (!ok) {
+      if (options.retry_selftest_log)
+        do_smart_selftest_log = true;
+      else if (!do_smart_selftest_log)
+        pout("Try '-l [xselftest,]selftest' to read traditional SMART Self Test Log\n");
     }
   }
 
   // Print SMART self-test log
-  if (options.smart_selftest_log) {
+  if (do_smart_selftest_log) {
     if (!isSmartTestLogCapable(&smartval, &drive)){
       pout("Warning: device does not support Self Test Logging\n");
       failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
diff --git a/sm5/ataprint.h b/sm5/ataprint.h
index d672fadfe..404cb398f 100644
--- a/sm5/ataprint.h
+++ b/sm5/ataprint.h
@@ -26,7 +26,7 @@
 #ifndef ATAPRINT_H_
 #define ATAPRINT_H_
 
-#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.41 2009/06/20 17:58:33 chrfranke Exp $\n"
+#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.42 2009/07/05 17:16:38 chrfranke Exp $\n"
 
 #include <vector>
 
@@ -58,6 +58,7 @@ struct ata_print_options
   bool gp_logdir, smart_logdir;
   unsigned smart_ext_error_log;
   unsigned smart_ext_selftest_log;
+  bool retry_error_log, retry_selftest_log;
 
   std::vector<ata_log_request> log_requests;
 
@@ -99,6 +100,7 @@ struct ata_print_options
       gp_logdir(false), smart_logdir(false),
       smart_ext_error_log(0),
       smart_ext_selftest_log(0),
+      retry_error_log(false), retry_selftest_log(false),
       sct_temp_sts(false), sct_temp_hist(false),
       sataphy(false), sataphy_reset(false),
       smart_disable(false), smart_enable(false),
diff --git a/sm5/smartctl.8.in b/sm5/smartctl.8.in
index 3c2f74088..984f8b31e 100644
--- a/sm5/smartctl.8.in
+++ b/sm5/smartctl.8.in
@@ -1,7 +1,7 @@
 .ig
  Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
- $Id: smartctl.8.in,v 1.131 2009/06/29 19:56:19 chrfranke Exp $
+ $Id: smartctl.8.in,v 1.132 2009/07/05 17:16:38 chrfranke Exp $
  
  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 the Free
@@ -833,7 +833,7 @@ receives a command which is not implemented or is not valid.
 \- [SCSI] prints the error counter log pages for reads, write and verifies.
 The verify row is only output if it has an element other than zero.
 
-.I xerror[,NUM]
+.I xerror[,NUM][,error]
 \- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints the Extended
 Comprehensive SMART error log (General Purpose Log address 0x03).
 Unlike the Summary SMART error log (see \'\-l error\' above),
@@ -846,6 +846,13 @@ are 2 (Samsung), 5 (Seagate) or 6 (WD).
 If the optional parameter NUM is specified, only the NUM most
 recent log entries are printed.  Otherwise, all entries are printed.
 
+If ',error' is appended and the Extended Comprehensive SMART error
+log is not supported, the Summary SMART self-test log is printed.
+
+Please note that some recent (e.g. Samsung) drives report errors only
+in the Comprehensive SMART error log. The Summary SMART error log can
+be read but is always empty.
+
 .I selftest
 \- [ATA] prints the SMART self\-test log.  The disk maintains a self\-test
 log showing the results of the self tests, which can be run using the
@@ -882,7 +889,7 @@ Additional Sense Code Qualifier (ASQ) are also printed. The self tests
 can be run using the \'\-t\' option described below (using the ATA
 test terminology).
 
-.I xselftest[,NUM]
+.I xselftest[,NUM][,selftest]
 \- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] prints the Extended
 SMART self\-test log (General Purpose Log address 0x07). Unlike the SMART
 self\-test log (see \'\-l selftest\' above), it supports 48-bit LBA
@@ -893,6 +900,9 @@ values are 1 (Seagate) or 2 (Samsung).
 If the optional parameter NUM is specified, only the NUM most
 recent log entries are printed.  Otherwise, all entries are printed.
 
+If ',selftest' is appended and the Extended SMART self-test log is not
+supported, the old SMART self-test log is printed.
+
 .I selective
 \- [ATA only] Please see the \'\-t select\' option below for a
 description of selective self\-tests.  The selective self\-test log
@@ -1743,7 +1753,7 @@ these documents may be found in the References section of the
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartctl.8.in,v 1.131 2009/06/29 19:56:19 chrfranke Exp $
+$Id: smartctl.8.in,v 1.132 2009/07/05 17:16:38 chrfranke Exp $
 .\" Local Variables:	         
 .\" mode: nroff         
 .\" End:
diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp
index 0d40dec20..62952c057 100644
--- a/sm5/smartctl.cpp
+++ b/sm5/smartctl.cpp
@@ -63,7 +63,7 @@ extern const char *os_solaris_ata_s_cvsid;
 extern const char *cciss_c_cvsid;
 #endif
 extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid;
-const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.200 2009/06/21 02:39:32 dpgilbert Exp $"
+const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.201 2009/07/05 17:16:44 chrfranke Exp $"
 ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
 
 // This is a block containing all the "control variables".  We declare
@@ -168,9 +168,9 @@ void Usage (void){
 "  -l TYPE, --log=TYPE\n"
 "        Show device log. TYPE: error, selftest, selective, directory[,g|s],\n"
 "                               background, sasphy[,reset], sataphy[,reset],\n"
-"                               scttemp[sts,hist],gplog,N[,RANGE],\n"
-"                               smartlog,N[,RANGE],\n"
-"                               xerror[,N], xselftest[,N]\n\n"
+"                               scttemp[sts,hist],\n"
+"                               gplog,N[,RANGE], smartlog,N[,RANGE],\n"
+"                               xerror[,N][,error], xselftest[,N][,selftest]\n\n"
 "  -v N,OPTION , --vendorattribute=N,OPTION                            (ATA)\n"
 "        Set display OPTION for vendor Attribute N (see man page)\n\n"
 "  -F TYPE, --firmwarebug=TYPE                                         (ATA)\n"
@@ -226,7 +226,7 @@ static const char *getvalidarglist(char opt)
   case 'l':
     return "error, selftest, selective, directory[,g|s], background, scttemp[sts|hist], "
            "sasphy[,reset], sataphy[,reset], gplog,N[,RANGE], smartlog,N[,RANGE], "
-	   "xerror[,N], xselftest[,N]";
+	   "xerror[,N][,error], xselftest[,N][,selftest]";
   case 'P':
     return "use, ignore, show, showall";
   case 't':
@@ -483,17 +483,35 @@ const char * parse_options(int argc, char** argv,
       } else if (!strcmp(optarg,"scttemphist")) {
         ataopts.sct_temp_hist = true;
 
-      } else if (   !strncmp(optarg,"xerror"   , sizeof("xerror"   )-1)
-                 || !strncmp(optarg,"xselftest", sizeof("xselftest")-1)) {
+      } else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) {
         int n1 = -1, n2 = -1, len = strlen(optarg);
         unsigned val = ~0U;
-        sscanf(optarg, "%*[a-z]%n,%u%n", &n1, &val, &n2);
-        if (!((n1 == len || n2 == len) && val > 0))
-          badarg = true;
-        else if (optarg[1] == 'e')
+        sscanf(optarg, "xerror%n,error%n", &n1, &n2);
+        if (!(n1 == len || n2 == len)) {
+          n1 = n2 = -1;
+          sscanf(optarg, "xerror,%u%n,error%n", &val, &n1, &n2);
+        }
+        if ((n1 == len || n2 == len) && val > 0) {
           ataopts.smart_ext_error_log = val;
+          ataopts.retry_error_log = (n2 == len);
+        }
         else
+          badarg = true;
+
+      } else if (!strncmp(optarg, "xselftest", sizeof("xselftest")-1)) {
+        int n1 = -1, n2 = -1, len = strlen(optarg);
+        unsigned val = ~0U;
+        sscanf(optarg, "xselftest%n,selftest%n", &n1, &n2);
+        if (!(n1 == len || n2 == len)) {
+          n1 = n2 = -1;
+          sscanf(optarg, "xselftest,%u%n,selftest%n", &val, &n1, &n2);
+        }
+        if ((n1 == len || n2 == len) && val > 0) {
           ataopts.smart_ext_selftest_log = val;
+          ataopts.retry_selftest_log = (n2 == len);
+        }
+        else
+          badarg = true;
 
       } else if (   !strncmp(optarg, "gplog,"   , sizeof("gplog,"   )-1)
                  || !strncmp(optarg, "smartlog,", sizeof("smartlog,")-1)) {
-- 
GitLab