From 28680ea2738d94b938b1e6a9357c55853dca7df2 Mon Sep 17 00:00:00 2001
From: chrfranke <chrfranke@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Sat, 19 Dec 2009 15:25:27 +0000
Subject: [PATCH] Add '-v ID,FORMAT:BYTEORDER[,NAME]' to specify byte order of
 attribute raw value.

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@3001 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 smartmontools/CHANGELOG        |  3 ++
 smartmontools/NEWS             |  1 +
 smartmontools/atacmds.cpp      | 80 ++++++++++++++++++++++------------
 smartmontools/atacmds.h        |  8 ++--
 smartmontools/ataprint.cpp     | 14 +++---
 smartmontools/smartctl.8.in    | 22 +++++++---
 smartmontools/smartd.8.in      |  6 +--
 smartmontools/smartd.conf.5.in |  6 +--
 8 files changed, 93 insertions(+), 47 deletions(-)

diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG
index 26a7c3849..1797f7256 100644
--- a/smartmontools/CHANGELOG
+++ b/smartmontools/CHANGELOG
@@ -43,6 +43,9 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [CF] Add '-v ID,FORMAT:BYTEORDER[,NAME]' to specify byte order
+       of attribute raw value.
+
   [CF] configure.in: Change --with-docdir default from
        'PREFIX/share/doc/smartmontools-VERSION' to
        'DATADIR/doc/smartmontools' to make it consistent with
diff --git a/smartmontools/NEWS b/smartmontools/NEWS
index 1474c6c78..9b04f65dc 100644
--- a/smartmontools/NEWS
+++ b/smartmontools/NEWS
@@ -8,6 +8,7 @@ http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontool
 Date <Not released yet, please try current SVN>
 Summary: smartmontools release 5.40
 -----------------------------------------------------------
+- Option '-v' allows to specify byte order of attribute raw value
 - configure: New default value for '--with-docdir'.
 - Drive database is in a separate source file 'drivedb.h'
   which can be downloaded from SVN.
diff --git a/smartmontools/atacmds.cpp b/smartmontools/atacmds.cpp
index c218cf0a2..6dc02ebf4 100644
--- a/smartmontools/atacmds.cpp
+++ b/smartmontools/atacmds.cpp
@@ -271,6 +271,19 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
     flags = ATTRFLAG_INCREASING;
   }
 
+  // Split "format[:byteorder]"
+  char byteorder[8+1] = "";
+  if (strchr(fmtname, ':')) {
+    if (!(   sscanf(fmtname, "%*[^:]%n:%8[012345rvwz]%n", &n1, byteorder, &n2) >= 1
+          && n2 == (int)strlen(fmtname)))
+      return false;
+    fmtname[n1] = 0;
+    if (strchr(byteorder, 'v'))
+      flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL);
+    if (strchr(byteorder, 'w'))
+      flags |= ATTRFLAG_NO_WORSTVAL;
+  }
+
   // Find format name
   for (i = 0; ; i++) {
     if (i >= num_format_names)
@@ -280,9 +293,9 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
   }
   ata_attr_raw_format format = format_names[i].format;
 
-  // 64-bit formats use the normalized value bytes.
-  if (format == RAWFMT_RAW64 || format == RAWFMT_HEX64)
-    flags |= ATTRFLAG_NO_NORMVAL;
+  // 64-bit formats use the normalized and worst value bytes.
+  if (!*byteorder && (format == RAWFMT_RAW64 || format == RAWFMT_HEX64))
+    flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL);
 
   if (!id) {
     // "N,format" -> set format for all entries
@@ -294,6 +307,7 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
       defs[i].priority = priority;
       defs[i].raw_format = format;
       defs[i].flags = flags;
+      strcpy(defs[i].byteorder, byteorder);
     }
   }
   else if (defs[id].priority <= priority) {
@@ -303,6 +317,7 @@ bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
     defs[id].raw_format = format;
     defs[id].priority = priority;
     defs[id].flags = flags;
+    strcpy(defs[id].byteorder, byteorder);
   }
 
   return true;
@@ -317,7 +332,7 @@ std::string create_vendor_attribute_arg_list()
   std::string s;
   unsigned i;
   for (i = 0; i < num_format_names; i++)
-    s += strprintf("%s\tN,%s[,ATTR_NAME]",
+    s += strprintf("%s\tN,%s[:012345rvwz][,ATTR_NAME]",
       (i>0 ? "\n" : ""), format_names[i].name);
   for (i = 0; i < num_old_vendor_opts; i++)
     s += strprintf("\n\t%s", map_old_vendor_opts[i][0]);
@@ -1736,8 +1751,8 @@ ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
   if (attr.current <= thre.threshold)
     return ATTRSTATE_FAILED_NOW;
 
-  // Failed in the passed if worst value is below threshold
-  if (attr.worst <= thre.threshold)
+  // Failed in the past if worst value is below threshold
+  if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL) && attr.worst <= thre.threshold)
     return ATTRSTATE_FAILED_PAST;
 
   return ATTRSTATE_OK;
@@ -1767,24 +1782,36 @@ static ata_attr_raw_format get_default_raw_format(unsigned char id)
 uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
                                 const ata_vendor_attr_defs & defs)
 {
-  // Get 48 bit raw value
-  const unsigned char * raw = attr.raw;
-  uint64_t rawvalue;
-  rawvalue =              raw[0]
-             | (          raw[1] <<  8)
-             | (          raw[2] << 16)
-             | ((uint64_t)raw[3] << 24)
-             | ((uint64_t)raw[4] << 32)
-             | ((uint64_t)raw[5] << 40);
-
-  if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL) {
-    // Some SSD vendors use bytes 3-10 from the Attribute
-    // Data Structure to store a 64-bit raw value.
-    rawvalue <<= 8;
-    rawvalue |= attr.worst;
-    rawvalue <<= 8;
-    rawvalue |= attr.current;
+  const ata_vendor_attr_defs::entry & def = defs[attr.id];
+
+  // Use default byteorder if not specified
+  const char * byteorder = def.byteorder;
+  if (!*byteorder) {
+    if (def.raw_format == RAWFMT_RAW64 || def.raw_format == RAWFMT_HEX64)
+      byteorder = "543210wv";
+    else
+      byteorder = "543210";
+  }
+
+  // Build 64-bit value from selected bytes
+  uint64_t rawvalue = 0;
+  for (int i = 0; byteorder[i]; i++) {
+    unsigned char b;
+    switch (byteorder[i]) {
+      case '0': b = attr.raw[0];  break;
+      case '1': b = attr.raw[1];  break;
+      case '2': b = attr.raw[2];  break;
+      case '3': b = attr.raw[3];  break;
+      case '4': b = attr.raw[4];  break;
+      case '5': b = attr.raw[5];  break;
+      case 'r': b = attr.reserv;  break;
+      case 'v': b = attr.current; break;
+      case 'w': b = attr.worst;   break;
+      default : b = 0;            break;
+    }
+    rawvalue <<= 8; rawvalue |= b;
   }
+
   return rawvalue;
 }
 
@@ -1793,7 +1820,7 @@ uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
 std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
                                       const ata_vendor_attr_defs & defs)
 {
-  // Get 48 bit or64 bit raw value
+  // Get 48 bit or 64 bit raw value
   uint64_t rawvalue = ata_get_attr_raw_value(attr, defs);
 
   // Get 16 bit words
@@ -1821,6 +1848,7 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
     break;
 
   case RAWFMT_RAW48:
+  case RAWFMT_RAW64:
     s = strprintf("%"PRIu64, rawvalue);
     break;
 
@@ -1828,10 +1856,6 @@ std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
     s = strprintf("0x%012"PRIx64, rawvalue);
     break;
 
-  case RAWFMT_RAW64:
-    s = strprintf("%"PRIu64, rawvalue);
-    break;
-
   case RAWFMT_HEX64:
     s = strprintf("0x%016"PRIx64, rawvalue);
     break;
diff --git a/smartmontools/atacmds.h b/smartmontools/atacmds.h
index 8d5279d35..f5b8becaa 100644
--- a/smartmontools/atacmds.h
+++ b/smartmontools/atacmds.h
@@ -656,8 +656,9 @@ enum ata_attr_raw_format
 
 // Attribute flags
 enum {
-  ATTRFLAG_INCREASING = 0x01, // Value not reset (for reallocated/pending counts)
-  ATTRFLAG_NO_NORMVAL = 0x02  // Normalized value not valid
+  ATTRFLAG_INCREASING = 0x01,   // Value not reset (for reallocated/pending counts)
+  ATTRFLAG_NO_NORMVAL = 0x02,   // Normalized value not valid
+  ATTRFLAG_NO_WORSTVAL = 0x04   // Worst value not valid
 };
 
 // Vendor attribute display defs for all attribute ids
@@ -670,12 +671,13 @@ public:
     ata_attr_raw_format raw_format; // Raw value print format
     ata_vendor_def_prior priority; // Setting priority
     unsigned flags; // ATTRFLAG_*
+    char byteorder[8+1]; // String [012345rvwz] to define byte order
 
     entry()
       : raw_format(RAWFMT_DEFAULT),
         priority(PRIOR_DEFAULT),
         flags(0)
-      { }
+      { byteorder[0] = 0; }
   };
 
   entry & operator[](unsigned char id)
diff --git a/smartmontools/ataprint.cpp b/smartmontools/ataprint.cpp
index 258c11f10..4bf3f6cfc 100644
--- a/smartmontools/ataprint.cpp
+++ b/smartmontools/ataprint.cpp
@@ -836,11 +836,15 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data,
     }
 
     // Format value, worst, threshold
-    std::string valstr, threstr;
+    std::string valstr, worstr, threstr;
     if (state > ATTRSTATE_NO_NORMVAL)
-      valstr = strprintf("%.3d   %.3d", attr.current, attr.worst);
+      valstr = strprintf("%.3d", attr.current);
     else
-      valstr = "---   ---";
+      valstr = "---";
+    if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL))
+      worstr = strprintf("%.3d", attr.worst);
+    else
+      worstr = "---";
     if (state > ATTRSTATE_NO_THRESHOLD)
       threstr = strprintf("%.3d", thre.threshold);
     else
@@ -848,9 +852,9 @@ static void PrintSmartAttribWithThres(const ata_smart_values * data,
 
     // Print line for each valid attribute
     std::string attrname = ata_get_smart_attr_name(attr.id, defs);
-    pout("%3d %-24s0x%04x   %-9s   %-3s    %-10s%-9s%-12s%s\n",
+    pout("%3d %-24s0x%04x   %-3s   %-3s   %-3s    %-10s%-9s%-12s%s\n",
          attr.id, attrname.c_str(), attr.flags,
-         valstr.c_str(), threstr.c_str(),
+         valstr.c_str(), worstr.c_str(), threstr.c_str(),
          (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags)? "Pre-fail" : "Old_age"),
          (ATTRIBUTE_FLAGS_ONLINE(attr.flags)? "Always" : "Offline"),
          (state == ATTRSTATE_FAILED_NOW  ? "FAILING_NOW" :
diff --git a/smartmontools/smartctl.8.in b/smartmontools/smartctl.8.in
index 769217f64..fc814c5c7 100644
--- a/smartmontools/smartctl.8.in
+++ b/smartmontools/smartctl.8.in
@@ -1017,14 +1017,26 @@ writes a binary representation of the one sector log 0x11
 (SATA Phy Event Counters) to file log.bin.
 
 .TP
-.B \-v ID,FORMAT[,NAME], \-\-vendorattribute=ID,FORMAT[,NAME]
-[ATA only] Sets a vendor\-specific raw value print FORMAT and
-optional NAME for Attribute ID.
+.B \-v ID,FORMAT[:BYTEORDER][,NAME], \-\-vendorattribute=ID,FORMAT[:BYTEORDER][,NAME]
+[ATA only] Sets a vendor\-specific raw value print FORMAT, an optional
+BYTEORDER and an optional NAME for Attribute ID.
 This option may be used multiple times.
 
 The Attribute ID can be in the range 1 to 255. If \'N\' is specified as
-ID, the settings for all Attributes are changed. The NAME is a string of
-letters, digits and underscore.
+ID, the settings for all Attributes are changed.
+
+The optional BYTEORDER consists of 1 to 8 characters from the
+set \'012345rvwz\'. The characters \'0\' to \'5\' select the byte 0
+to 5 from the 48\-bit raw value, \'r\' selects the reserved byte of
+the attribute data block, \'v\' selects the normalized value, \'w\'
+selects the worst value and \'z\' inserts a zero byte.
+The default BYTEORDER is \'543210\' for all 48-bit formats,
+and \'543210wv\' for the 64-bit formats.
+For example, \'\-v 5,raw48:012345\' prints the raw value of
+attribute 5 with big endian instead of little endian
+byte ordering.
+
+The NAME is a string of letters, digits and underscore.
 
 .I \-v help
 \- Prints (to STDOUT) a list of all valid arguments to this option,
diff --git a/smartmontools/smartd.8.in b/smartmontools/smartd.8.in
index 177dd989c..619f45285 100644
--- a/smartmontools/smartd.8.in
+++ b/smartmontools/smartd.8.in
@@ -1605,9 +1605,9 @@ values for \'\-F\' (see the \'\-P\' option below).
 [Please see the \fBsmartctl \-F\fP command-line option.]
 
 .TP
-.B \-v ID,FORMAT[,NAME]
-[ATA only] Sets a vendor\-specific raw value print FORMAT and
-optional NAME for Attribute ID.
+.B \-v ID,FORMAT[:BYTEORDER][,NAME]
+[ATA only] Sets a vendor\-specific raw value print FORMAT, an optional
+BYTEORDER and an optional NAME for Attribute ID.
 This directive may be used multiple times.
 Please see \fBsmartctl -v\fP command-line option for further details.
 
diff --git a/smartmontools/smartd.conf.5.in b/smartmontools/smartd.conf.5.in
index 7038c7e1d..78c7e5d4c 100644
--- a/smartmontools/smartd.conf.5.in
+++ b/smartmontools/smartd.conf.5.in
@@ -1167,9 +1167,9 @@ values for \'\-F\' (see the \'\-P\' option below).
 [Please see the \fBsmartctl \-F\fP command-line option.]
 
 .TP
-.B \-v ID,FORMAT[,NAME]
-[ATA only] Sets a vendor\-specific raw value print FORMAT and
-optional NAME for Attribute ID.
+.B \-v ID,FORMAT[:BYTEORDER][,NAME]
+[ATA only] Sets a vendor\-specific raw value print FORMAT, an optional
+BYTEORDER and an optional NAME for Attribute ID.
 This directive may be used multiple times.
 Please see \fBsmartctl -v\fP command-line option for further details.
 
-- 
GitLab