]> git.proxmox.com Git - mirror_smartmontools-debian.git/commitdiff
Imported Upstream version 5.38+svn2993
authorGiuseppe Iuculano <iuculano@debian.org>
Wed, 9 Dec 2009 16:12:33 +0000 (17:12 +0100)
committerGiuseppe Iuculano <iuculano@debian.org>
Wed, 9 Dec 2009 16:12:33 +0000 (17:12 +0100)
25 files changed:
CHANGELOG
INSTALL
NEWS
TODO
atacmds.cpp
atacmds.h
ataprint.cpp
ataprint.h
configure.in
dev_interface.cpp
dev_interface.h
dev_legacy.cpp
do_release
knowndrives.cpp
knowndrives.h
os_freebsd.cpp
os_linux.cpp
os_win32.cpp
scsiata.cpp
smartctl.8.in
smartctl.cpp
smartd.8.in
smartd.conf.5.in
smartd.cpp
utility.cpp

index dfe745f6c7a4f26eae5acd980c6f1fdf233521ce..87a7ffc49756c6df7eeabca3628a4a45c109f023 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG 2951 2009-10-08 23:43:46Z samm2 $
+$Id: CHANGELOG 2993 2009-12-04 17:29:50Z chrfranke $
 
 The most recent version of this file is:
 http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontools/CHANGELOG?view=markup
@@ -43,8 +43,107 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
-  [AS] Linux: Autodetect DELL PERC and MegaRAID controllers. 
-       Hiding debug messages coming from megaraid code.  
+  [CF] Linux: Add workaround for Adaptec series 2, 5 and 5Z controllers
+       with firmware >= 17380.  Patch was provided by Phil Wilson, see:
+       http://linux.adaptec.com/2009/07/24/using-smartmontools-538-with-series-255z-controllers-with-firmware-17380-onwards
+
+  [CF] configure.in: Add '-fno-strict-aliasing' to CXXFLAGS if supported.
+       This suppresses gcc 4.4.1 warnings on Linux and avoids possible
+       unsafe optimizations (ticket #23).
+       Patch was provided by Manfred Schwarb.
+
+  [CF] Avoid truncation of configure arguments in '-V' output.
+
+  [AS] Added USB IDs of WD Passport USB Portable
+
+  [CF] Linux: Fix segfault in 3ware interface (ticket #22).
+
+  [MS] knowndrives.cpp updates:
+       - Hitachi Deskstar 7K2000
+       - Seagate Momentus 7200 FDE.2 series
+
+  [CF] Add USB ID of WD My Passport 070A.
+       knowndrives.cpp update:
+       - WD My Passport hard drive (USB interface)
+
+  [CF] smartd: Write 'worst' attribute value to '.state' file also.
+       This allows to use state persistence with 'raw64' attributes.
+
+  [CF] Rework ATA SMART attribute check in smartctl and smartd.
+       smartd: Ignore normalized attribute value and threshold
+       if 'raw64' or 'hex64' format is selected.
+
+  [CF] Add USB IDs of Iomega LPHD080-0, 2 Genesys Logic bridges and
+       Initio 316000.
+
+  [MS] knowndrives.cpp update: Hitachi Travelstar 5K320 series
+
+  [CF] smartctl: Ignore normalized attribute value and threshold
+       if 'raw64' or 'hex64' format is selected.
+
+  [CF] knowndrives.cpp updates:
+       - add OCZ-Vertex raw64 attributes
+       - add OCZ-Agility
+       Thanks to Marcin Marszalek for the patch.
+
+  [CF] Add '-v ID,hex*' print formats. Fix '-v N,FORMAT,NAME' parsing.
+
+  [CF] Add '-v ID,raw64[,...]' print format based on a patch provided
+       by Marcin Marszalek.
+
+  [CF] Add '-v ID,RAW_FORMAT[,ATTR_NAME]' option. This allows to add new
+       attributes without the need to enhance the '-v' option.
+       Rework attribute name and raw value formatting.
+
+  [CF] Fix auto_ptr initialization in linux_scsi_device::autodetect_open().
+
+  [CF] Remove duplicate function smart_device_list::add().
+       Replace calls with push_back().
+
+  [MS] attribute update:
+       trim attribute names to 23 chars
+
+  [CF] Add smart pointer class template to manage device object pointers.
+       Remove related 'delete' calls and 'try/catch' blocks.
+
+  [CF] do_release: Replace generation of '*.asc' by '*.md5' and '*.sha1'.
+
+  [MS] attribute updates:
+       - change attributes 202,204,205 to the meanings as found in wdidle3.exe
+         retain old entries as comments (possible Fujitsu use)
+       - add attribute 240 as found in Fujitsu MHY2xxxBH
+
+  [MS] attributes updates:
+       - attributes 225, 232 and 233 for Intel X25-E SSD
+       - non-conflicting attributes extracted from wdidle3.exe
+         (thanks to Franc Zabkar and Dan Lukes)
+
+  [CF] Update Windows and ./configure info in INSTALL file.
+
+  [CF] Update 'do_release' script for SVN.
+
+  [MS] knowndrives.cpp updates:
+       - Western Digital MyPassport Essential hard drive (USB interface)
+       - Seagate Momentus 7200.4 series
+       - Western Digital Raptor X
+       - Intel X25-E SSD
+
+  [CF] knowndrives.cpp updates:
+       - New Seagate 7200.11 firmware version
+       - Update IBM link
+
+  [CF] smartctl: Use printf() instead of pout() for exception error
+       messages to avoid access to bogus 'con->dont_print'.
+
+  [CF] smartd: Add missing help texts for '-A', '-B' and '-s'.
+
+  [CF] Add missing check for log page 0x11 support to smartctl
+       '-l sataphy' option.
+
+  [CF] Add USB ID of Freecom Hard Drive XS.
+
+  [AS] Linux: Autodetect DELL PERC and MegaRAID controllers.
+       Hiding debug messages coming from megaraid code.
 
   [AS] Linux: Fixed SATA drives support on megaraid device (see ticket #15).
 
@@ -57,7 +156,7 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
   [AS] FreeBSD: cam_get_umassno rewritten using XPT_PATH_INQ
 
-  [AS] FreeBSD: do not open/close cam device on every request for SCSI 
+  [AS] FreeBSD: do not open/close cam device on every request for SCSI
        disks. Use com->camdev both for SCSI and ATAPICAM.
 
   [AS] FreeBSD: added support for the ada disks, based on agapon patch
diff --git a/INSTALL b/INSTALL
index 7af41e33a91a5e260d9f9227419f94096159213a..dae2f24be85671026e30a7187de57950d410799c 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
 Smartmontools installation instructions
 =======================================
 
-$Id: INSTALL 2925 2009-10-02 20:45:54Z chrfranke $
+$Id: INSTALL 2967 2009-10-23 21:45:56Z chrfranke $
 
 Please also see the smartmontools home page:
 http://smartmontools.sourceforge.net/
@@ -102,8 +102,8 @@ Table of contents:
 
     E) Cygwin
 
-    The code was tested on Cygwin 1.5.7, 1.5.11 and 1.5.18-22. It should
-    also work on other recent releases.
+    The code was tested on Cygwin 1.5.25-15 and 1.7.0-62. It should also
+    work on other recent releases.
 
     Release 1.5.15 or later is recommended for Cygwin smartd. Older versions
     do not provide syslogd support.
@@ -114,9 +114,10 @@ Table of contents:
 
     F) Windows
 
-    The code was tested on Windows 98SE, NT4(SP5,SP6), 2000(SP4),
-    XP(no SP,SP1a,SP2) and Vista RC 1. It should also work on Windows
-    95(OSR2), 98, ME and 2003.
+    The code was tested on Windows 98SE, ME, NT4(SP5,SP6), 2000(SP4),
+    XP(up to SP3), 2003 and Vista.
+
+    -- Windows 9x/ME
 
     On 9x/ME, only standard (legacy) IDE/ATA devices 0-3 are supported.
     The driver SMARTVSD.VXD must be present in WINDOWS\SYSTEM\IOSUBSYS
@@ -124,13 +125,10 @@ Table of contents:
     installation of some versions of Windows is the WINDOWS\SYSTEM folder.
     In this case, move SMARTVSD.VXD to WINDOWS\SYSTEM\IOSUBSYS and reboot
     (http://support.microsoft.com/kb/265854/en-us).
-    SMARTVSD.VXD may also be missing in a new installation
-    (http://support.microsoft.com/kb/199886/en-us).
 
     SMARTVSD.VXD relies on the standard IDE port driver ESDI_506.PDR.
     If the system uses a vendor specific driver, access of SMART data
-    is not possible on 9x/ME. This is the case if e.g. the optional
-    "IDE miniport driver" is installed on a system with VIA chipset.
+    is not possible.
 
     Some ATA controllers (e.g. Promise) provided a custom SMARTVSD.VXD
     for their Win9x/ME driver. To access SMART data from both the legacy
@@ -139,21 +137,22 @@ Table of contents:
     all occurrences of the string "SMARTVSD" with "SMARTVSE". Then reinstall
     the original Windows SMARTVSD.VXD.
 
-    On NT4/2000/XP/2003, ATA or SATA devices are supported if the device
-    driver implements the SMART IOCTL.
+    To access SCSI and USB devices, an installed ASPI interface (WNASPI32.DLL)
+    is required. The code was tested with Adaptec Windows ASPI drivers 4.71.2.
+    (http://www.adaptec.com/en-US/support/_eol/scsi_sw/ASPI-4.70/)
+    Links to other ASPI drivers can be found at http://www.nu2.nu/aspi/.
+
+    -- Windows NT4/2000/XP/2003/Vista
 
-    The IDE/ATA read log command (smartctl -l, --log, -a, --all) is
-    not supported by the SMART IOCTL of NT4/2000/XP. Undocumented
-    and possibly buggy system calls are used for this purpose,
-    see WARNINGS file for details.
+    ATA or SATA devices are supported if the device driver implements
+    the SMART IOCTLs or IOCTL_IDE_PASS_THROUGH or IOCTL_ATA_PASS_THROUGH.
+    The ATA SMART READ LOG command (smartctl -l, --log, -a, --all) is not
+    supported if only the SMART IOCTLs are implemented.
 
-    SCSI devices are supported on all versions of Windows. An installed
-    ASPI interface (WNASPI32.DLL) is required to access SCSI devices.
-    The code was tested with Adaptec Windows ASPI drivers 4.71.2.
-    (http://www.adaptec.com/en-US/support/scsi_soft/ASPI/ASPI-4.70/)
-    Links to other ASPI drivers can be found at http://www.nu2.nu/aspi/.
+    SCSI and USB devices are accessed through SPTI. Special driver support
+    is not required.
 
-    3ware 9000 RAID controllers are supported using new features available
+    3ware 9000 RAID controllers are supported using features available
     in the Windows driver release 9.4.0 (3wareDrv.sys 3.0.2.70) or later.
     Older drivers provide SMART access to the first physical drive (port)
     of each logical drive (unit). If driver support is not available
@@ -669,9 +668,11 @@ OPTIONS              DEFAULT                                      AFFECTS
                                                                   nodes for 3ware/AMCC controllers, this option ensures that the nodes are created
                                                                   with correct SELinux file contexts.
 --enable-drivedb      --disable-drivedb                           Enables default drive database file '${drivedbdir}/drivedb.h'
---with-drivedbdir     ${prefix}/share/smartmontools/drivedb.h     Directory for 'drivedb.h' (specifying this option implies --enable-drivedb)
+--with-drivedbdir     ${prefix}/share/smartmontools               Directory for 'drivedb.h' (implies --enable-drivedb)
 --enable-savestates   --disable-savestates                        Enables default smartd state files '${savestates}MODEL-SERIAL.ata.state'
---with-savestates     ${prefix}/var/lib/smartmontools/smartd.     Prefix for smartd state files (specifying this option implies --enable-savestates)
+--with-savestates     ${prefix}/var/lib/smartmontools/smartd.     Prefix for smartd state files (implies --enable-savestates)
+--enable-attributelog --disable-attributelog                      Enables default smartd attribute log files
+--with-attributelog   ${prefix}/var/lib/smartmontools/attrlog.    Prefix for smartd attribute log files (implies --enable-attributelog)
 
 Here's an example:
 If you set --prefix=/home/joe and none of the other four
diff --git a/NEWS b/NEWS
index 4cc0395783ee2382039f22b8abab77364afc9a10..d15a51cd7b772cc7329af686e2f9511fe64b91cf 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,6 @@
 smartmontools NEWS
 ------------------
-$Id: NEWS 2956 2009-10-11 00:21:15Z samm2 $
+$Id: NEWS 2989 2009-11-30 20:17:14Z chrfranke $
 
 The most up-to-date version of this file is:
 http://smartmontools.svn.sourceforge.net/viewvc/smartmontools/trunk/smartmontools/NEWS?view=markup
@@ -10,8 +10,8 @@ Summary: smartmontools release 5.39 (UNSTABLE/EXPERIMENTAL)
 -----------------------------------------------------------
 - Sourcecode repository moved from CVS to SVN
 - Support for USB devices with Cypress, JMicron and Sunplus USB bridges
-- USB device type autodetection for some devices on Linux,Windows and FreeBSD
-  (http://smartmontools.wiki.sourceforge.net/overview_USB-Support)
+- USB device type autodetection for some devices on Linux, Windows and FreeBSD
+  (http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_USB-Devices)
 - Support for Areca controllers on Linux
 - Support for MegaRAID controllers on Linux
 - Support for HighPoint RocketRAID controllers on FreeBSD
@@ -22,10 +22,14 @@ Summary: smartmontools release 5.39 (UNSTABLE/EXPERIMENTAL)
   Error Log
 - smartctl option '-l xselftest' to print ATA SMART Extended Self-test Log
 - smartctl option '-l sataphy' to print SATA Phy Event Counters
+- smartctl option '-l sasphy' to print SAS device phy information
 - smartctl options '-l gplog,...' and '-l smartlog,...' to print any log page
+- smartctl option '-x' to print all extended info if available
 - smartctl prints SCSI load/unload cycle counts
 - Improve display of huge raw values of some SMART attributes
 - Option '-d sat+TYPE' to use SAT with controllers which require '-d TYPE'
+- Option '-v ID,RAW_FORMAT,ATTR_NAME' to add new vendor specific attributes
+- Support for SSD drives using 64-bit raw attributes
 - Many additions to drive database
 - New simplified syntax for drive database
 - Option '-B FILE' to read drive database from a file
@@ -33,15 +37,18 @@ Summary: smartmontools release 5.39 (UNSTABLE/EXPERIMENTAL)
 - smartd can now handle attributes 197 and 198 with increasing raw values
 - smartd logs changes of self-test execution status
 - smartd directive '-n powermode,N' to limit the number of skipped checks
+- smartd flag '!' for '-r' and '-R' directives to log changes as critical
 - smartd supports scheduled Selective Self-Tests
-- Self-tests scheduled during downtime are run after next startup
-- Option '-s PREFIX' to store smartd internal state until next startup
-- Configure option to enable the above by default
+- Self-tests scheduled during system downtime or disk standby are run after
+  next startup
+- smartd option '-s PREFIX' to store smartd internal state until next startup
+- smartd option '-A PREFIX' to log attributes at each check cycle
+- Configure options to enable the above by default
 - Change to an object oriented interface to access ATA and SCSI devices
 - Linux, Win32 and FreeBSD modules migrated to new interface
 - Rework of smartd data structures
 - Checkin date and SVN revision and optional BUILD_INFO printed in version info
-- Better support for gSmartControl on Windows
+- Better support for GSmartControl on Windows
 - SELinux fixes to 3ware device node creation
 - Fix CCISS file descriptor leak on FreeBSD
 - Compile fixes for Solaris and FreeBSD
diff --git a/TODO b/TODO
index e49a9f3780592f5ffa5a7e7b8ebbff5a24d51ab7..fb0e6c3fa8896aa55f5fe65e7c421819557947ea 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
 TODO list for smartmontools:
 
-$Id: TODO 2845 2009-07-18 13:25:18Z chrfranke $
+$Id: TODO 2966 2009-10-23 21:05:16Z chrfranke $
 
 USB devices under Linux
 -----------------------
@@ -50,8 +50,6 @@ that can be monitored.
 
 Packaging
 ---------
-Rework 'do_release' script for SVN.
-
 Under freebsd and solaris, the following are wrong:
 smartd.conf: has linux device paths
 smart*.in  : man pages have (mostly) linux device paths
index eebff63531459f58643897d8a9c1dfbbde019c98..7c7f774b196b03b532b0e0f78815f3b9c4fd55f2 100644 (file)
@@ -37,7 +37,7 @@
 #include "utility.h"
 #include "dev_ata_cmd_set.h" // for parsed_ata_device
 
-const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 2928 2009-10-03 16:24:53Z chrfranke $"
+const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 2983 2009-11-14 21:41:41Z chrfranke $"
                                  ATACMDS_H_CVSID;
 
 // for passing global control variables
@@ -146,56 +146,17 @@ static const int actual_ver[] = {
   6             /* 0x0022       WARNING:        */
 };
 
-// When you add additional items to this list, you should then:
-// 0 -- update this list
-// 1 -- if needed, modify ataPrintSmartAttribRawValue()
-// 2 -  if needed, modify ataPrintSmartAttribName()
-// 3 -- add drive in question into builtin_knowndrives[] table in knowndrives.cpp
-// 4 -- update smartctl.8
-// 5 -- update smartd.8
-// 6 -- do "make smartd.conf.5" to update smartd.conf.5
-// 7 -- update CHANGELOG file
-
-struct vendor_attr_arg_entry
-{
-  unsigned char id;  // attribute ID, 0 for all
-  const char * name; // attribute name
-  unsigned char val; // value for attribute defs array
-};
-
-// The order of these entries is (only) relevant for '-v help' output.
-const vendor_attr_arg_entry vendor_attribute_args[] = {
-  {  9,"halfminutes", 4},
-  {  9,"minutes", 1},
-  {  9,"seconds", 3},
-  {  9,"temp", 2},
-  {192,"emergencyretractcyclect", 1},
-  {193,"loadunload", 1},
-  {194,"10xCelsius", 1},
-  {194,"unknown", 2},
-  {197,"increasing", 1},
-  {198,"offlinescanuncsectorct", 2},
-  {198,"increasing", 1},
-  {200,"writeerrorcount", 1},
-  {201,"detectedtacount", 1},
-  {220,"temp", 1},
-  {  0,"raw8", 253},
-  {  0,"raw16", 254},
-  {  0,"raw48", 255},
-};
-
-const unsigned num_vendor_attribute_args = sizeof(vendor_attribute_args)/sizeof(vendor_attribute_args[0]);
-
 // Get ID and increase flag of current pending or offline
 // uncorrectable attribute.
-unsigned char get_unc_attr_id(bool offline, const unsigned char * defs,
+unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs,
                               bool & increase)
 {
   unsigned char id = (!offline ? 197 : 198);
-  increase = (defs[id] == 1);
+  increase = !!(defs[id].flags & ATTRFLAG_INCREASING);
   return id;
 }
 
+#if 0 // TODO: never used
 // This are the meanings of the Self-test failure checkpoint byte.
 // This is in the self-test log at offset 4 bytes into the self-test
 // descriptor and in the SMART READ DATA structure at byte offset
@@ -221,63 +182,145 @@ const char *SelfTestFailureCodeName(unsigned char which){
     return NULL;
   }
 }
+#endif
+
+
+// Table of raw print format names
+struct format_name_entry
+{
+  const char * name;
+  ata_attr_raw_format format;
+};
+
+const format_name_entry format_names[] = {
+  {"raw8"           , RAWFMT_RAW8},
+  {"raw16"          , RAWFMT_RAW16},
+  {"raw48"          , RAWFMT_RAW48},
+  {"hex48"          , RAWFMT_HEX48},
+  {"raw64"          , RAWFMT_RAW64},
+  {"hex64"          , RAWFMT_HEX64},
+  {"raw16(raw16)"   , RAWFMT_RAW16_OPT_RAW16},
+  {"raw16(avg16)"   , RAWFMT_RAW16_OPT_AVG16},
+  {"raw24/raw24"    , RAWFMT_RAW24_RAW24},
+  {"sec2hour"       , RAWFMT_SEC2HOUR},
+  {"min2hour"       , RAWFMT_MIN2HOUR},
+  {"halfmin2hour"   , RAWFMT_HALFMIN2HOUR},
+  {"tempminmax"     , RAWFMT_TEMPMINMAX},
+  {"temp10x"        , RAWFMT_TEMP10X},
+};
+
+const unsigned num_format_names = sizeof(format_names)/sizeof(format_names[0]);
+
+// Table to map old to new '-v' option arguments
+const char * map_old_vendor_opts[][2] = {
+  {  "9,halfminutes"              , "9,halfmin2hour,Power_On_Half_Minutes"},
+  {  "9,minutes"                  , "9,min2hour,Power_On_Minutes"},
+  {  "9,seconds"                  , "9,sec2hour,Power_On_Seconds"},
+  {  "9,temp"                     , "9,tempminmax,Temperature_Celsius"},
+  {"192,emergencyretractcyclect"  , "192,raw48,Emerg_Retract_Cycle_Ct"},
+  {"193,loadunload"               , "193,raw24/raw24"},
+  {"194,10xCelsius"               , "194,temp10x,Temperature_Celsius_x10"},
+  {"194,unknown"                  , "194,raw48,Unknown_Attribute"},
+  {"197,increasing"               , "197,raw48+,Total_Pending_Sectors"}, // '+' sets flag
+  {"198,offlinescanuncsectorct"   , "198,raw48,Offline_Scan_UNC_SectCt"},
+  {"198,increasing"               , "198,raw48+,Total_Offl_Uncorrectabl"}, // '+' sets flag
+  {"200,writeerrorcount"          , "200,raw48,Write_Error_Count"},
+  {"201,detectedtacount"          , "201,raw48,Detected_TA_Count"},
+  {"220,temp"                     , "220,raw48,Temperature_Celsius"},
+};
+
+const unsigned num_old_vendor_opts = sizeof(map_old_vendor_opts)/sizeof(map_old_vendor_opts[0]);
 
-// This is a utility function for parsing pairs like "9,minutes" or
-// "220,temp", and putting the correct flag into the attributedefs
-// array.  Returns 1 if problem, 0 if pair has been recongized.
-int parse_attribute_def(const char * pair, unsigned char * defs)
+// Parse vendor attribute display def (-v option).
+// Return false on error.
+bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
+                         ata_vendor_def_prior priority)
 {
-  int id = 0, nc = -1;
-  char name[32+1];
-  if (pair[0] == 'N') {
-    // "N,name"
-    if (!(sscanf(pair, "N,%32s%n", name, &nc) == 1 && nc == (int)strlen(pair)))
-      return 1;
+  // Map old -> new options
+  unsigned i;
+  for (i = 0; i < num_old_vendor_opts; i++) {
+    if (!strcmp(opt, map_old_vendor_opts[i][0])) {
+      opt = map_old_vendor_opts[i][1];
+      break;
+    }
+  }
+
+  // Parse option
+  int len = strlen(opt);
+  int id = 0, n1 = -1, n2 = -1;
+  char fmtname[32+1], attrname[32+1];
+  if (opt[0] == 'N') {
+    // "N,format"
+    if (!(   sscanf(opt, "N,%32[^,]%n,%32[^,]%n", fmtname, &n1, attrname, &n2) >= 1
+          && (n1 == len || n2 == len)))
+      return false;
   }
   else {
-    // "attr,name"
-    if (!(   sscanf(pair, "%d,%32s%n", &id, name, &nc) == 2
-          && 1 <= id && id <= 255 && nc == (int)strlen(pair)))
-      return 1;
+    // "id,format[+][,name]"
+    if (!(   sscanf(opt, "%d,%32[^,]%n,%32[^,]%n", &id, fmtname, &n1, attrname, &n2) >= 2
+          && 1 <= id && id <= 255 && (n1 == len || n2 == len)))
+      return false;
   }
+  if (n1 == len)
+    attrname[0] = 0;
 
-  // Find pair
-  unsigned i;
+  unsigned flags = 0;
+  // For "-v 19[78],increasing" above
+  if (fmtname[strlen(fmtname)-1] == '+') {
+    fmtname[strlen(fmtname)-1] = 0;
+    flags = ATTRFLAG_INCREASING;
+  }
+
+  // Find format name
   for (i = 0; ; i++) {
-    if (i >= num_vendor_attribute_args)
-      return 1; // Not found
-    if (   (!vendor_attribute_args[i].id || vendor_attribute_args[i].id == id)
-        && !strcmp(vendor_attribute_args[i].name, name)                       )
+    if (i >= num_format_names)
+      return false; // Not found
+    if (!strcmp(fmtname, format_names[i].name))
       break;
   }
+  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;
 
   if (!id) {
-    // "N,name" -> set all entries
-    for (int j = 0; j < MAX_ATTRIBUTE_NUM; j++)
-      defs[j] = vendor_attribute_args[i].val;
+    // "N,format" -> set format for all entries
+    for (i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
+      if (defs[i].priority >= priority)
+        continue;
+      if (attrname[0])
+        defs[i].name = attrname;
+      defs[i].priority = priority;
+      defs[i].raw_format = format;
+      defs[i].flags = flags;
+    }
+  }
+  else if (defs[id].priority <= priority) {
+    // "id,format[,name]"
+    if (attrname[0])
+      defs[id].name = attrname;
+    defs[id].raw_format = format;
+    defs[id].priority = priority;
+    defs[id].flags = flags;
   }
-  else
-    // "attr,name"
-    defs[id] = vendor_attribute_args[i].val;
 
-  return 0;
+  return true;
 }
 
+
 // Return a multiline string containing a list of valid arguments for
 // parse_attribute_def().  The strings are preceeded by tabs and followed
 // (except for the last) by newlines.
 std::string create_vendor_attribute_arg_list()
 {
   std::string s;
-  for (unsigned i = 0; i < num_vendor_attribute_args; i++) {
-    if (i > 0)
-      s += '\n';
-    if (!vendor_attribute_args[i].id)
-      s += "\tN,";
-    else
-      s += strprintf("\t%d,", vendor_attribute_args[i].id);
-    s += vendor_attribute_args[i].name;
-  }
+  unsigned i;
+  for (i = 0; i < num_format_names; i++)
+    s += strprintf("%s\tN,%s[,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]);
   return s;
 }
 
@@ -1660,370 +1703,281 @@ int isSupportSelectiveSelfTest(const ata_smart_values * data)
    return data->offline_data_collection_capability & 0x40;
 }
 
+// Get attribute state
+ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
+                                  const ata_smart_threshold_entry & thre,
+                                  const ata_vendor_attr_defs & defs)
+{
+  if (!attr.id)
+    return ATTRSTATE_NON_EXISTING;
 
+  // Normalized values (current,worst,threshold) not valid
+  // if specified by '-v' option.
+  // (Some SSD disks uses these bytes to store raw value).
+  if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL)
+    return ATTRSTATE_NO_NORMVAL;
 
-// Loop over all valid attributes.  If they are prefailure attributes
-// and are at or below the threshold value, then return the ID of the
-// first failing attribute found.  Return 0 if all prefailure
-// attributes are in bounds.  The spec says "Bit 0
-// -Pre-failure/advisory - If the value of this bit equals zero, an
-// attribute value less than or equal to its corresponding attribute
-// threshold indicates an advisory condition where the usage or age of
-// the device has exceeded its intended design life period. If the
-// value of this bit equals one, an atribute value less than or equal
-// to its corresponding attribute threshold indicates a pre-failure
-// condition where imminent loss of data is being predicted."
-
-
-// onlyfailed=0 : are or were any age or prefailure attributes <= threshold
-// onlyfailed=1:  are any prefailure attributes <= threshold now
-int ataCheckSmart(const ata_smart_values * data,
-                  const ata_smart_thresholds_pvt * thresholds,
-                  int onlyfailed)
-{
-  // loop over all attributes
-  for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++){
-
-    // pointers to disk's values and vendor's thresholds
-    const ata_smart_attribute * disk = data->vendor_attributes+i;
-    const ata_smart_threshold_entry * thre = thresholds->thres_entries+i;
-    // consider only valid attributes
-    if (disk->id && thre->id){
-      int failednow,failedever;
-      
-      failednow =disk->current <= thre->threshold;
-      failedever=disk->worst   <= thre->threshold;
-      
-      if (!onlyfailed && failedever)
-        return disk->id;
-      
-      if (onlyfailed && failednow && ATTRIBUTE_FLAGS_PREFAILURE(disk->flags))
-        return disk->id;      
-    }
-  }
-  return 0;
-}
+  // No threshold if thresholds cannot be read.
+  if (!thre.id && !thre.threshold)
+    return ATTRSTATE_NO_THRESHOLD;
 
+  // Bad threshold if id's don't match
+  if (attr.id != thre.id)
+    return ATTRSTATE_BAD_THRESHOLD;
 
+  // Don't report a failed attribute if its threshold is 0.
+  // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing"
+  // threshold (Later ATA versions declare all thresholds as "obsolete").
+  // In practice, threshold value 0 is often used for usage attributes.
+  if (!thre.threshold)
+    return ATTRSTATE_OK;
 
-// This checks the n'th attribute in the attribute list, NOT the
-// attribute with id==n.  If the attribute does not exist, or the
-// attribute is > threshold, then returns zero.  If the attribute is
-// <= threshold (failing) then we the attribute number if it is a
-// prefail attribute.  Else we return minus the attribute number if it
-// is a usage attribute.
-int ataCheckAttribute(const ata_smart_values * data,
-                      const ata_smart_thresholds_pvt * thresholds,
-                      int n)
-{
-  if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !data || !thresholds)
-    return 0;
-  
-  // pointers to disk's values and vendor's thresholds
-  const ata_smart_attribute * disk = data->vendor_attributes+n;
-  const ata_smart_threshold_entry * thre = thresholds->thres_entries+n;
+  // Failed now if current value is below threshold
+  if (attr.current <= thre.threshold)
+    return ATTRSTATE_FAILED_NOW;
 
-  if (!disk || !thre)
-    return 0;
-  
-  // consider only valid attributes, check for failure
-  if (!disk->id || !thre->id || (disk->id != thre->id) || disk->current> thre->threshold)
-    return 0;
-  
-  // We have found a failed attribute.  Return positive or negative? 
-  if (ATTRIBUTE_FLAGS_PREFAILURE(disk->flags))
-    return disk->id;
-  else
-    return -1*(disk->id);
-}
+  // Failed in the passed if worst value is below threshold
+  if (attr.worst <= thre.threshold)
+    return ATTRSTATE_FAILED_PAST;
 
+  return ATTRSTATE_OK;
+}
 
-// Print temperature value and Min/Max value if present
-static void ataPrintTemperatureValue(char *out, const unsigned char *raw, const unsigned *word)
+// Get default raw value print format
+static ata_attr_raw_format get_default_raw_format(unsigned char id)
 {
-  out+=sprintf(out, "%u", word[0]);
-  if (!word[1] && !word[2])
-    return; // No Min/Max
+  switch (id) {
+  case 3:   // Spin-up time
+    return RAWFMT_RAW16_OPT_AVG16;
 
-  unsigned lo = ~0, hi = ~0;
-  if (!raw[3]) {
-    // 00 HH 00 LL 00 TT (IBM)
-    hi = word[2]; lo = word[1];
-  }
-  else if (!word[2]) {
-    // 00 00 HH LL 00 TT (Maxtor)
-    hi = raw[3]; lo = raw[2];
+  case 5:   // Reallocated sector count
+  case 196: // Reallocated event count
+    return RAWFMT_RAW16_OPT_RAW16;
+
+  case 190: // Temperature
+  case 194:
+    return RAWFMT_TEMPMINMAX;
+
+  default:
+    return RAWFMT_RAW48;
   }
-  if (lo > hi) {
-    unsigned t = lo; lo = hi; hi = t;
+}
+
+// Get attribute raw value.
+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;
   }
-  if (lo <= word[0] && word[0] <= hi)
-    sprintf(out, " (Lifetime Min/Max %u/%u)", lo, hi);
-  else
-    sprintf(out, " (%u %u %u %u)", raw[5], raw[4], raw[3], raw[2]);
+  return rawvalue;
 }
 
 
-// This routine prints the raw value of an attribute as a text string
-// into out. It also returns this 48-bit number as a long long.  The
-// array defs[] contains non-zero values if particular attributes have
-// non-default interpretations.
+// Format attribute raw value.
+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
+  uint64_t rawvalue = ata_get_attr_raw_value(attr, defs);
 
-int64_t ataPrintSmartAttribRawValue(char *out, 
-                                    const ata_smart_attribute * attribute,
-                                    const unsigned char * defs){
-  int64_t rawvalue;
+  // Get 16 bit words
+  const unsigned char * raw = attr.raw;
   unsigned word[3];
-  int j;
-  unsigned char select;
-  
-  // convert the six individual bytes to a long long (8 byte) integer.
-  // This is the value that we'll eventually return.
-  rawvalue = 0;
-  for (j=0; j<6; j++) {
-    // This looks a bit roundabout, but is necessary.  Don't
-    // succumb to the temptation to use raw[j]<<(8*j) since under
-    // the normal rules this will be promoted to the native type.
-    // On a 32 bit machine this might then overflow.
-    int64_t temp;
-    temp = attribute->raw[j];
-    temp <<= 8*j;
-    rawvalue |= temp;
-  }
-
-  // convert quantities to three two-byte words
-  for (j=0; j<3; j++){
-    word[j] = attribute->raw[2*j+1];
-    word[j] <<= 8;
-    word[j] |= attribute->raw[2*j];
-  }
-  
-  // if no data array, Attributes have default interpretations
-  if (defs)
-    select=defs[attribute->id];
-  else
-    select=0;
-
-  // Print six one-byte quantities.
-  if (select==253){
-    for (j=0; j<5; j++)
-      out+=sprintf(out, "%d ", attribute->raw[5-j]);
-    out+=sprintf(out, "%d ", attribute->raw[0]);
-    return rawvalue;
-  } 
-  
-  // Print three two-byte quantities
-  if (select==254){
-    out+=sprintf(out, "%d %d %d", word[2], word[1], word[0]); 
-    return rawvalue;
-  } 
-  
-  // Print one six-byte quantity
-  if (select==255){
-    out+=sprintf(out, "%"PRIu64, rawvalue);
-    return rawvalue;
-  }
+  word[0] = raw[0] | (raw[1] << 8);
+  word[1] = raw[2] | (raw[3] << 8);
+  word[2] = raw[4] | (raw[5] << 8);
 
-  // This switch statement is where we handle Raw attributes
-  // that are stored in an unusual vendor-specific format,
-  switch (attribute->id){
-    // Spin-up time
-  case 3:
-    out+=sprintf(out, "%d", word[0]);
-    // if second nonzero then it stores the average spin-up time
-    if (word[1])
-      out+=sprintf(out, " (Average %d)", word[1]);
+  // Get print format
+  ata_attr_raw_format format = defs[attr.id].raw_format;
+  if (format == RAWFMT_DEFAULT)
+    format = get_default_raw_format(attr.id);
+
+  // Print
+  std::string s;
+  switch (format) {
+  case RAWFMT_RAW8:
+    s = strprintf("%d %d %d %d %d %d",
+      raw[5], raw[4], raw[3], raw[2], raw[1], raw[0]);
     break;
-    // reallocated sector count
-  case 5:
-    out+=sprintf(out, "%u", word[0]);
+
+  case RAWFMT_RAW16:
+    s = strprintf("%u %u %u", word[2], word[1], word[0]);
+    break;
+
+  case RAWFMT_RAW48:
+    s = strprintf("%"PRIu64, rawvalue);
+    break;
+
+  case RAWFMT_HEX48:
+    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;
+
+  case RAWFMT_RAW16_OPT_RAW16:
+    s = strprintf("%u", word[0]);
     if (word[1] || word[2])
-      out+=sprintf(out, " (%u, %u)", word[2], word[1]);
+      s += strprintf(" (%u, %u)", word[2], word[1]);
     break;
-    // Power on time
-  case 9:
-    if (select==1){
+
+  case RAWFMT_RAW16_OPT_AVG16:
+    s = strprintf("%u", word[0]);
+    if (word[1])
+      s += strprintf(" (Average %u)", word[1]);
+    break;
+
+  case RAWFMT_RAW24_RAW24:
+    s = strprintf("%d/%d",
+      raw[0] | (raw[1]<<8) | (raw[2]<<16),
+      raw[3] | (raw[4]<<8) | (raw[5]<<16));
+    break;
+
+  case RAWFMT_MIN2HOUR:
+    {
       // minutes
-      int64_t temp=word[0]+(word[1]<<16);
-      int64_t tmp1=temp/60;
-      int64_t tmp2=temp%60;
-      out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2);
+      int64_t temp = word[0]+(word[1]<<16);
+      int64_t tmp1 = temp/60;
+      int64_t tmp2 = temp%60;
+      s = strprintf("%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2);
       if (word[2])
-        out+=sprintf(out, " (%u)", word[2]);
+        s += strprintf(" (%u)", word[2]);
     }
-    else if (select==3){
+    break;
+
+  case RAWFMT_SEC2HOUR:
+    {
       // seconds
-      int64_t hours=rawvalue/3600;
-      int64_t minutes=(rawvalue-3600*hours)/60;
-      int64_t seconds=rawvalue%60;
-      out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds);
-    }
-    else if (select==4){
-      // 30-second counter
-      int64_t tmp1=rawvalue/120;
-      int64_t tmp2=(rawvalue-120*tmp1)/2;
-      out+=sprintf(out, "%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2);
+      int64_t hours = rawvalue/3600;
+      int64_t minutes = (rawvalue-3600*hours)/60;
+      int64_t seconds = rawvalue%60;
+      s = strprintf("%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds);
     }
-    else
-      // hours
-      out+=sprintf(out, "%"PRIu64, rawvalue);  //stored in hours
     break;
-    // Temperature
-  case 190:
-    ataPrintTemperatureValue(out, attribute->raw, word);
-    break;
-   // Load unload cycles
-  case 193:
-    if (select==1){
-      // loadunload
-      long load  =attribute->raw[0] + (attribute->raw[1]<<8) + (attribute->raw[2]<<16);
-      long unload=attribute->raw[3] + (attribute->raw[4]<<8) + (attribute->raw[5]<<16);
-      out+=sprintf(out, "%lu/%lu", load, unload);
+
+  case RAWFMT_HALFMIN2HOUR:
+    {
+      // 30-second counter
+      int64_t hours = rawvalue/120;
+      int64_t minutes = (rawvalue-120*hours)/2;
+      s += strprintf("%"PRIu64"h+%02"PRIu64"m", hours, minutes);
     }
-    else
-      // associated
-      out+=sprintf(out, "%"PRIu64, rawvalue);
     break;
+
+  case RAWFMT_TEMPMINMAX:
     // Temperature
-  case 194:
-    if (select==1){
-      // ten times temperature in Celsius
-      int deg=word[0]/10;
-      int tenths=word[0]%10;
-      out+=sprintf(out, "%d.%d", deg, tenths);
+    s = strprintf("%u", word[0]);
+    if (word[1] || word[2]) {
+      unsigned lo = ~0, hi = ~0;
+      if (!raw[3]) {
+        // 00 HH 00 LL 00 TT (IBM)
+        hi = word[2]; lo = word[1];
+      }
+      else if (!word[2]) {
+        // 00 00 HH LL 00 TT (Maxtor)
+        hi = raw[3]; lo = raw[2];
+      }
+      if (lo > hi) {
+        unsigned t = lo; lo = hi; hi = t;
+      }
+      if (lo <= word[0] && word[0] <= hi)
+        s += strprintf(" (Lifetime Min/Max %u/%u)", lo, hi);
+      else
+        s += strprintf(" (%d %d %d %d)", raw[5], raw[4], raw[3], raw[2]);
     }
-    else if (select==2)
-      // unknown attribute
-      out+=sprintf(out, "%"PRIu64, rawvalue);
-    else
-      ataPrintTemperatureValue(out, attribute->raw, word);
     break;
-    // reallocated event count
-  case 196:
-    out+=sprintf(out, "%u", word[0]);
-    if (word[1] || word[2])
-      out+=sprintf(out, " (%u, %u)", word[2], word[1]);
+
+  case RAWFMT_TEMP10X:
+    // ten times temperature in Celsius
+    s = strprintf("%d.%d", word[0]/10, word[0]%10);
     break;
+
   default:
-    out+=sprintf(out, "%"PRIu64, rawvalue);
+    s = "?"; // Should not happen
+    break;
   }
-  
-  // Return the full value
-  return rawvalue;
-}
-
 
-// Note some attribute names appear redundant because different
-// manufacturers use different attribute IDs for an attribute with the
-// same name.  The variable val should contain a non-zero value if a particular
-// attributes has a non-default interpretation.
-void ataPrintSmartAttribName(char * out, unsigned char id, const unsigned char * definitions){
-  const char *name;
-  unsigned char val;
-
-  // If no data array, use default interpretations
-  if (definitions)
-    val=definitions[id];
-  else
-    val=0;
+  return s;
+}
 
-  switch (id){
-    
+// Attribute names shouldn't be longer than 23 chars, otherwise they break the
+// output of smartctl.
+static const char * get_default_attr_name(unsigned char id)
+{
+  switch (id) {
   case 1:
-    name="Raw_Read_Error_Rate";
-    break;
+    return "Raw_Read_Error_Rate";
   case 2:
-    name="Throughput_Performance";
-    break;
+    return "Throughput_Performance";
   case 3:
-    name="Spin_Up_Time";
-    break;
+    return "Spin_Up_Time";
   case 4:
-    name="Start_Stop_Count";
-    break;
+    return "Start_Stop_Count";
   case 5:
-    name="Reallocated_Sector_Ct";
-    break;
+    return "Reallocated_Sector_Ct";
   case 6:
-    name="Read_Channel_Margin";
-    break;
+    return "Read_Channel_Margin";
   case 7:
-    name="Seek_Error_Rate";
-    break;
+    return "Seek_Error_Rate";
   case 8:
-    name="Seek_Time_Performance";
-    break;
+    return "Seek_Time_Performance";
   case 9:
-    switch (val) {
-    case 1:
-      name="Power_On_Minutes";
-      break;
-    case 2:
-      name="Temperature_Celsius";
-      break;
-    case 3:
-      name="Power_On_Seconds";
-      break;
-    case 4:
-      name="Power_On_Half_Minutes";
-      break;
-    default:
-      name="Power_On_Hours";
-      break;
-    }
-    break;
+    return "Power_On_Hours";
   case 10:
-    name="Spin_Retry_Count";
-    break;
+    return "Spin_Retry_Count";
   case 11:
-    name="Calibration_Retry_Count";
-    break;
+    return "Calibration_Retry_Count";
   case 12:
-    name="Power_Cycle_Count";
-    break;
+    return "Power_Cycle_Count";
   case 13:
-    name="Read_Soft_Error_Rate";
-    break;
+    return "Read_Soft_Error_Rate";
   case 175:
-    name="Program_Fail_Count_Chip";
-    break;
+    return "Program_Fail_Count_Chip";
   case 176:
-    name="Erase_Fail_Count_Chip";
-    break;
+    return "Erase_Fail_Count_Chip";
   case 177:
-    name="Wear_Leveling_Count";
-    break;
+    return "Wear_Leveling_Count";
   case 178:
-    name="Used_Rsvd_Blk_Cnt_Chip";
-    break;
+    return "Used_Rsvd_Blk_Cnt_Chip";
   case 179:
-    name="Used_Rsvd_Blk_Cnt_Tot";
-    break;
+    return "Used_Rsvd_Blk_Cnt_Tot";
   case 180:
-    name="Unused_Rsvd_Blk_Cnt_Tot";
-    break;
+    return "Unused_Rsvd_Blk_Cnt_Tot";
   case 181:
-    name="Program_Fail_Cnt_Total";
-    break;
+    return "Program_Fail_Cnt_Total";
   case 182:
-    name="Erase_Fail_Count_Total";
-    break;
+    return "Erase_Fail_Count_Total";
   case 183:
-    name="Runtime_Bad_Block";
-    break;
+    return "Runtime_Bad_Block";
   case 184:
-    name="End-to-End_Error";
-    break;
+    return "End-to-End_Error";
   case 187:
-    name="Reported_Uncorrect";
-    break;
+    return "Reported_Uncorrect";
   case 188:
-    name="Command_Timeout";
-    break;
+    return "Command_Timeout";
   case 189:
-    name="High_Fly_Writes";
-    break;
+    return "High_Fly_Writes";
   case 190:
     // Western Digital uses this for temperature.
     // It's identical to Attribute 194 except that it
@@ -2032,243 +1986,138 @@ void ataPrintSmartAttribName(char * out, unsigned char id, const unsigned char *
     // is typically 55C.  So if this attribute has failed
     // in the past, it indicates that the drive temp exceeded
     // 55C sometime in the past.
-    name="Airflow_Temperature_Cel";
-    break;
+    return "Airflow_Temperature_Cel";
   case 191:
-    name="G-Sense_Error_Rate";
-    break;
+    return "G-Sense_Error_Rate";
   case 192:
-    switch (val) {
-    case 1:
-      // Fujitsu
-      name="Emergency_Retract_Cycle_Ct";
-      break;
-    default:
-      name="Power-Off_Retract_Count";
-      break;
-    }
-    break;
+    return "Power-Off_Retract_Count";
   case 193:
-    name="Load_Cycle_Count";
-    break;
+    return "Load_Cycle_Count";
   case 194:
-    switch (val){
-    case 1:
-      // Samsung SV1204H with RK100-13 firmware
-      name="Temperature_Celsius_x10";
-      break;
-    case 2:
-      // for disks with no temperature Attribute
-      name="Unknown_Attribute";
-      break;
-    default:
-      name="Temperature_Celsius";
-      break;
-    }
-    break;
+    return "Temperature_Celsius";
   case 195:
-    // Fujitsu name="ECC_On_The_Fly_Count";
-    name="Hardware_ECC_Recovered";
-    break;
+    // Fujitsu: "ECC_On_The_Fly_Count";
+    return "Hardware_ECC_Recovered";
   case 196:
-    name="Reallocated_Event_Count";
-    break;
+    return "Reallocated_Event_Count";
   case 197:
-    switch (val) {
-    default:
-      name="Current_Pending_Sector";
-      break;
-    case 1:
-      // Not reset after sector reallocation
-      name="Total_Pending_Sectors";
-      break;
-    }
-    break;
+    return "Current_Pending_Sector";
   case 198:
-    switch (val){
-    default:
-      name="Offline_Uncorrectable";
-      break;
-    case 1:
-      // Not reset after sector reallocation
-      name="Total_Offl_Uncorrectabl"/*e*/;
-      break;
-    case 2:
-      // Fujitsu
-      name="Off-line_Scan_UNC_Sector_Ct";
-      break;
-    }
-    break;
+    return "Offline_Uncorrectable";
   case 199:
-    name="UDMA_CRC_Error_Count";
-    break;
+    return "UDMA_CRC_Error_Count";
   case 200:
-    switch (val) {
-    case 1:
-      // Fujitsu MHS2020AT
-      name="Write_Error_Count";
-      break;
-    default:
-      // Western Digital
-      name="Multi_Zone_Error_Rate";
-      break;
-    }
-    break;
+    // Western Digital
+    return "Multi_Zone_Error_Rate";
   case 201:
-    switch (val) {
-    case 1:
-      // Fujitsu
-      name="Detected_TA_Count";
-      break;
-    default:
-      name="Soft_Read_Error_Rate";
-      break;
-    }
-    break;
+    return "Soft_Read_Error_Rate";
   case 202:
-    // Fujitsu
-    name="TA_Increase_Count";
-    // Maxtor: Data Address Mark Errors
-    break;
+    // Fujitsu: "TA_Increase_Count"
+    return "Data_Address_Mark_Errs";
   case 203:
     // Fujitsu
-    name="Run_Out_Cancel";
+    return "Run_Out_Cancel";
     // Maxtor: ECC Errors
-    break;
   case 204:
-    // Fujitsu
-    name="Shock_Count_Write_Opern";
-    // Maxtor: Soft ECC Correction
-    break;
+    // Fujitsu: "Shock_Count_Write_Opern"
+    return "Soft_ECC_Correction";
   case 205:
-    // Fujitsu
-    name="Shock_Rate_Write_Opern";
-    // Maxtor: Thermal Aspirates
-    break;
+    // Fujitsu: "Shock_Rate_Write_Opern"
+    return "Thermal_Asperity_Rate";
   case 206:
     // Fujitsu
-    name="Flying_Height";
-    break;
+    return "Flying_Height";
   case 207:
     // Maxtor
-    name="Spin_High_Current";
-    break;
+    return "Spin_High_Current";
   case 208:
     // Maxtor
-    name="Spin_Buzz";
-    break;
+    return "Spin_Buzz";
   case 209:
     // Maxtor
-    name="Offline_Seek_Performnce";
-    break;
+    return "Offline_Seek_Performnce";
   case 220:
-    switch (val) {
-    case 1:
-      name="Temperature_Celsius";
-      break;
-    default:
-      name="Disk_Shift";
-      break;
-    }
-    break;
+    return "Disk_Shift";
   case 221:
-    name="G-Sense_Error_Rate";
-    break;
+    return "G-Sense_Error_Rate";
   case 222:
-    name="Loaded_Hours";
-    break;
+    return "Loaded_Hours";
   case 223:
-    name="Load_Retry_Count";
-    break;
+    return "Load_Retry_Count";
   case 224:
-    name="Load_Friction";
-    break;
+    return "Load_Friction";
   case 225:
-    name="Load_Cycle_Count";
-    break;
+    return "Load_Cycle_Count";
   case 226:
-    name="Load-in_Time";
-    break;
+    return "Load-in_Time";
   case 227:
-    name="Torq-amp_Count";
-    break;
+    return "Torq-amp_Count";
   case 228:
-    name="Power-off_Retract_Count";
-    break;
+    return "Power-off_Retract_Count";
   case 230:
     // seen in IBM DTPA-353750
-    name="Head_Amplitude";
-    break;
+    return "Head_Amplitude";
   case 231:
-    name="Temperature_Celsius";
-    break;
+    return "Temperature_Celsius";
+  case 232:
+    // seen in Intel X25-E SSD
+    return "Available_Reservd_Space";
+  case 233:
+    // seen in Intel X25-E SSD
+    return "Media_Wearout_Indicator";
   case 240:
-    name="Head_Flying_Hours";
-    break;
+    return "Head_Flying_Hours";
+  case 241:
+    return "Total_LBAs_Written";
+  case 242:
+    return "Total_LBAs_Read";
   case 250:
-    name="Read_Error_Retry_Rate";
-    break;
+    return "Read_Error_Retry_Rate";
+  case 254:
+    return "Free_Fall_Sensor";
   default:
-    name="Unknown_Attribute";
-    break;
+    return "Unknown_Attribute";
   }
-  sprintf(out,"%3hu %s",(short int)id,name);
-  return;
 }
 
-// Returns raw value of Attribute with ID==id. This will be in the
-// range 0 to 2^48-1 inclusive.  If the Attribute does not exist,
-// return -1.
-int64_t ATAReturnAttributeRawValue(unsigned char id, const ata_smart_values * data)
+// Get attribute name
+std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs)
+{
+  if (!defs[id].name.empty())
+    return defs[id].name;
+  else
+    return get_default_attr_name(id);
+}
+
+// Find attribute index for attribute id, -1 if not found.
+int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval)
 {
-  // valid Attribute IDs are in the range 1 to 255 inclusive.
-  if (!id || !data)
+  if (!id)
     return -1;
-  
-  // loop over Attributes to see if there is one with the desired ID
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
-    const ata_smart_attribute * ap = data->vendor_attributes + i;
-    if (ap->id == id) {
-      // we've found the desired Attribute.  Return its value
-      int64_t rawvalue=0;
-      int j;
-
-      for (j=0; j<6; j++) {
-       // This looks a bit roundabout, but is necessary.  Don't
-       // succumb to the temptation to use raw[j]<<(8*j) since under
-       // the normal rules this will be promoted to the native type.
-       // On a 32 bit machine this might then overflow.
-       int64_t temp;
-       temp = ap->raw[j];
-       temp <<= 8*j;
-       rawvalue |= temp;
-      } // loop over j
-      return rawvalue;
-    } // found desired Attribute
-  } // loop over Attributes
-  
-  // fall-through: no such Attribute found
+    if (smartval.vendor_attributes[i].id == id)
+      return i;
+  }
   return -1;
 }
 
 // Return Temperature Attribute raw value selected according to possible
 // non-default interpretations. If the Attribute does not exist, return 0
-unsigned char ATAReturnTemperatureValue(const ata_smart_values * data, const unsigned char * defs)
+unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs)
 {
   for (int i = 0; i < 3; i++) {
     static const unsigned char ids[3] = {194, 9, 220};
     unsigned char id = ids[i];
-    unsigned char select = (defs ? defs[id] : 0);
-    int64_t raw; unsigned temp;
-    if (!(   (id == 194 && select <= 1)   // ! -v 194,unknown
-          || (id == 9 && select == 2)     // -v 9,temp
-          || (id == 220 && select == 1))) // -v 220,temp
+    const ata_attr_raw_format format = defs[id].raw_format;
+    if (!(   (id == 194 && format == RAWFMT_DEFAULT)
+          || format == RAWFMT_TEMPMINMAX || format == RAWFMT_TEMP10X))
       continue;
-    raw = ATAReturnAttributeRawValue(id, data);
-    if (raw < 0)
+    int idx = ata_find_attr_index(id, *data);
+    if (idx < 0)
       continue;
-    temp = (unsigned short)raw; // ignore possible min/max values in high words
-    if (id == 194 && select == 1) // -v 194,10xCelsius
+    uint64_t raw = ata_get_attr_raw_value(data->vendor_attributes[idx], defs);
+    unsigned temp = (unsigned short)raw; // ignore possible min/max values in high words
+    if (format == RAWFMT_TEMP10X) // -v N,temp10x
       temp = (temp+5) / 10;
     if (!(0 < temp && temp <= 255))
       continue;
index c5f77e4254654b5332d9cd2ce226e82f1e8a4194..4500b86a839ae45bff2a0decf6b03bca26524436 100644 (file)
--- a/atacmds.h
+++ b/atacmds.h
@@ -26,7 +26,7 @@
 #ifndef ATACMDS_H_
 #define ATACMDS_H_
 
-#define ATACMDS_H_CVSID "$Id: atacmds.h 2859 2009-07-23 18:55:06Z chrfranke $"
+#define ATACMDS_H_CVSID "$Id: atacmds.h 2983 2009-11-14 21:41:41Z chrfranke $"
 
 #include "dev_interface.h" // ata_device
 
@@ -626,6 +626,68 @@ struct ata_selective_selftest_args
     : num_spans(0), pending_time(0), scan_after_select(0) { }
 };
 
+// Priority for vendor attribute defs
+enum ata_vendor_def_prior
+{
+  PRIOR_DEFAULT,
+  PRIOR_DATABASE,
+  PRIOR_USER
+};
+
+// Raw attribute value print formats
+enum ata_attr_raw_format
+{
+  RAWFMT_DEFAULT,
+  RAWFMT_RAW8,
+  RAWFMT_RAW16,
+  RAWFMT_RAW48,
+  RAWFMT_HEX48,
+  RAWFMT_RAW64,
+  RAWFMT_HEX64,
+  RAWFMT_RAW16_OPT_RAW16,
+  RAWFMT_RAW16_OPT_AVG16,
+  RAWFMT_RAW24_RAW24,
+  RAWFMT_SEC2HOUR,
+  RAWFMT_MIN2HOUR,
+  RAWFMT_HALFMIN2HOUR,
+  RAWFMT_TEMPMINMAX,
+  RAWFMT_TEMP10X,
+};
+
+// Attribute flags
+enum {
+  ATTRFLAG_INCREASING = 0x01, // Value not reset (for reallocated/pending counts)
+  ATTRFLAG_NO_NORMVAL = 0x02  // Normalized value not valid
+};
+
+// Vendor attribute display defs for all attribute ids
+class ata_vendor_attr_defs
+{
+public:
+  struct entry
+  {
+    std::string name; // Attribute name, empty for default
+    ata_attr_raw_format raw_format; // Raw value print format
+    ata_vendor_def_prior priority; // Setting priority
+    unsigned flags; // ATTRFLAG_*
+
+    entry()
+      : raw_format(RAWFMT_DEFAULT),
+        priority(PRIOR_DEFAULT),
+        flags(0)
+      { }
+  };
+
+  entry & operator[](unsigned char id)
+    { return m_defs[id]; }
+
+  const entry & operator[](unsigned char id) const
+    { return m_defs[id]; }
+
+private:
+  entry m_defs[256];
+};
+
 
 // Get information from drive
 int ataReadHDIdentity(ata_device * device, struct ata_identify_device *buf);
@@ -700,11 +762,6 @@ int ataSmartSupport(const ata_identify_device * drive);
 // -1: can't tell if SMART is enabled -- try issuing ataDoesSmartWork command to see
 int ataIsSmartEnabled(const ata_identify_device * drive);
 
-/* Check SMART for Threshold failure */
-// onlyfailed=0 : are or were any age or prefailure attributes <= threshold
-// onlyfailed=1:  are any prefailure attributes <= threshold now
-int ataCheckSmart(const ata_smart_values * data, const ata_smart_thresholds_pvt * thresholds, int onlyfailed);
-
 int ataSmartStatus2(ata_device * device);
 
 int isSmartErrorLogCapable(const ata_smart_values * data, const ata_identify_device * identity);
@@ -741,25 +798,34 @@ int ataSmartTest(ata_device * device, int testtype, const ata_selective_selftest
 
 int TestTime(const ata_smart_values * data, int testtype);
 
-// Prints the raw value (with appropriate formatting) into the
-// character string out.
-int64_t ataPrintSmartAttribRawValue(char *out, 
-                                    const ata_smart_attribute * attribute,
-                                    const unsigned char * defs);
-
-// Prints Attribute Name for standard SMART attributes. Writes a
-// 30 byte string with attribute name into output
-void ataPrintSmartAttribName(char * out, unsigned char id, const unsigned char * definitions);
-
-// This checks the n'th attribute in the attribute list, NOT the
-// attribute with id==n.  If the attribute does not exist, or the
-// attribute is > threshold, then returns zero.  If the attribute is
-// <= threshold (failing) then we the attribute number if it is a
-// prefail attribute.  Else we return minus the attribute number if it
-// is a usage attribute.
-int ataCheckAttribute(const ata_smart_values * data,
-                      const ata_smart_thresholds_pvt * thresholds,
-                      int n);
+// Attribute state
+enum ata_attr_state
+{
+  ATTRSTATE_NON_EXISTING,   // No such Attribute
+  ATTRSTATE_NO_NORMVAL,     // Normalized value not valid
+  ATTRSTATE_BAD_THRESHOLD,  // Threshold not valid
+  ATTRSTATE_NO_THRESHOLD,   // Unknown or no threshold
+  ATTRSTATE_OK,             // Never failed
+  ATTRSTATE_FAILED_PAST,    // Failed in the past
+  ATTRSTATE_FAILED_NOW      // Failed now
+};
+
+// Get attribute state
+ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr,
+                                  const ata_smart_threshold_entry & thre,
+                                  const ata_vendor_attr_defs & defs);
+
+// Get attribute raw value.
+uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr,
+                                const ata_vendor_attr_defs & defs);
+
+// Format attribute raw value.
+std::string ata_format_attr_raw_value(const ata_smart_attribute & attr,
+                                      const ata_vendor_attr_defs & defs);
+
+// Get attribute name
+std::string ata_get_smart_attr_name(unsigned char id,
+                                    const ata_vendor_attr_defs & defs);
 
 // External handler function, for when a checksum is not correct.  Can
 // simply return if no action is desired, or can print error messages
@@ -767,14 +833,12 @@ int ataCheckAttribute(const ata_smart_values * data,
 // Structure with the incorrect checksum.
 void checksumwarning(const char *string);
 
-// Returns raw value of Attribute with ID==id. This will be in the
-// range 0 to 2^48-1 inclusive.  If the Attribute does not exist,
-// return -1.
-int64_t ATAReturnAttributeRawValue(unsigned char id, const ata_smart_values * data);
+// Find attribute index for attribute id, -1 if not found.
+int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval);
 
 // Return Temperature Attribute raw value selected according to possible
 // non-default interpretations. If the Attribute does not exist, return 0
-unsigned char ATAReturnTemperatureValue(const ata_smart_values * data, const unsigned char * defs);
+unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs);
 
 
 // This are the meanings of the Self-test failure checkpoint byte.
@@ -788,14 +852,14 @@ const char *SelfTestFailureCodeName(unsigned char which);
 
 #define MAX_ATTRIBUTE_NUM 256
 
-// function to parse pairs like "9,minutes" or "220,temp".  See end of
-// extern.h for definition of defs[].  Returns 0 if pair recognized,
-// else 1 if there is a problem.
-int parse_attribute_def(const char * pair, unsigned char * defs);
+// Parse vendor attribute display def (-v option).
+// Return false on error.
+bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs,
+                         ata_vendor_def_prior priority);
 
 // Get ID and increase flag of current pending or offline
 // uncorrectable attribute.
-unsigned char get_unc_attr_id(bool offline, const unsigned char * defs,
+unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs,
                               bool & increase);
 
 // Return a multiline string containing a list of valid arguments for
index ed5f286c67c5e2e6ae8c9ada4a53f3b03e8d9052..9906a86ebd6320304be45fb06b3e797dffa62175 100644 (file)
@@ -44,7 +44,7 @@
 #include "utility.h"
 #include "knowndrives.h"
 
-const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 2860 2009-07-23 20:27:28Z chrfranke $"
+const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 2983 2009-11-14 21:41:41Z chrfranke $"
                                   ATAPRINT_H_CVSID;
 
 // for passing global control variables
@@ -773,87 +773,97 @@ static void PrintSmartConveyanceSelfTestPollingTime(const ata_smart_values * dat
     pout("recommended polling time: \t        Not Supported.\n");
 }
 
+// Check SMART attribute table for Threshold failure
+// onlyfailed=0: are or were any age or prefailure attributes <= threshold
+// onlyfailed=1: are any prefailure attributes <= threshold now
+static int find_failed_attr(const ata_smart_values * data,
+                            const ata_smart_thresholds_pvt * thresholds,
+                            const ata_vendor_attr_defs & defs, int onlyfailed)
+{
+  for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
+    const ata_smart_attribute & attr = data->vendor_attributes[i];
+
+    ata_attr_state state = ata_get_attr_state(attr,
+                             thresholds->thres_entries[i], defs);
+
+    if (!onlyfailed) {
+      if (state >= ATTRSTATE_FAILED_PAST)
+        return attr.id;
+    }
+    else {
+      if (state == ATTRSTATE_FAILED_NOW && ATTRIBUTE_FLAGS_PREFAILURE(attr.flags))
+        return attr.id;
+    }
+  }
+  return 0;
+}
+
 // onlyfailed=0 : print all attribute values
 // onlyfailed=1:  just ones that are currently failed and have prefailure bit set
 // onlyfailed=2:  ones that are failed, or have failed with or without prefailure bit set
 static void PrintSmartAttribWithThres(const ata_smart_values * data,
                                       const ata_smart_thresholds_pvt * thresholds,
-                                      const unsigned char * attributedefs,
+                                      const ata_vendor_attr_defs & defs,
                                       int onlyfailed)
 {
-  int needheader=1;
-  char rawstring[64];
-    
+  bool needheader = true;
+
   // step through all vendor attributes
   for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
-    const char *status;
-    const ata_smart_attribute * disk = data->vendor_attributes+i;
-    const ata_smart_threshold_entry * thre = thresholds->thres_entries+i;
-    
-    // consider only valid attributes (allowing some screw-ups in the
-    // thresholds page data to slip by)
-    if (disk->id){
-      const char *type, *update;
-      char attributename[64];
-
-      // Don't report a failed attribute if its threshold is 0.
-      // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing"
-      // threshold (Later ATA versions declare all thresholds as "obsolete").
-      // In practice, threshold value 0 is often used for usage attributes or
-      // appears if the thresholds cannot be read.
-      bool failednow  = (thre->threshold > 0 && disk->current <= thre->threshold);
-      bool failedever = (thre->threshold > 0 && disk->worst   <= thre->threshold);
-
-      // These break out of the loop if we are only printing certain entries...
-      if (onlyfailed==1 && (!ATTRIBUTE_FLAGS_PREFAILURE(disk->flags) || !failednow))
-        continue;
-      
-      if (onlyfailed==2 && !failedever)
-        continue;
-      
-      // print header only if needed
-      if (needheader){
-        if (!onlyfailed){
-          pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber);
-          pout("Vendor Specific SMART Attributes with Thresholds:\n");
-        }
-        pout("ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE\n");
-        needheader=0;
-      }
-      
-      // is this Attribute currently failed, or has it ever failed?
-      if (failednow)
-        status="FAILING_NOW";
-      else if (failedever)
-        status="In_the_past";
-      else
-        status="    -";
+    const ata_smart_attribute & attr = data->vendor_attributes[i];
+    const ata_smart_threshold_entry & thre = thresholds->thres_entries[i];
 
-      // Print name of attribute
-      ataPrintSmartAttribName(attributename, disk->id, attributedefs);
-      pout("%-28s",attributename);
+    // Check attribute and threshold
+    ata_attr_state state = ata_get_attr_state(attr, thre, defs);
+    if (state == ATTRSTATE_NON_EXISTING)
+      continue;
 
-      // printing line for each valid attribute
-      type=ATTRIBUTE_FLAGS_PREFAILURE(disk->flags)?"Pre-fail":"Old_age";
-      update=ATTRIBUTE_FLAGS_ONLINE(disk->flags)?"Always":"Offline";
+    // These break out of the loop if we are only printing certain entries...
+    if (onlyfailed == 1 && !(ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) && state == ATTRSTATE_FAILED_NOW))
+      continue;
 
-      pout("0x%04x   %.3d   %.3d   %.3d    %-10s%-9s%-12s", 
-             (int)disk->flags, (int)disk->current, (int)disk->worst,
-             (int)thre->threshold, type, update, status);
+    if (onlyfailed == 2 && state < ATTRSTATE_FAILED_PAST)
+      continue;
 
-      // print raw value of attribute
-      ataPrintSmartAttribRawValue(rawstring, disk, attributedefs);
-      pout("%s\n", rawstring);
-      
-      // Print a warning if there is inconsistency here and
-      // threshold info is not empty.
-      if (disk->id != thre->id && (thre->id || thre->threshold)) {
-        char atdat[64],atthr[64];
-        ataPrintSmartAttribName(atdat, disk->id, attributedefs);
-        ataPrintSmartAttribName(atthr, thre->id, attributedefs);
-        pout("%-28s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",atdat);
-        pout("%-28s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",atthr);
+    // print header only if needed
+    if (needheader) {
+      if (!onlyfailed) {
+        pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber);
+        pout("Vendor Specific SMART Attributes with Thresholds:\n");
       }
+      pout("ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE\n");
+      needheader = false;
+    }
+
+    // Format value, worst, threshold
+    std::string valstr, threstr;
+    if (state > ATTRSTATE_NO_NORMVAL)
+      valstr = strprintf("%.3d   %.3d", attr.current, attr.worst);
+    else
+      valstr = "---   ---";
+    if (state > ATTRSTATE_NO_THRESHOLD)
+      threstr = strprintf("%.3d", thre.threshold);
+    else
+      threstr = "---";
+
+    // 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",
+         attr.id, attrname.c_str(), attr.flags,
+         valstr.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" :
+          state == ATTRSTATE_FAILED_PAST ? "In_the_past" :
+                                           "    -"        ),
+         ata_format_attr_raw_value(attr, defs).c_str());
+
+    // Print a warning if there is inconsistency here
+    if (state == ATTRSTATE_BAD_THRESHOLD) {
+      pout("%3d %-24s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",
+           attr.id, attrname.c_str());
+      pout("%3d %-24s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",
+           thre.id, ata_get_smart_attr_name(thre.id, defs).c_str());
     }
   }
   if (!needheader) pout("\n");
@@ -1757,11 +1767,10 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   }
 
   // Use preset vendor attribute options unless user has requested otherwise.
-  unsigned char attributedefs[256];
-  memcpy(attributedefs, options.attributedefs, sizeof(attributedefs));
+  ata_vendor_attr_defs attribute_defs = options.attribute_defs;
   unsigned char fix_firmwarebug = options.fix_firmwarebug;
   if (!options.ignore_presets)
-    apply_presets(&drive, attributedefs, fix_firmwarebug, options.fix_swapped_id);
+    apply_presets(&drive, attribute_defs, fix_firmwarebug, options.fix_swapped_id);
 
   // Print most drive identity information if requested
   bool known = false;
@@ -1958,13 +1967,13 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     case 0:
       // The case where the disk health is OK
       pout("SMART overall-health self-assessment test result: PASSED\n");
-      if (ataCheckSmart(&smartval, &smartthres,0)){
+      if (find_failed_attr(&smartval, &smartthres, options.attribute_defs, 0)){
         if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
         else {
           PRINT_ON(con);
           pout("Please note the following marginal Attributes:\n");
-          PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 2);
+          PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2);
         } 
         returnval|=FAILAGE;
       }
@@ -1978,14 +1987,14 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
       pout("SMART overall-health self-assessment test result: FAILED!\n"
            "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
       PRINT_OFF(con);
-      if (ataCheckSmart(&smartval, &smartthres,1)){
+      if (find_failed_attr(&smartval, &smartthres, options.attribute_defs, 1)){
         returnval|=FAILATTR;
         if (options.smart_vendor_attrib)
           pout("See vendor-specific Attribute list for failed Attributes.\n\n");
         else {
           PRINT_ON(con);
           pout("Failed Attributes:\n");
-          PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 1);
+          PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1);
         }
       }
       else
@@ -1997,7 +2006,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     case -1:
     default:
       // The case where something went wrong with HDIO_DRIVE_TASK ioctl()
-      if (ataCheckSmart(&smartval, &smartthres,1)){
+      if (find_failed_attr(&smartval, &smartthres, options.attribute_defs, 1)){
         PRINT_ON(con);
         pout("SMART overall-health self-assessment test result: FAILED!\n"
              "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n");
@@ -2009,18 +2018,18 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
         else {
           PRINT_ON(con);
           pout("Failed Attributes:\n");
-          PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 1);
+          PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 1);
         }
       }
       else {
         pout("SMART overall-health self-assessment test result: PASSED\n");
-        if (ataCheckSmart(&smartval, &smartthres,0)){
+        if (find_failed_attr(&smartval, &smartthres, options.attribute_defs, 0)){
           if (options.smart_vendor_attrib)
             pout("See vendor-specific Attribute list for marginal Attributes.\n\n");
           else {
             PRINT_ON(con);
             pout("Please note the following marginal Attributes:\n");
-            PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs, 2);
+            PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, 2);
           } 
           returnval|=FAILAGE;
         }
@@ -2041,7 +2050,7 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   // Print vendor-specific attributes
   if (options.smart_vendor_attrib) {
     PRINT_ON(con);
-    PrintSmartAttribWithThres(&smartval, &smartthres, attributedefs,
+    PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs,
                               (con->printing_switchable ? 2 : 0));
     PRINT_OFF(con);
   }
@@ -2051,10 +2060,12 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
   ata_smart_log_directory smartlogdir_buf, gplogdir_buf;
   const ata_smart_log_directory * smartlogdir = 0, * gplogdir = 0;
 
-  if (   options.gp_logdir || options.smart_logdir
-      || options.sataphy || options.smart_ext_error_log
+  if (   options.gp_logdir
+      || options.smart_logdir
+      || options.smart_ext_error_log
       || options.smart_ext_selftest_log
-      || !options.log_requests.empty()                 ) {
+      || options.sataphy
+      || !options.log_requests.empty() ) {
     PRINT_ON(con);
     if (isGeneralPurposeLoggingCapable(&drive))
       pout("General Purpose Logging (GPL) feature set supported\n");
@@ -2063,7 +2074,8 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
     bool need_smart_logdir = options.smart_logdir;
     bool need_gp_logdir    = (   options.gp_logdir
                               || options.smart_ext_error_log
-                              || options.smart_ext_selftest_log);
+                              || options.smart_ext_selftest_log
+                              || options.sataphy               );
     unsigned i;
     for (i = 0; i < options.log_requests.size(); i++) {
       if (options.log_requests[i].gpl)
@@ -2323,12 +2335,19 @@ int ataPrintMain (ata_device * device, const ata_print_options & options)
 
   // Print SATA Phy Event Counters
   if (options.sataphy) {
-    unsigned char log_11[512] = {0, };
-    unsigned char features = (options.sataphy_reset ? 0x01 : 0x00);
-    if (!ataReadLogExt(device, 0x11, features, 0, log_11, 1))
-      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
-    else
-      PrintSataPhyEventCounters(log_11, options.sataphy_reset);
+    unsigned nsectors = GetNumLogSectors(gplogdir, 0x11, true);
+    if (!nsectors)
+      pout("SATA Phy Event Counters (GP Log 0x11) not supported\n");
+    else if (nsectors != 1)
+      pout("SATA Phy Event Counters with %u sectors not supported\n", nsectors);
+    else {
+      unsigned char log_11[512] = {0, };
+      unsigned char features = (options.sataphy_reset ? 0x01 : 0x00);
+      if (!ataReadLogExt(device, 0x11, features, 0, log_11, 1))
+        failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+      else
+        PrintSataPhyEventCounters(log_11, options.sataphy_reset);
+    }
   }
 
   // START OF THE TESTING SECTION OF THE CODE.  IF NO TESTING, RETURN
index a493892175f14e6c27fdfd9fba92b3823b2efcb0..58a629d7f734b7d53456f47693c8896d60cc04f8 100644 (file)
@@ -26,7 +26,7 @@
 #ifndef ATAPRINT_H_
 #define ATAPRINT_H_
 
-#define ATAPRINT_H_CVSID "$Id: ataprint.h,v 1.43 2009/07/07 19:28:29 chrfranke Exp $\n"
+#define ATAPRINT_H_CVSID "$Id: ataprint.h 2975 2009-10-29 22:52:38Z chrfranke $\n"
 
 #include <vector>
 
@@ -78,13 +78,7 @@ struct ata_print_options
   unsigned char fix_firmwarebug; // FIX_*, see atacmds.h
   bool fix_swapped_id; // Fix swapped ID strings returned by some buggy drivers
 
-  // The i'th entry in this array will modify the printed meaning of
-  // the i'th SMART attribute.  The default definitions of the
-  // Attributes are obtained by having the array be all zeros.  If
-  // attributedefs[i] is nonzero, it means that the i'th attribute has
-  // a non-default meaning.  See the ataPrintSmartAttribName and
-  // and parse_attribute_def functions.
-  unsigned char attributedefs[256];
+  ata_vendor_attr_defs attribute_defs; // -v options
 
   bool ignore_presets; // Ignore presets from drive database
   bool show_presets; // Show presets and exit
@@ -114,7 +108,7 @@ struct ata_print_options
       ignore_presets(false),
       show_presets(false),
       powermode(0)
-    { memset(attributedefs, 0, sizeof(attributedefs)); }
+    { }
 };
 
 int ataPrintMain(ata_device * device, const ata_print_options & options);
index e8ea75a66f016d346c07bc76b58291fad3529e77..9d6186fd5ef9e65abf1f41149093efd05cb70eba 100644 (file)
@@ -1,5 +1,5 @@
 #
-# $Id: configure.in 2927 2009-10-03 16:08:34Z chrfranke $
+# $Id: configure.in 2992 2009-12-04 17:05:21Z chrfranke $
 #
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ(2.50)
@@ -7,9 +7,9 @@ AC_INIT(smartmontools, 5.39, smartmontools-support@lists.sourceforge.net)
 AC_CONFIG_SRCDIR(smartctl.cpp)
 
 smartmontools_configure_date=`date -u +'%Y-%m-%d %T %Z'`
-smartmontools_cvs_tag=`echo '$Id: configure.in 2927 2009-10-03 16:08:34Z chrfranke $'`
-smartmontools_release_date=2008/03/10
-smartmontools_release_time="10:44:07 GMT"
+smartmontools_cvs_tag=`echo '$Id: configure.in 2992 2009-12-04 17:05:21Z chrfranke $'`
+smartmontools_release_date=2009-11-30
+smartmontools_release_time="20:24:12 UTC"
 
 AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_ARGS, "$ac_configure_args",            [smartmontools Configure Arguments])
 AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_DATE, "$smartmontools_configure_date", [smartmontools Configure Date])
@@ -310,8 +310,8 @@ AM_CONDITIONAL(OS_SOLARIS, [echo $host_os | grep '^solaris' > /dev/null])
 AM_CONDITIONAL(OS_WIN32_MINGW, [echo $host_os | grep '^mingw' > /dev/null])
 AM_CONDITIONAL(OS_FREEBSD, [echo $host_os | grep '^freebsd' > /dev/null])
 
-dnl Add -Wall and -W if using gcc and its not already specified.
-if test "x$GCC" = "xyes"; then
+dnl Add -Wall and -W if using g++ and its not already specified.
+if test "$GXX" = "yes"; then
   if test -z "`echo "$CXXFLAGS" | grep "\-Wall" 2> /dev/null`" ; then
       CXXFLAGS="$CXXFLAGS -Wall"
   fi
@@ -324,6 +324,21 @@ if test "x$GCC" = "xyes"; then
       # MinGW uses MSVCRT.DLL which uses printf format "%I64d" and not "%lld" for int64_t
       CXXFLAGS="$CXXFLAGS -Wno-format";;
   esac
+
+  # Disable strict aliasing rules by default (see ticket #23).
+  if test -z "`echo "$CXXFLAGS" | grep "\-f[[no-]]*strict-aliasing" 2> /dev/null`" ; then
+    AC_MSG_CHECKING([whether g++ supports -fno-strict-aliasing])
+    ac_save_CXXFLAGS="$CXXFLAGS"
+    CXXFLAGS="-fno-strict-aliasing"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
+      [gcc_have_fno_strict_aliasing=yes], [gcc_have_fno_strict_aliasing=no])
+    CXXFLAGS="$ac_save_CXXFLAGS"
+    if test "$gcc_have_fno_strict_aliasing" = "yes"; then
+      CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"
+    fi
+    AC_MSG_RESULT([$gcc_have_fno_strict_aliasing])
+  fi
+
 else
  dnl We are NOT using gcc, so enable host-specific compiler flags
  case "${host}" in
index 9f5ea792232ee01ef27ad38340e03f8c09978862..a14f47cedfc8a36191850f1be74c9762f823dc8f 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <stdexcept>
 
-const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
+const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 2971 2009-10-26 22:05:54Z chrfranke $"
   DEV_INTERFACE_H_CVSID;
 
 /////////////////////////////////////////////////////////////////////////////
@@ -301,29 +301,22 @@ smart_device * smart_interface::get_smart_device(const char * name, const char *
     // Recurse to allocate base device, default is standard SCSI
     if (!*basetype)
       basetype = "scsi";
-    dev = get_smart_device(name, basetype);
-    if (!dev) {
+    smart_device_auto_ptr basedev( get_smart_device(name, basetype) );
+    if (!basedev) {
       set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg());
       return 0;
     }
     // Result must be SCSI
-    if (!dev->is_scsi()) {
-      delete dev;
+    if (!basedev->is_scsi()) {
       set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype);
       return 0;
     }
     // Attach SAT tunnel
-    try {
-      ata_device * satdev = get_sat_device(sattype.c_str(), dev->to_scsi());
-      if (!satdev) {
-        delete dev;
-        return 0;
-      }
-      return satdev;
-    }
-    catch (...) {
-      delete dev; throw;
-    }
+    ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi());
+    if (!satdev)
+      return 0;
+    basedev.release();
+    return satdev;
   }
 
   else {
index 960a069af154af33b36045e9fc1325c86e474fcb..5f54fd8742c2f092af0ad561c21d64b784501bb3 100644 (file)
 #ifndef DEV_INTERFACE_H
 #define DEV_INTERFACE_H
 
-#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 2915 2009-09-18 21:17:37Z chrfranke $\n"
+#define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 2973 2009-10-26 22:38:19Z chrfranke $\n"
 
 #include <stdarg.h>
+#include <stdexcept>
 #include <string>
 #include <vector>
 
@@ -514,6 +515,95 @@ inline void smart_device::this_is_scsi(scsi_device * scsi)
 }
 
 
+/////////////////////////////////////////////////////////////////////////////
+/// Smart pointer class for device pointers
+
+template <class Dev>
+class any_device_auto_ptr
+{
+public:
+  typedef Dev device_type;
+
+  /// Construct from optional pointer to device
+  /// and optional pointer to base device.
+  explicit any_device_auto_ptr(device_type * dev = 0,
+                               smart_device * base_dev = 0)
+    : m_dev(dev), m_base_dev(base_dev) { }
+
+  /// Destructor deletes device object.
+  ~any_device_auto_ptr() throw()
+    { reset(); }
+
+  /// Assign a new pointer.
+  /// Throws if a pointer is already assigned.
+  void operator=(device_type * dev)
+    {
+      if (m_dev)
+        fail();
+      m_dev = dev;
+    }
+
+  /// Delete device object and clear the pointer.
+  void reset()
+    {
+      if (m_dev) {
+        if (m_base_dev && m_dev->owns(m_base_dev))
+          m_dev->release(m_base_dev);
+        delete m_dev;
+      }
+      m_dev = 0;
+    }
+
+  /// Return the pointer and release ownership.
+  device_type * release()
+    {
+      device_type * dev = m_dev;
+      m_dev = 0;
+      return dev;
+    }
+
+  /// Replace the pointer.
+  /// Used to call dev->autodetect_open().
+  void replace(device_type * dev)
+    { m_dev = dev; }
+
+  /// Return the pointer.
+  device_type * get() const
+    { return m_dev; }
+
+  /// Pointer dereferencing.
+  device_type & operator*() const
+    { return *m_dev; }
+
+  /// Pointer dereferencing.
+  device_type * operator->() const
+    { return m_dev; }
+
+  /// For (ptr != 0) check.
+  operator bool() const
+    { return !!m_dev; }
+
+  /// For (ptr == 0) check.
+  bool operator !() const
+    { return !m_dev; }
+
+private:
+  device_type * m_dev;
+  smart_device * m_base_dev;
+
+  void fail() const
+    { throw std::logic_error("any_device_auto_ptr: wrong usage"); }
+
+  // Prevent copy/assignment
+  any_device_auto_ptr(const any_device_auto_ptr<Dev> &);
+  void operator=(const any_device_auto_ptr<Dev> &);
+};
+
+typedef any_device_auto_ptr<smart_device> smart_device_auto_ptr;
+typedef any_device_auto_ptr<ata_device>   ata_device_auto_ptr;
+typedef any_device_auto_ptr<scsi_device>  scsi_device_auto_ptr;
+
+
 /////////////////////////////////////////////////////////////////////////////
 // smart_device_list
 
@@ -544,12 +634,15 @@ public:
     }
 
 
-  void add(smart_device * dev)
-    { m_list.push_back(dev); }
-
   void push_back(smart_device * dev)
     { m_list.push_back(dev); }
 
+  void push_back(smart_device_auto_ptr & dev)
+    {
+      m_list.push_back(dev.get());
+      dev.release();
+    }
+
   smart_device * at(unsigned i)
     { return m_list.at(i); }
 
index 8b39d3fc6b248eb131e15e7fa1b8468516fbec9d..c2a8cfa24ff5f86208d8df1735bffd4b522e16d2 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Home page of code is: http://smartmontools.sourceforge.net
  *
- * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net>
+ * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
  *
  * 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
@@ -24,7 +24,7 @@
 #include "dev_interface.h"
 #include "dev_ata_cmd_set.h"
 
-const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
+const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 2973 2009-10-26 22:38:19Z chrfranke $"
   DEV_INTERFACE_H_CVSID;
 
 extern smartmonctrl * con; // con->reportscsiioctl
@@ -405,44 +405,42 @@ smart_device * legacy_scsi_device::autodetect_open()
   int avail_len = req_buff[4] + 5;
   int len = (avail_len < req_len ? avail_len : req_len);
   if (len < 36)
-      return this;
+    return this;
 
   // Use INQUIRY to detect type
-  smart_device * newdev = 0;
-  try {
-    // 3ware ?
-    if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
-      close();
+
+  // 3ware ?
+  if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
+    close();
 #if defined(_WIN32) || defined(__CYGWIN__)
-      set_err(EINVAL, "AMCC/3ware controller, please try changing device to %s,N", get_dev_name());
+    set_err(EINVAL, "AMCC/3ware controller, please try changing device to %s,N", get_dev_name());
 #else
-      set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
-                      "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
+    set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
+                    "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
 #endif
-      return this;
-    }
+    return this;
+  }
 
-    // Marvell ?
-    if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) { // TODO: Linux-specific?
-      //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name());
-      close();
-      newdev = new legacy_marvell_device(smi(), get_dev_name(), get_req_type());
-      newdev->open(); // TODO: Can possibly pass open fd
-      delete this;
-      return newdev;
-    }
+  // Marvell ?
+  if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) { // TODO: Linux-specific?
+    //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name());
+    close();
+    smart_device_auto_ptr newdev(
+      new legacy_marvell_device(smi(), get_dev_name(), get_req_type()),
+      this
+    );
+    newdev->open(); // TODO: Can possibly pass open fd
+    delete this;
+    return newdev.release();
+  }
 
-    // SAT or USB ?
-    newdev = smi()->autodetect_sat_device(this, req_buff, len);
+  // SAT or USB ?
+  {
+    smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
     if (newdev)
       // NOTE: 'this' is now owned by '*newdev'
       return newdev;
   }
-  catch (...) {
-    // Cleanup if exception occurs after newdev was allocated
-    delete newdev;
-    throw;
-  }
 
   // Nothing special found
   return this;
@@ -518,7 +516,7 @@ smart_device * legacy_smart_interface::autodetect_smart_device(const char * name
 
 static void free_devnames(char * * devnames, int numdevs)
 {
-  static const char version[] = "$Id: dev_legacy.cpp 2915 2009-09-18 21:17:37Z chrfranke $";
+  static const char version[] = "$Id: dev_legacy.cpp 2973 2009-10-26 22:38:19Z chrfranke $";
   for (int i = 0; i < numdevs; i++)
     FreeNonZero(devnames[i], -1,__LINE__, version);
   FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version);
@@ -559,14 +557,14 @@ bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist,
   for (i = 0; i < numata; i++) {
     ata_device * atadev = get_ata_device(atanames[i], type);
     if (atadev)
-      devlist.add(atadev);
+      devlist.push_back(atadev);
   }
   free_devnames(atanames, numata);
 
   for (i = 0; i < numscsi; i++) {
     scsi_device * scsidev = get_scsi_device(scsinames[i], type);
     if (scsidev)
-      devlist.add(scsidev);
+      devlist.push_back(scsidev);
   }
   free_devnames(scsinames, numscsi);
   return true;
index 67b957af90d176bec33a35900f9e826f06bc10f3..0a4beee5c0336442c7c3519af1f6d09137acf50e 100755 (executable)
@@ -1,39 +1,19 @@
-#!/bin/bash -ev
+#!/bin/bash
 #
 # do a smartmontools release
-# (C) 2003-6 Bruce Allen <ballen4705@users.sourceforge.net>, 
-#          Guido Guenther <agx@sigxcpu.org>
-# $Id: do_release 2845 2009-07-18 13:25:18Z chrfranke $
-
-echo 'TODO: Rework this script for SVN.'
-exit 1
+# (C) 2003-9 Bruce Allen <ballen4705@users.sourceforge.net>,
+#            Guido Guenther <agx@sigxcpu.org>
+#            Christian Franke <smartmontools-support@lists.sourceforge.net>
+# $Id: do_release 2970 2009-10-26 18:36:22Z chrfranke $
 
 # Notes on generating releases:
 # (1) update NEWS
 # (2) update CHANGELOG -- put in release number
 # (3) update release number in configure.in 
-# (4) to test, set USECVS below to 0
-# (5) when satisfied, set USECVS below to 1
-
-USECVS=1
-
-KEYID=0x841ABAE8
-
-setup_cvs()
-{
-  CVS_SERVER=fakevalue
-  unset CVS_SERVER || echo "can't unset CVS_SERVER=$CVS_SERVER"
-  CVS_RSH=ssh
-  CVSROOT=:ext:ballen4705@smartmontools.cvs.sourceforge.net:/cvsroot/smartmontools
-}
+# (4) to test, run without '--commit'
+# (5) when satisfied, add option '--commit'
 
-get_release()
-{
-  VERSION=`grep 'AC_INIT' configure.in | awk '{ print $2 }' | sed s/,//g`
-  RELEASE="RELEASE_${VERSION//\./_}"
-  echo "Version: $VERSION"
-  echo "Release: $RELEASE"
-}
+set -e
 
 inc_release()
 {
@@ -48,52 +28,94 @@ inc_release()
   echo "New Release: $NEW_RELEASE"
 }
 
-# run automake/autoconf
-if [ -f Makefile ] ; then
-  make distcheck || exit 1
-  make clean
-  make distclean
-  rm -f Makefile configure
+COMMIT=
+RC=
+
+case "$1" in
+  --commit) COMMIT=yes; shift ;;
+esac
+
+case "$*" in
+  RC[1-9]) RC="$1" ;;
+  FINAL) ;;
+  *) echo "Usage: $0 [--commit] RC[1-9]|FINAL"; exit 1 ;;
+esac
+
+# Check workdir
+case "`/bin/pwd`" in
+  */trunk/smartmontools) ;;
+  *) echo "not run from trunk checkout"; exit 1 ;;
+esac
+
+if [ ! -d ../../tags ]; then
+  echo "tags directory missing"; exit 1
+fi
+
+REV=`(cd ../.. && svnversion)` || exit 1
+if [ -z "`echo "$REV" | sed -n '/^[0-9][0-9]*$/p'`" ]; then
+  echo "Working directory not clean: $REV"; exit 1
+fi
+
+# Get release number
+VERSION=`sed -n 's|^AC_INIT[^,]*, *\([0-9.]*\) *,.*$|\1|p' configure.in`
+if [ -z "$VERSION" ]; then
+  echo "AC_INIT not found in configure.in"; exit 1
 fi
+VERSIONRC="$VERSION"
+RELEASE="RELEASE_${VERSION//\./_}"
 
-smartmontools_release_date=`date -u +"%Y/%m/%d"`
+if [ "$RC" ]; then
+  VERSIONRC="${VERSION}-${RC/#RC/rc}"
+  RELEASE="${RELEASE}_${RC}"
+fi
+
+if [ -e "../../tags/$RELEASE" ]; then
+  echo "tags/$RELEASE exists"; exit 1
+fi
+
+echo "r$REV: Release $VERSIONRC $RELEASE"
+set -v
+
+# Update timestamp
+smartmontools_release_date=`date -u +"%Y-%m-%d"`
 smartmontools_release_time=`date -u +"%T %Z"`
 cat configure.in  | sed "s|smartmontools_release_date=.*|smartmontools_release_date=${smartmontools_release_date}|" > configure.tmp
 cat configure.tmp | sed "s|smartmontools_release_time=.*|smartmontools_release_time=\"${smartmontools_release_time}\"|" > configure.in
 rm -f configure.tmp
 
-./autogen.sh
-
-get_release
-
-# tag CVS version
-if [ $USECVS -ne 0 ] ; then
-    setup_cvs
-    cvs commit -m "Release $VERSION $RELEASE"
-    cvs tag -d $RELEASE 
-    cvs tag $RELEASE
+# Create tag and commit
+cd ../..
+if [ "$COMMIT" = "yes" ]; then
+  svn mkdir tags/$RELEASE
+  svn copy trunk/smartmontools tags/$RELEASE/smartmontools
+  svn commit -m "Release $VERSIONRC $RELEASE"
 fi
+cd trunk/smartmontools
+
+# Build
+./autogen.sh
 
-# build .tar.gz
-rm -rf build
 mkdir build
 cd build
 ../configure
 make distcheck || exit 1
+make maintainer-clean
 cd ..
 
-# increase release number:
-inc_release
-if [ $USECVS -ne 0 ] ; then
-    perl -p -i.bak -e "s/$PERL_OLD/$PERL_NEW/" configure.in
-fi
+TARFILE=smartmontools-$VERSIONRC.tar.gz
 
-cp -f build/smartmontools-$VERSION.tar.gz .
-if [ "$KEYID" ]; then
-  gpg --default-key $KEYID --armor --detach-sign ./smartmontools-$VERSION.tar.gz
+mv -f build/smartmontools-$VERSION.tar.gz $TARFILE
+rm -rvf build
+
+md5sum $TARFILE > $TARFILE.md5
+sha1sum $TARFILE > $TARFILE.sha1
+
+# Increase release number
+if [ -z "$RC" ]; then
+  inc_release
+  if [ "$COMMIT" = "yes" ]; then
+    perl -p -i.bak -e "s/$PERL_OLD/$PERL_NEW/" configure.in
+    # svn commit -m "Bump release number to $NEW_VERSION" configure.in
+  fi
 fi
 
-# cleanup
-rm -rf autom4te.cache build/ config.h.in Makefile.in examplescripts/Makefile.in \
-       depcomp mkinstalldirs install-sh configure config.guess config.sub \
-       aclocal.m4 missing *.bak
index 4ed09c84b6582fd1c495e4fb955bee47e1e56a61..9e9e15f81d2f400947b9c814d590d15a49754f79 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <stdexcept>
 
-const char *knowndrives_c_cvsid="$Id: knowndrives.cpp,v 1.207 2009/07/04 23:24:37 manfred99 Exp $"
+const char *knowndrives_c_cvsid="$Id: knowndrives.cpp 2986 2009-11-16 22:43:50Z manfred99 $"
 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID UTILITY_H_CVSID;
 
 #define MODEL_STRING_LENGTH                         40
@@ -70,8 +70,53 @@ static const drive_settings builtin_knowndrives[] = {
     "", "", ""
   },
   { "OCZ Vertex SSD",
-    "OCZ-VERTEX.*",
-    "", "", ""
+    "OCZ[ -]VERTEX.*",
+    "", "",
+    " -v 9,raw64"
+    " -v 12,raw64"
+    " -v 184,raw64,Initial_Bad_Block_Count"
+    " -v 195,raw64,Program_Failure_Blk_Ct"
+    " -v 196,raw64,Erase_Failure_Blk_Ct"
+    " -v 197,raw64,Read_Failure_Blk_Ct"
+    " -v 198,raw64,Read_Sectors_Tot_Ct"
+    " -v 199,raw64,Write_Sectors_Tot_Ct"
+    " -v 200,raw64,Read_Commands_Tot_Ct"
+    " -v 201,raw64,Write_Commands_Tot_Ct"
+    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
+    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
+    " -v 204,raw64,Bad_Block_Full_Flag"
+    " -v 205,raw64,Max_PE_Count_Spec"
+    " -v 206,raw64,Min_Erase_Count"
+    " -v 207,raw64,Max_Erase_Count"
+    " -v 208,raw64,Average_Erase_Count"
+    " -v 209,raw64,Remaining_Lifetime_Perc"
+  },
+  { "OCZ Agility SSD",
+    "OCZ[ -]AGILITY",
+    "", "",
+    " -v 9,raw64"
+    " -v 12,raw64"
+    " -v 184,raw64,Initial_Bad_Block_Count"
+    " -v 195,raw64,Program_Failure_Blk_Ct"
+    " -v 196,raw64,Erase_Failure_Blk_Ct"
+    " -v 197,raw64,Read_Failure_Blk_Ct"
+    " -v 198,raw64,Read_Sectors_Tot_Ct"
+    " -v 199,raw64,Write_Sectors_Tot_Ct"
+    " -v 200,raw64,Read_Commands_Tot_Ct"
+    " -v 201,raw64,Write_Commands_Tot_Ct"
+    " -v 202,raw64,Error_Bits_Flash_Tot_Ct"
+    " -v 203,raw64,Corr_Read_Errors_Tot_Ct"
+    " -v 204,raw64,Bad_Block_Full_Flag"
+    " -v 205,raw64,Max_PE_Count_Spec"
+    " -v 206,raw64,Min_Erase_Count"
+    " -v 207,raw64,Max_Erase_Count"
+    " -v 208,raw64,Average_Erase_Count"
+    " -v 209,raw64,Remaining_Lifetime_Perc"
+  },
+  { "Intel X25-E SSD",
+    "SSDSA2SH(032|064)G1.* INTEL",
+    "", "",
+    "-v 225,raw48,Host_Writes_Count"
   },
   { "Transcend Solid-State Drive",
     "TS(8|16|32|64|128)GSSD25-(M|S)",
@@ -99,8 +144,7 @@ static const drive_settings builtin_knowndrives[] = {
     "",
     "IBM Deskstar 60GXP drives may need upgraded SMART firmware.\n"
     "Please see http://www.geocities.com/dtla_update/index.html#rel and\n"
-    "http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215 or\n"
-    "http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215",
+    "http://www.ibm.com/pc/support/site.wss/MIGR-42215.html",
     ""
   },
   { "IBM Deskstar 40GV & 75GXP series (A5AA/A6AA firmware)",
@@ -113,8 +157,7 @@ static const drive_settings builtin_knowndrives[] = {
     "",
     "IBM Deskstar 40GV and 75GXP drives may need upgraded SMART firmware.\n"
     "Please see http://www.geocities.com/dtla_update/ and\n"
-    "http://www-3.ibm.com/pc/support/site.wss/document.do?lndocid=MIGR-42215 or\n"
-    "http://www-1.ibm.com/support/docview.wss?uid=psg1MIGR-42215",
+    "http://www.ibm.com/pc/support/site.wss/MIGR-42215.html",
     ""
   },
   { "", // ExcelStor J240, J340, J360, J680, and J880
@@ -218,7 +261,8 @@ static const drive_settings builtin_knowndrives[] = {
   },
   { "Fujitsu MHY2 BH series",
     "FUJITSU MHY2(04|06|08|10|12|16|20|25)0BH.*",
-    "", "", ""
+    "", "",
+    "-v 240,raw48,Transfer_Error_Rate"
   },
   { "Fujitsu MHW2 BH series",
     "FUJITSU MHW2(04|06|08|10|12|16)0BH.*",
@@ -759,6 +803,10 @@ static const drive_settings builtin_knowndrives[] = {
     "(Hitachi |HITACHI )?HTS5425(80|12|16|20|25)K9(A3|SA)00",
     "", "", ""
   },
+  { "Hitachi Travelstar 5K320 series",
+    "(Hitachi |HITACHI )?HT(S|E)5432(80|12|16|25|32)L9(A300|SA01)",
+    "", "", ""
+  },
   { "Hitachi Travelstar 7K60",
     "(Hitachi )?HTS726060M9AT00",
     "", "", ""
@@ -843,6 +891,10 @@ static const drive_settings builtin_knowndrives[] = {
     "(Hitachi )?HDT7210((16|25)SLA380|(32|50|64|75|10)SLA360)",
     "", "", ""
   },
+  { "Hitachi Deskstar 7K2000",
+    "Hitachi HDS722020ALA330",
+    "", "", ""
+  },
   { "Hitachi Ultrastar 7K1000",
     "(Hitachi )?HUA7210(50|75|10)KLA330",
     "", "", ""
@@ -931,6 +983,14 @@ static const drive_settings builtin_knowndrives[] = {
     "ST9((80|120|160)411|(250|320)421)ASG?",
     "", "", ""
   },
+  { "Seagate Momentus 7200.4 series",
+    "ST9(160412|250410|320423|500420)ASG?",
+    "", "", ""
+  },
+  { "Seagate Momentus 7200 FDE.2 series",
+    "ST9((160413|25041[12]|320426|50042[12])AS|(16041[89]|2504[16]4|32042[67]|500426)ASG)",
+    "", "", ""
+  },
   { "Seagate Medalist 1010, 1721, 2120, 3230 and 4340",  // ATA2, with -t permissive
     "ST3(1010|1721|2120|3230|4340)A",
     "", "", ""
@@ -1023,7 +1083,7 @@ static const drive_settings builtin_knowndrives[] = {
   },
   { "Seagate Barracuda 7200.11 family", // fixed firmware
     "ST3(160813|320[68]13|640[36]23|1000333|1500341)AS?",
-    "SD1B", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207957
+    "SD[12]B", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207957
     "", ""
   },
   { "Seagate Barracuda 7200.11 family", // buggy firmware
@@ -1221,6 +1281,10 @@ static const drive_settings builtin_knowndrives[] = {
     "WDC WD((360|740|800)GD|(360|740|1500)ADF[DS])-.*",
     "", "", ""
   },
+  { "Western Digital Raptor X",
+    "WDC WD1500AHFD-.*",
+    "", "", ""
+  },
   { "Western Digital VelociRaptor family",
     "WDC WD((1500|3000)B|3000G)LFS-.*",
     "", "", ""
@@ -1245,6 +1309,14 @@ static const drive_settings builtin_knowndrives[] = {
     "WDC WD(8|12|16|25|32)00B[EJ]KT-.*",
     "", "", ""
   },
+  { "Western Digital My Passport Essential hard drive (USB interface)",
+    "WDC WD3200BMVU-.*",
+    "", "", ""
+  },
+  { "Western Digital My Passport hard drive (USB interface)",
+    "WDC WD3200BMVV-.*",
+    "", "", ""
+  },
   { "Quantum Bigfoot series",
     "QUANTUM BIGFOOT TS10.0A",
     "", "", ""
@@ -1434,7 +1506,8 @@ const drive_settings * lookup_drive(const char * model, const char * firmware)
 }
 
 // Parse '-v' and '-F' options in preset string, return false on error.
-static bool parse_presets(const char * presets, unsigned char * opts, unsigned char & fix_firmwarebug)
+static bool parse_presets(const char * presets, ata_vendor_attr_defs & defs,
+                          unsigned char & fix_firmwarebug)
 {
   for (int i = 0; ; ) {
     i += strspn(presets+i, " \t");
@@ -1444,14 +1517,9 @@ static bool parse_presets(const char * presets, unsigned char * opts, unsigned c
     if (!(sscanf(presets+i, "-%c %40[^ ]%n", &opt, arg, &len) >= 2 && len > 0))
       return false;
     if (opt == 'v') {
-      // Parse "-v N,option"
-      unsigned char newopts[MAX_ATTRIBUTE_NUM] = {0, };
-      if (parse_attribute_def(arg, newopts))
+      // Parse "-v N,format[,name]"
+      if (!parse_attribute_def(arg, defs, PRIOR_DATABASE))
         return false;
-      // Set only if not set by user
-      for (int j = 0; j < MAX_ATTRIBUTE_NUM; j++)
-        if (newopts[j] && !opts[j])
-          opts[j] = newopts[j];
     }
     else if (opt == 'F') {
       unsigned char fix;
@@ -1508,19 +1576,16 @@ static int showonepreset(const drive_settings * dbentry)
   unsigned char fix_firmwarebug = 0;
   bool first_preset = true;
   if (*dbentry->presets) {
-    unsigned char opts[MAX_ATTRIBUTE_NUM] = {0,};
-    if (!parse_presets(dbentry->presets, opts, fix_firmwarebug)) {
+    ata_vendor_attr_defs defs;
+    if (!parse_presets(dbentry->presets, defs, fix_firmwarebug)) {
       pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
       errcnt++;
     }
     for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
-      char out[256];
-      if (opts[i]) {
-        ataPrintSmartAttribName(out, i, opts);
+      if (defs[i].priority != PRIOR_DEFAULT) {
         // Use leading zeros instead of spaces so that everything lines up.
-        out[0] = (out[0] == ' ') ? '0' : out[0];
-        out[1] = (out[1] == ' ') ? '0' : out[1];
-        pout("%-*s %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", out);
+        pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "",
+             i, ata_get_smart_attr_name(i, defs).c_str());
         first_preset = false;
       }
     }
@@ -1648,7 +1713,7 @@ void show_presets(const ata_identify_device * drive, bool fix_swapped_id)
 // (if any) for the given drive in knowndrives[].  Values that have
 // already been set in opts will not be changed.  Returns false if drive
 // not recognized.
-bool apply_presets(const ata_identify_device *drive, unsigned char * opts,
+bool apply_presets(const ata_identify_device *drive, ata_vendor_attr_defs & defs,
                    unsigned char & fix_firmwarebug, bool fix_swapped_id)
 {
   // get the drive's model/firmware strings
@@ -1663,7 +1728,7 @@ bool apply_presets(const ata_identify_device *drive, unsigned char * opts,
 
   if (*dbentry->presets) {
     // Apply presets
-    if (!parse_presets(dbentry->presets, opts, fix_firmwarebug))
+    if (!parse_presets(dbentry->presets, defs, fix_firmwarebug))
       pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
   }
   return true;
@@ -1883,8 +1948,8 @@ static bool parse_drive_database(parse_ptr src, drive_database & db, const char
             break;
           case 4:
             if (!token.value.empty()) {
-              unsigned char opts[MAX_ATTRIBUTE_NUM] = {0, }; unsigned char fix = 0;
-              if (!parse_presets(token.value.c_str(), opts, fix)) {
+              ata_vendor_attr_defs defs; unsigned char fix = 0;
+              if (!parse_presets(token.value.c_str(), defs, fix)) {
                 pout("%s(%d): Syntax error in preset option string\n", path, token.line);
                 ok = false;
               }
index 3908e40f918eafbd54e46eef96f586af44456c5c..9b3c611c6af929483db5b356df255c16fdb46752 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef KNOWNDRIVES_H_
 #define KNOWNDRIVES_H_
 
-#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h,v 1.23 2009/04/16 21:24:08 chrfranke Exp $\n"
+#define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 2975 2009-10-29 22:52:38Z chrfranke $\n"
 
 /* Structure used to store settings for specific drives in knowndrives[]. The
  * elements are used in the following ways:
@@ -69,7 +69,7 @@ int showmatchingpresets(const char *model, const char *firmware);
 // (if any) for the given drive in knowndrives[].  Values that have
 // already been set in opts will not be changed.  Also sets options in
 // con.  Returns false if drive not recognized.
-bool apply_presets(const ata_identify_device * drive, unsigned char * opts,
+bool apply_presets(const ata_identify_device * drive, ata_vendor_attr_defs & defs,
                    unsigned char & fix_firmwarebug, bool fix_swapped_id);
 
 // Read drive database from file.
index 0f92fc0f023ce0996f769ee15a3006694d4bc36d..4df4b2d1f16dc6bd4aa085c730f09479a3f94ab7 100644 (file)
@@ -71,9 +71,9 @@
 #define PATHINQ_SETTINGS_SIZE   128
 #endif
 
-static __unused const char *filenameandversion="$Id: os_freebsd.cpp 2955 2009-10-10 12:34:08Z samm2 $";
+static __unused const char *filenameandversion="$Id: os_freebsd.cpp 2973 2009-10-26 22:38:19Z chrfranke $";
 
-const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 2955 2009-10-10 12:34:08Z samm2 $" \
+const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 2973 2009-10-26 22:38:19Z chrfranke $" \
 ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 extern smartmonctrl * con;
@@ -121,7 +121,7 @@ void printwarning(int msgNo, const char* extra) {
 // global variable holding byte count of allocated memory
 long long bytes;
 
-const char * dev_freebsd_cpp_cvsid = "$Id: os_freebsd.cpp 2955 2009-10-10 12:34:08Z samm2 $"
+const char * dev_freebsd_cpp_cvsid = "$Id: os_freebsd.cpp 2973 2009-10-26 22:38:19Z chrfranke $"
   DEV_INTERFACE_H_CVSID;
 
 extern smartmonctrl * con; // con->reportscsiioctl
@@ -1218,27 +1218,22 @@ smart_device * freebsd_scsi_device::autodetect_open()
     return this;
 
   // Use INQUIRY to detect type
-  smart_device * newdev = 0;
-  try {
-    // 3ware ?
-    if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
-      close();
-      set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
-                      "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
-      return this;
-    }
 
-    // SAT or USB ?
-    newdev = smi()->autodetect_sat_device(this, req_buff, len);
+  // 3ware ?
+  if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
+    close();
+    set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
+                    "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
+    return this;
+  }
+
+  // SAT or USB ?
+  {
+    smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
     if (newdev)
       // NOTE: 'this' is now owned by '*newdev'
       return newdev;
   }
-  catch (...) {
-    // Cleanup if exception occurs after newdev was allocated
-    delete newdev;
-    throw;
-  }
 
   // Nothing special found
   return this;
@@ -1593,19 +1588,19 @@ bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist,
   for (i = 0; i < numata; i++) {
     ata_device * atadev = get_ata_device(atanames[i], type);
     if (atadev)
-      devlist.add(atadev);
+      devlist.push_back(atadev);
   }
 
   for (i = 0; i < numscsi; i++) {
     if(!*type) { // try USB autodetection if no type specified
       smart_device * smartdev = autodetect_smart_device(scsinames[i]);
       if(smartdev)
-        devlist.add(smartdev);
+        devlist.push_back(smartdev);
     }
     else {
       scsi_device * scsidev = get_scsi_device(scsinames[i], type);
       if (scsidev)
-        devlist.add(scsidev);
+        devlist.push_back(scsidev);
     }
   }
   return true;
index 5635eaa01454552dcd1608f1638e26e80a8d6697..9369630999e18dab92e8278c814715bbf0d9f948 100644 (file)
@@ -90,7 +90,7 @@
 
 #define ARGUSED(x) ((void)(x))
 
-const char *os_XXXX_c_cvsid="$Id: os_linux.cpp 2951 2009-10-08 23:43:46Z samm2 $" \
+const char *os_XXXX_c_cvsid="$Id: os_linux.cpp 2993 2009-12-04 17:29:50Z chrfranke $" \
 ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_LINUX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 /* for passing global control variables */
@@ -493,6 +493,7 @@ int linux_ata_device::ata_command_interface(smart_command_set command, int selec
 #define SG_IO_RESP_SENSE_LEN 64 /* large enough see buffer */
 #define LSCSI_DRIVER_MASK  0xf /* mask out "suggestions" */
 #define LSCSI_DRIVER_SENSE  0x8 /* alternate CHECK CONDITION indication */
+#define LSCSI_DID_ERROR 0x7 /* Need to work around aacraid driver quirk */
 #define LSCSI_DRIVER_TIMEOUT  0x6
 #define LSCSI_DID_TIME_OUT  0x3
 #define LSCSI_DID_BUS_BUSY  0x2
@@ -617,7 +618,10 @@ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report,
                 (LSCSI_DID_TIME_OUT == io_hdr.host_status))
                 return -ETIMEDOUT;
             else
-                return -EIO;    /* catch all */
+               /* Check for DID_ERROR - workaround for aacraid driver quirk */
+               if (LSCSI_DID_ERROR != io_hdr.host_status) {
+                       return -EIO; /* catch all if not DID_ERR */
+               }
         }
         if (0 != masked_driver_status) {
             if (LSCSI_DRIVER_TIMEOUT == masked_driver_status)
@@ -902,6 +906,8 @@ linux_megaraid_device::~linux_megaraid_device() throw()
 
 smart_device * linux_megaraid_device::autodetect_open()
 {
+  int report = con->reportscsiioctl; 
+
   // Open device
   if (!open())
     return this;
@@ -924,22 +930,17 @@ smart_device * linux_megaraid_device::autodetect_open()
   if (len < 36)
       return this;
 
-  printf("Got MegaRAID inquiry.. %s\n", req_buff+8);
+  if (report)
+    printf("Got MegaRAID inquiry.. %s\n", req_buff+8);
 
   // Use INQUIRY to detect type
-  smart_device * newdev = 0;
-  try {
+  {
     // SAT or USB ?
-    newdev = smi()->autodetect_sat_device(this, req_buff, len);
+    ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
     if (newdev)
       // NOTE: 'this' is now owned by '*newdev'
       return newdev;
   }
-  catch (...) {
-    // Cleanup if exception occurs after newdev was allocated
-    delete newdev;
-    throw;
-  }
 
   // Nothing special found
   return this;
@@ -1051,12 +1052,12 @@ bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop)
     // Emulate SMART STATUS CHECK drive reply
     // smartctl fail to work without this
     if(iop->cmnd[2]==0x2c) {
-      iop->resp_sense_len=22;
-      iop->sensep[0]=0x72; // response code
-      iop->sensep[7]=0x0e; // no idea what it is, copied from sat device answer
-      iop->sensep[8]=0x09; // 
-      iop->sensep[17]=0x4f; // lm
-      iop->sensep[19]=0xc2; // lh
+      iop->resp_sense_len=22; // copied from real response
+      iop->sensep[0]=0x72; // descriptor format
+      iop->sensep[7]=0x0e; // additional length
+      iop->sensep[8]=0x09; // description pointer
+      iop->sensep[17]=0x4f; // low cylinder GOOD smart status
+      iop->sensep[19]=0xc2; // high cylinder GOOD smart status
     }
     return true;
   }
@@ -1544,7 +1545,7 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
       passthru->size++;
   }
   else
-    set_err(EINVAL);
+    return set_err(EINVAL);
 
   // Now send the command down through an ioctl()
   int ioctlreturn;
@@ -1608,7 +1609,7 @@ bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out
   }
 
   // Return register values
-  {
+  if (passthru) {
     ata_out_regs_48bit & r = out.out_regs;
     r.error           = passthru->features;
     r.sector_count_16 = passthru->sector_count;
@@ -2668,46 +2669,44 @@ smart_device * linux_scsi_device::autodetect_open()
   int avail_len = req_buff[4] + 5;
   int len = (avail_len < req_len ? avail_len : req_len);
   if (len < 36)
-      return this;
+    return this;
 
   // Use INQUIRY to detect type
-  smart_device * newdev = 0;
-  try {
-    // 3ware ?
-    if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
-      close();
-      set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
-                      "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
-      return this;
-    }
-    // DELL?
-    if (!memcmp(req_buff + 8, "DELL    PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8)) {
-      close();
-      set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'");
-      return this;
-    }
-    
-    // Marvell ?
-    if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) {
-      //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name());
-      close();
-      newdev = new linux_marvell_device(smi(), get_dev_name(), get_req_type());
-      newdev->open(); // TODO: Can possibly pass open fd
-      delete this;
-      return newdev;
-    }
 
-    // SAT or USB ?
-    newdev = smi()->autodetect_sat_device(this, req_buff, len);
+  // 3ware ?
+  if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) {
+    close();
+    set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n"
+                    "you may need to replace %s with /dev/twaN or /dev/tweN", get_dev_name());
+    return this;
+  }
+
+  // DELL?
+  if (!memcmp(req_buff + 8, "DELL    PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8)) {
+    close();
+    set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'");
+    return this;
+  }
+
+  // Marvell ?
+  if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) {
+    //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name());
+    close();
+    smart_device_auto_ptr newdev(
+      new linux_marvell_device(smi(), get_dev_name(), get_req_type())
+    );
+    newdev->open(); // TODO: Can possibly pass open fd
+    delete this;
+    return newdev.release();
+  }
+
+  // SAT or USB ?
+  {
+    smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len);
     if (newdev)
       // NOTE: 'this' is now owned by '*newdev'
       return newdev;
   }
-  catch (...) {
-    // Cleanup if exception occurs after newdev was allocated
-    delete newdev;
-    throw;
-  }
 
   // Nothing special found
   return this;
@@ -2896,7 +2895,7 @@ bool linux_smart_interface::get_dev_list(smart_device_list & devlist,
       else
         dev = new linux_ata_device(this, name, req_type);
       if (dev) // autodetect_smart_device() may return nullptr.
-        devlist.add(dev);
+        devlist.push_back(dev);
     }
   }
 
index a0f6c4e70d14c3b0de95eef4a1904f53d1cbb459..b885e8bd332bcdf3c2ba34c048645409efc60463 100644 (file)
@@ -48,7 +48,7 @@ extern smartmonctrl * con; // con->permissive,reportataioctl
 
 
 // Needed by '-V' option (CVS versioning) of smartd/smartctl
-const char *os_XXXX_c_cvsid="$Id: os_win32.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
+const char *os_XXXX_c_cvsid="$Id: os_win32.cpp 2973 2009-10-26 22:38:19Z chrfranke $"
 ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID;
 
 
@@ -2440,7 +2440,7 @@ bool win9x_smart_interface::ata_scan(smart_device_list & devlist)
     if (!(devmap & (1 << i)))
       continue;
     sprintf(name, "/dev/hd%c", 'a'+i);
-    devlist.add( new win_ata_device(this, name, "ata") );
+    devlist.push_back( new win_ata_device(this, name, "ata") );
   }
   return true;
 }
@@ -2469,7 +2469,7 @@ bool winnt_smart_interface::ata_scan(smart_device_list & devlist)
       for (int pi = 0; pi < 32; pi++) {
         if (vers_ex.dwDeviceMapEx & (1L << pi)) {
             sprintf(name, "/dev/sd%c,%u", 'a'+i, pi);
-            devlist.add( new win_ata_device(this, name, "ata") );
+            devlist.push_back( new win_ata_device(this, name, "ata") );
         }
       }
       continue;
@@ -2477,7 +2477,7 @@ bool winnt_smart_interface::ata_scan(smart_device_list & devlist)
 
     // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returns ATA/SATA
     sprintf(name, "/dev/sd%c", 'a'+i);
-    devlist.add( new win_ata_device(this, name, "ata") );
+    devlist.push_back( new win_ata_device(this, name, "ata") );
   }
 
   return true;
@@ -3209,7 +3209,7 @@ bool win9x_smart_interface::scsi_scan(smart_device_list & devlist)
           pout("  ID %u: Device Type=0x%02x\n", id, srb.t.devtype);
         char name[20];
         sprintf(name, "/dev/scsi%u%u", ad, id);
-        devlist.add( new win_aspi_device(this, name, "scsi") );
+        devlist.push_back( new win_aspi_device(this, name, "scsi") );
       }
       else if (con->reportscsiioctl)
         pout("  ID %u: Device Type=0x%02x (ignored)\n", id, srb.t.devtype);
@@ -3432,7 +3432,7 @@ bool winnt_smart_interface::scsi_scan(smart_device_list & devlist)
       continue;
     // STORAGE_QUERY_PROPERTY returned SCSI/SAS/...
     sprintf(name, "/dev/sd%c", 'a'+i);
-    devlist.add( new win_scsi_device(this, name, "scsi") );
+    devlist.push_back( new win_scsi_device(this, name, "scsi") );
   }
   return true;
 }
index 1a02b4ae92b70c350ff880b0e0b1e39525918bbf..495bcbf1982565b6e6fc8aa61dead87450e149a9 100644 (file)
@@ -61,7 +61,7 @@
 #include "dev_ata_cmd_set.h" // ata_device_with_command_set
 #include "dev_tunnelled.h" // tunnelled_device<>
 
-const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 2923 2009-09-24 20:10:38Z chrfranke $";
+const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 2988 2009-11-29 16:21:07Z samm2 $";
 
 /* for passing global control variables */
 extern smartmonctrl *con;
@@ -1307,40 +1307,11 @@ ata_device * smart_interface::autodetect_sat_device(scsi_device * scsidev,
   if (!scsidev->is_open())
     return 0;
 
-  ata_device * atadev = 0;
-  try {
-    // SAT ?
-    if (inqdata && inqsize >= 36 && !memcmp(inqdata + 8, "ATA     ", 8)) { // TODO: Linux-specific?
-      atadev = new sat_device(this, scsidev, "");
-      if (has_sat_pass_through(atadev))
-        return atadev; // Detected SAT
-      atadev->release(scsidev);
-      delete atadev;
-    }
-
-/* The new usbcypress_device(this, scsidev, "", 0x24) sends vendor specific comand to non-cypress devices.
- * It's dangerous as other device may interpret such command as own valid vendor specific command.
- * I commented it out untill problem resolved
- */
-#if 0
-    // USB ?
-    {
-      atadev = new usbcypress_device(this, scsidev, "", 0x24);
-      if (has_usbcypress_pass_through(atadev,
-            (inqdata && inqsize >= 36 ? (const char*)inqdata  + 8 : 0),
-            (inqdata && inqsize >= 36 ? (const char*)inqdata + 16 : 0) ))
-        return atadev; // Detected USB
-      atadev->release(scsidev);
-      delete atadev;
-    }
-#endif
-  }
-  catch (...) {
-    if (atadev) {
-      atadev->release(scsidev);
-      delete atadev;
-    }
-    throw;
+  // SAT ?
+  if (inqdata && inqsize >= 36 && !memcmp(inqdata + 8, "ATA     ", 8)) { // TODO: Linux-specific?
+    ata_device_auto_ptr atadev( new sat_device(this, scsidev, "") , scsidev);
+    if (has_sat_pass_through(atadev.get()))
+      return atadev.release(); // Detected SAT
   }
 
   return 0;
@@ -1374,14 +1345,20 @@ const usb_id_entry usb_ids[] = {
   { 0x04fc, 0x0c15, 0xf615, d_sunplus }, // SunPlus SPDIF215
   { 0x04fc, 0x0c25, 0x0103, d_sunplus }, // SunPlus SPDIF225 (USB+SATA->SATA)
   // Iomega
+  { 0x059b, 0x0272,     -1, d_cypress }, // Iomega LPHD080-0
   { 0x059b, 0x0275, 0x0001, d_unsup   }, // Iomega MDHD500-U
   // LaCie
   { 0x059f, 0x0651,     -1, d_unsup   }, // LaCie hard disk (FA Porsche design)
   { 0x059f, 0x1018,     -1, d_sat     }, // LaCie hard disk (Neil Poulton design)
   // In-System Design
   { 0x05ab, 0x0060, 0x1101, d_cypress }, // In-System/Cypress ISD-300A1
+  // Genesys Logic
+  { 0x05e3, 0x0702,     -1, d_unsup   }, // Genesys Logic GL881E
+  { 0x05e3, 0x0718, 0x0041, d_sat     }, // Genesys Logic ? (TODO: requires '-T permissive')
   // Prolific
   { 0x067b, 0x3507, 0x0001, d_unsup   }, // Prolific PL3507
+  // Freecom
+  { 0x07ab, 0xfc8e, 0x010f, d_sunplus }, // Freecom Hard Drive XS
   // Toshiba
   { 0x0930, 0x0b09,     -1, d_sunplus }, // Toshiba PX1396E-3T01 (similar to Dura Micro 501)
   // Seagate
@@ -1396,8 +1373,10 @@ const usb_id_entry usb_ids[] = {
   { 0x0d49, 0x7410, 0x0122, d_sat     }, // Maxtor Basics Desktop
   { 0x0d49, 0x7450, 0x0122, d_sat     }, // Maxtor Basics Portable
   // Western Digital
+  { 0x1058, 0x0702, 0x0104, d_sat     }, // WD My Passport Portable  
   { 0x1058, 0x0704, 0x0175, d_sat     }, // WD My Passport Essential
   { 0x1058, 0x0705, 0x0175, d_sat     }, // WD My Passport Elite
+  { 0x1058, 0x070a, 0x1028, d_sat     }, // WD My Passport 070A
   { 0x1058, 0x0906, 0x0012, d_sat     }, // WD My Book ES
   { 0x1058, 0x1001, 0x0104, d_sat     }, // WD Elements Desktop
   { 0x1058, 0x1003, 0x0175, d_sat     }, // WD Elements Desktop WDE1UBK...
@@ -1405,6 +1384,7 @@ const usb_id_entry usb_ids[] = {
   { 0x1058, 0x1100, 0x0165, d_sat     }, // WD My Book Essential
   { 0x1058, 0x1102, 0x1028, d_sat     }, // WD My Book
   // Initio
+  { 0x13fd, 0x0540,     -1, d_unsup   }, // Initio 316000
   { 0x13fd, 0x1240, 0x0104, d_sat     }, // Initio ? (USB->SATA)
   { 0x13fd, 0x1340, 0x0208, d_sat     }, // Initio ? (USB+SATA->SATA)
   // JMicron
index ed928ddb203fd02eb402c639d12ca49882d1b213..7082f5c8de1b3946507a8ec239270ed80c4e076c 100644 (file)
@@ -1,7 +1,7 @@
 .ig
  Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
- $Id: smartctl.8.in 2922 2009-09-22 16:27:33Z chrfranke $
+ $Id: smartctl.8.in 2978 2009-10-30 23:20:39Z chrfranke $
  
  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
@@ -1017,42 +1017,87 @@ writes a binary representation of the one sector log 0x11
 (SATA Phy Event Counters) to file log.bin.
 
 .TP
-.B \-v N,OPTION, \-\-vendorattribute=N,OPTION
-[ATA only] Sets a vendor\-specific display OPTION for Attribute N. This
-option may be used multiple times. Valid arguments to this option are:
+.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.
+This option may be used multiple times.
 
-.I help
+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.
+
+.I \-v help
 \- Prints (to STDOUT) a list of all valid arguments to this option,
 then exits.
 
-.I 9,minutes
-\- Raw Attribute number 9 is power\-on time in minutes.  Its raw value
+Valid arguments for FORMAT are:
+
+.I raw8
+\- Print the Raw value as six 8\-bit unsigned base\-10 integers.
+This may be useful for decoding the meaning of the Raw value.
+
+.I raw16
+\- Print the Raw value as three 16\-bit unsigned base\-10 integers.
+This may be useful for decoding the meaning of the Raw value.
+
+.I raw48
+\- Print the Raw value as a 48\-bit unsigned base\-10 integer.
+This is the default for most attributes.
+
+.I hex48
+\- Print the Raw value as a 12 digit hexadecimal number.
+This may be useful for decoding the meaning of the Raw value.
+
+.I raw64
+\- Print the Raw value as a 64\-bit unsigned base\-10 integer.
+This includes two bytes from the normalized and worst attribute value.
+This new raw format is used by some recent SSD devices.
+
+.I hex64
+\- Print the Raw value as a 16 digit hexadecimal number.
+This includes two bytes from the normalized and worst attribute value.
+This new raw format is used by some recent SSD devices.
+
+.I min2hour
+\- Raw Attribute is power\-on time in minutes.  Its raw value
 will be displayed in the form "Xh+Ym".  Here X is hours, and Y is
 minutes in the range 0\-59 inclusive.  Y is always printed with two
 digits, for example "06" or "31" or "00".
 
-.I 9,seconds
-\- Raw Attribute number 9 is power\-on time in seconds.  Its raw value
+.I sec2hour
+\- Raw Attribute is power\-on time in seconds.  Its raw value
 will be displayed in the form "Xh+Ym+Zs".  Here X is hours, Y is
 minutes in the range 0\-59 inclusive, and Z is seconds in the range
 0\-59 inclusive.  Y and Z are always printed with two digits, for
 example "06" or "31" or "00".
 
-.I 9,halfminutes
-\- Raw Attribute number 9 is power\-on time, measured in units of 30
+.I halfmin2hour
+\- Raw Attribute is power\-on time, measured in units of 30
 seconds.  This format is used by some Samsung disks.  Its raw value
 will be displayed in the form "Xh+Ym".  Here X is hours, and Y is
 minutes in the range 0\-59 inclusive.  Y is always printed with two
 digits, for example "06" or "31" or "00".
 
-.I 9,temp
-\- Raw Attribute number 9 is the disk temperature in Celsius.
+.I tempminmax
+\- Raw Attribute is the disk temperature in Celsius.  Info about
+Lifetime Min/Max temperature is printed if available.  This is the
+default for Attributes 190 and 194.
 
-.I 192,emergencyretractcyclect
-\- Raw Attribute number 192 is the Emergency Retract Cycle Count.
+.I temp10x
+\- Raw Attribute is ten times the disk temperature in Celsius.
 
-.I 193,loadunload
-\- Raw Attribute number 193 contains two values. The first is the
+.I raw16(raw16)
+\- Print the raw attribute as a 16\-bit value and two optional
+16\-bit values if these words are nonzero.  This is the default
+for Attributes 5 and 196.
+
+.I raw16(avg16)
+\- Raw attribute is spin-up time.  It is printed as a 16-bit value
+and an optional "Average" 16-bit value if the word is nonzero.
+This is the default for Attribute 3.
+
+.I raw24/raw24
+\- Raw Attribute contains two 24\-bit values. The first is the
 number of load cycles.  The second is the number of unload cycles.
 The difference between these two values is the number of times that
 the drive was unexpectedly powered off (also called an emergency
@@ -1060,61 +1105,74 @@ unload). As a rule of thumb, the mechanical stress created by one
 emergency unload is equivalent to that created by one hundred normal
 unloads.
 
+The following old arguments to \'\-v\' are also still valid:
+
+.I 9,minutes
+\- same as:
+.I 9,min2hour,Power_On_Minutes.
+
+.I 9,seconds
+\- same as:
+.I 9,sec2hour,Power_On_Seconds.
+
+.I 9,halfminutes
+\- same as:
+.I 9,halfmin2hour,Power_On_Half_Minutes.
+
+.I 9,temp
+\- same as:
+.I 9,tempminmax,Temperature_Celsius.
+
+.I 192,emergencyretractcyclect
+\- same as:
+.I 192,raw48,Emerg_Retract_Cycle_Ct
+
+.I 193,loadunload
+\- same as:
+.I 193,raw24/raw24.
+
 .I 194,10xCelsius
-\- Raw Attribute number 194 is ten times the disk temperature in
-Celsius.  This is used by some Samsung disks (example: model SV1204H
-with RK100\-13 firmware).
+\- same as:
+.I 194,temp10x,Temperature_Celsius_x10.
 
 .I 194,unknown
-\- Raw Attribute number 194 is NOT the disk temperature, and its
-interpretation is unknown. This is primarily useful for the \-P
-(presets) option.
+\- same as:
+.I 194,raw48,Unknown_Attribute.
 
 .I 197,increasing
-\- Raw Attribute number 197 (Current Pending Sector Count) is not
-reset if uncorrectable sectors are reallocated.
+\- same as:
+.I 197,raw48,Total_Pending_Sectors.
+Also means that Attribute number 197 (Current Pending Sector Count)
+is not reset if uncorrectable sectors are reallocated
+(see \fBsmartd.conf\fP(5) man page).
 
 .I 198,increasing
-\- Raw Attribute number 198 (Offline Uncorrectable Sector Count) is not
-reset if uncorrectable sectors are reallocated.
+\- same as:
+.I 198,raw48,Total_Offl_Uncorrectabl.
+Also means that Attribute number 198 (Offline Uncorrectable Sector Count)
+is not reset if uncorrectable sectors are reallocated
+(see \fBsmartd.conf\fP(5) man page).
 
 .I 198,offlinescanuncsectorct
-\- Raw Attribute number 198 is the Offline Scan UNC Sector Count.
+\- same as:
+.I 198,raw48,Offline_Scan_UNC_SectCt.
 
 .I 200,writeerrorcount
-\- Raw Attribute number 200 is the Write Error Count.
+\- same as:
+.I 200,raw48,Write_Error_Count.
 
 .I 201,detectedtacount
-\- Raw Attribute number 201 is the Detected TA Count.
+\- same as:
+.I 201,raw48,Detected_TA_Count.
 
 .I 220,temp
-\- Raw Attribute number 220 is the disk temperature in Celsius.
+\- same as:
+.I 220,raw48,Temperature_Celsius.
 
 Note: a table of hard drive models, listing which Attribute
 corresponds to temperature, can be found at:
 \fBhttp://www.guzu.net/linux/hddtemp.db\fP
 
-.I N,raw8
-\- Print the Raw value of Attribute N as six 8\-bit unsigned base\-10
-integers.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw8\' prints Raw values for ALL Attributes in this
-form.  The form (for example) \'123,raw8\' only prints the Raw value for
-Attribute 123 in this form.
-
-.I N,raw16
-\- Print the Raw value of Attribute N as three 16\-bit unsigned base\-10
-integers.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw16\' prints Raw values for ALL Attributes in this
-form.  The form (for example) \'123,raw16\' only prints the Raw value for
-Attribute 123 in this form.
-
-.I N,raw48
-\- Print the Raw value of Attribute N as a 48\-bit unsigned base\-10
-integer.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw48\' prints Raw values for ALL Attributes in
-this form.  The form (for example) \'123,raw48\' only prints the Raw
-value for Attribute 123 in this form.
-
 .TP
 .B \-F TYPE, \-\-firmwarebug=TYPE
 [ATA only] Modifies the behavior of \fBsmartctl\fP to compensate for some
@@ -1770,7 +1828,7 @@ these documents may be found in the References section of the
 
 .SH
 SVN ID OF THIS PAGE:
-$Id: smartctl.8.in 2922 2009-09-22 16:27:33Z chrfranke $
+$Id: smartctl.8.in 2978 2009-10-30 23:20:39Z chrfranke $
 .\" Local Variables:            
 .\" mode: nroff         
 .\" End:
index 7da7a0b1c5adc2b4042571ad362a77901a78eac4..65b6d3b9bc31cf4f5565817a6c761a4fd3210793 100644 (file)
@@ -56,7 +56,7 @@
 #include "smartctl.h"
 #include "utility.h"
 
-const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
+const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 2975 2009-10-29 22:52:38Z chrfranke $"
                                   CONFIG_H_CVSID EXTERN_H_CVSID SMARTCTL_H_CVSID;
 
 // This is a block containing all the "control variables".  We declare
@@ -539,7 +539,7 @@ const char * parse_options(int argc, char** argv,
              create_vendor_attribute_arg_list().c_str());
         EXIT(0);
       }
-      if (parse_attribute_def(optarg, ataopts.attributedefs))
+      if (!parse_attribute_def(optarg, ataopts.attribute_defs, PRIOR_USER))
         badarg = true;
       break;    
     case 'P':
@@ -877,92 +877,83 @@ int main_worker(int argc, char **argv)
   if (!smi())
     return 1;
 
-  int retval = 0;
+  // define control block for external functions
+  smartmonctrl control;
+  con=&control;
 
-  smart_device * dev = 0;
-  try {
-    // define control block for external functions
-    smartmonctrl control;
-    con=&control;
-
-    // Parse input arguments
-    ata_print_options ataopts;
-    scsi_print_options scsiopts;
-    const char * type = parse_options(argc, argv, ataopts, scsiopts);
-
-    // '-d test' -> Report result of autodetection
-    bool print_type_only = (type && !strcmp(type, "test"));
-    if (print_type_only)
-      type = 0;
-
-    const char * name = argv[argc-1];
-
-    if (!strcmp(name,"-")) {
-      // Parse "smartctl -r ataioctl,2 ..." output from stdin
-      if (type || print_type_only) {
-        pout("Smartctl: -d option is not allowed in conjunction with device name \"-\".\n");
-        UsageSummary();
-        return FAILCMD;
-      }
-      dev = get_parsed_ata_device(smi(), name);
-    }
-    else
-      // get device of appropriate type
-      dev = smi()->get_smart_device(name, type);
+  // Parse input arguments
+  ata_print_options ataopts;
+  scsi_print_options scsiopts;
+  const char * type = parse_options(argc, argv, ataopts, scsiopts);
 
-    if (!dev) {
-      pout("%s: %s\n", name, smi()->get_errmsg());
-      if (type)
-        printvalidarglistmessage('d');
-      else
-        pout("Smartctl: please specify device type with the -d option.\n");
+  // '-d test' -> Report result of autodetection
+  bool print_type_only = (type && !strcmp(type, "test"));
+  if (print_type_only)
+    type = 0;
+
+  const char * name = argv[argc-1];
+
+  smart_device_auto_ptr dev;
+  if (!strcmp(name,"-")) {
+    // Parse "smartctl -r ataioctl,2 ..." output from stdin
+    if (type || print_type_only) {
+      pout("Smartctl: -d option is not allowed in conjunction with device name \"-\".\n");
       UsageSummary();
       return FAILCMD;
     }
+    dev = get_parsed_ata_device(smi(), name);
+  }
+  else
+    // get device of appropriate type
+    dev = smi()->get_smart_device(name, type);
+
+  if (!dev) {
+    pout("%s: %s\n", name, smi()->get_errmsg());
+    if (type)
+      printvalidarglistmessage('d');
+    else
+      pout("Smartctl: please specify device type with the -d option.\n");
+    UsageSummary();
+    return FAILCMD;
+  }
 
-    if (print_type_only)
-      // Report result of first autodetection
-      pout("%s: Device of type '%s' [%s] detected\n",
-           dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev));
-
-    // Open device
-    {
-      // Save old info
-      smart_device::device_info oldinfo = dev->get_info();
-
-      // Open with autodetect support, may return 'better' device
-      dev = dev->autodetect_open();
+  if (print_type_only)
+    // Report result of first autodetection
+    pout("%s: Device of type '%s' [%s] detected\n",
+         dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
 
-      // Report if type has changed
-      if ((type || print_type_only) && oldinfo.dev_type != dev->get_dev_type())
-        pout("%s: Device open changed type from '%s' to '%s'\n",
-          dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type());
-    }
-    if (!dev->is_open()) {
-      pout("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg());
-      delete dev;
-      return FAILDEV;
-    }
+  // Open device
+  {
+    // Save old info
+    smart_device::device_info oldinfo = dev->get_info();
 
-    // now call appropriate ATA or SCSI routine
-    if (print_type_only)
-      pout("%s: Device of type '%s' [%s] opened\n",
-           dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev));
-    else if (dev->is_ata())
-      retval = ataPrintMain(dev->to_ata(), ataopts);
-    else if (dev->is_scsi())
-      retval = scsiPrintMain(dev->to_scsi(), scsiopts);
-    else
-      // we should never fall into this branch!
-      pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name());
+    // Open with autodetect support, may return 'better' device
+    dev.replace( dev->autodetect_open() );
 
-    dev->close();
-    delete dev;
+    // Report if type has changed
+    if ((type || print_type_only) && oldinfo.dev_type != dev->get_dev_type())
+      pout("%s: Device open changed type from '%s' to '%s'\n",
+        dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type());
   }
-  catch (...) {
-    delete dev;
-    throw;
+  if (!dev->is_open()) {
+    pout("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg());
+    return FAILDEV;
   }
+
+  // now call appropriate ATA or SCSI routine
+  int retval = 0;
+  if (print_type_only)
+    pout("%s: Device of type '%s' [%s] opened\n",
+         dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
+  else if (dev->is_ata())
+    retval = ataPrintMain(dev->to_ata(), ataopts);
+  else if (dev->is_scsi())
+    retval = scsiPrintMain(dev->to_scsi(), scsiopts);
+  else
+    // we should never fall into this branch!
+    pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name());
+
+  dev->close();
   return retval;
 }
 
@@ -981,12 +972,12 @@ int main(int argc, char **argv)
   }
   catch (const std::bad_alloc & /*ex*/) {
     // Memory allocation failed (also thrown by std::operator new)
-    pout("Smartctl: Out of memory\n");
+    printf("Smartctl: Out of memory\n");
     status = FAILCMD;
   }
   catch (const std::exception & ex) {
     // Other fatal errors
-    pout("Smartctl: Exception: %s\n", ex.what());
+    printf("Smartctl: Exception: %s\n", ex.what());
     status = FAILCMD;
   }
   return status;
index 041e5925f0e7400abea768a31c6f4cfb06a11a2e..000abfac5d6bf10cb0c127636e994362ce216970 100644 (file)
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
  
-$Id: smartd.8.in 2921 2009-09-20 19:19:32Z samm2 $
+$Id: smartd.8.in 2977 2009-10-30 22:29:05Z chrfranke $
 
 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
@@ -157,7 +157,7 @@ The path must be absolute, except if debug mode is enabled.
 [NEW EXPERIMENTAL SMARTD FEATURE] Read the drive database from FILE.
 The new database replaces the built in database by default. If \'+\' is
 specified, then the new entries prepend the built in entries.
-Please see the \fBsmartctl\fP man page for further details.
+Please see the \fBsmartctl\fP(8) man page for further details.
 
 .TP
 .B \-c FILE, \-\-configfile=FILE
@@ -722,8 +722,8 @@ along with the \'\-d areca,N\' Directive (see below).  The individual
 SATA disks hosted by the Areca controller appear to \fBsmartd\fP as
 normal ATA devices.  Hence all the ATA directives can be used for
 these disks.  Areca firmware version 1.46 or later which supports
-smartmontools must be used; Please see the \fBsmartctl\fP man page for
-further details.
+smartmontools must be used; Please see the \fBsmartctl\fP(8) man page
+for further details.
 
 .TP
 .B \-d TYPE
@@ -795,14 +795,14 @@ you may use \fBany\fP of the 3ware SCSI logical devices /dev/sd? to
 address \fBany\fP of the physical disks (3ware ports), error and log
 messages will make the most sense if you always list the 3ware SCSI
 logical device corresponding to the particular physical disks.  Please
-see the \fBsmartctl\fP man page for further details.
+see the \fBsmartctl\fP(8) man page for further details.
 
 ATA disks behind 3ware controllers may alternatively be accessed via a
 character device interface /dev/twe0-15 (3ware 6000/7000/8000
 controllers) and /dev/twa0-15 (3ware 9000 series controllers).  Note
 that the 9000 series controllers may \fBonly\fP be accessed using the
 character device interface /dev/twa0-15 and not the SCSI device
-interface /dev/sd?.  Please see the \fBsmartctl\fP man page for
+interface /dev/sd?.  Please see the \fBsmartctl\fP(8) man page for
 further details.
 
 Note that older 3w-xxxx drivers do not pass the \'Enable Autosave\'
@@ -1605,105 +1605,23 @@ values for \'\-F\' (see the \'\-P\' option below).
 [Please see the \fBsmartctl \-F\fP command-line option.]
 
 .TP
-.B \-v N,OPTION
-Modifies the labeling for Attribute N, for disks which use
-non-standard Attribute definitions.  This is useful in connection with
-the Attribute tracking/reporting Directives.
-
-This Directive may appear multiple times. Valid arguments to this
-Directive are:
+.B \-v ID,FORMAT[,NAME]
+[ATA only] Sets a vendor\-specific raw value print FORMAT and
+optional NAME for Attribute ID.
+This directive may be used multiple times.
+Please see \fBsmartctl -v\fP command-line option for further details.
 
-.I 9,minutes
-\- Raw Attribute number 9 is power-on time in minutes.  Its raw value
-will be displayed in the form \'Xh+Ym\'.  Here X is hours, and Y is
-minutes in the range 0-59 inclusive.  Y is always printed with two
-digits, for example \'06\' or \'31\' or \'00\'.
-
-.I 9,seconds
-\- Raw Attribute number 9 is power-on time in seconds.  Its raw value
-will be displayed in the form \'Xh+Ym+Zs\'.  Here X is hours, Y is
-minutes in the range 0-59 inclusive, and Z is seconds in the range
-0-59 inclusive.  Y and Z are always printed with two digits, for
-example \'06\' or \'31\' or \'00\'.
-
-.I 9,halfminutes
-\- Raw Attribute number 9 is power-on time, measured in units of 30
-seconds.  This format is used by some Samsung disks.  Its raw value
-will be displayed in the form \'Xh+Ym\'.  Here X is hours, and Y is
-minutes in the range 0-59 inclusive.  Y is always printed with two
-digits, for example \'06\' or \'31\' or \'00\'.
-
-.I 9,temp
-\- Raw Attribute number 9 is the disk temperature in Celsius.
-
-.I 192,emergencyretractcyclect
-\- Raw Attribute number 192 is the Emergency Retract Cycle Count.
-
-.I 193,loadunload
-\- Raw Attribute number 193 contains two values. The first is the
-number of load cycles.  The second is the number of unload cycles.
-The difference between these two values is the number of times that
-the drive was unexpectedly powered off (also called an emergency
-unload). As a rule of thumb, the mechanical stress created by one
-emergency unload is equivalent to that created by one hundred normal
-unloads.
-
-.I 194,10xCelsius
-\- Raw Attribute number 194 is ten times the disk temperature in
-Celsius.  This is used by some Samsung disks (example: model SV1204H
-with RK100-13 firmware).
-
-.I 194,unknown
-\- Raw Attribute number 194 is NOT the disk temperature, and its
-interpretation is unknown. This is primarily useful for the -P
-(presets) Directive.
+The following arguments affect smartd warning output:
 
 .I 197,increasing
 \- Raw Attribute number 197 (Current Pending Sector Count) is not
-reset if uncorrectable sectors are reallocated.  This also sets
-\'-C 197+\' if no other \'-C\' directive is specified.
+reset if uncorrectable sectors are reallocated.  This sets \'-C 197+\'
+if no other \'-C\' directive is specified.
 
 .I 198,increasing
 \- Raw Attribute number 198 (Offline Uncorrectable Sector Count) is not
-reset if uncorrectable sector are reallocated.  This also sets
-\'-U 198+\' if no other \'-U\' directive is specified.
-
-.I 198,offlinescanuncsectorct
-\- Raw Attribute number 198 is the Offline Scan UNC Sector Count.
-
-.I 200,writeerrorcount
-\- Raw Attribute number 200 is the Write Error Count.
-
-.I 201,detectedtacount
-\- Raw Attribute number 201 is the Detected TA Count.
-
-.I 220,temp
-\- Raw Attribute number 220 is the disk temperature in Celsius.
-
-Note: a table of hard drive models, listing which Attribute
-corresponds to temperature, can be found at:
-\fBhttp://www.guzu.net/linux/hddtemp.db\fP
-
-.I N,raw8
-\- Print the Raw value of Attribute N as six 8-bit unsigned base-10
-integers.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw8\' prints Raw values for ALL Attributes in this
-form.  The form (for example) \'123,raw8\' only prints the Raw value for
-Attribute 123 in this form.
-
-.I N,raw16
-\- Print the Raw value of Attribute N as three 16-bit unsigned base-10
-integers.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw16\' prints Raw values for ALL Attributes in this
-form.  The form (for example) \'123,raw16\' only prints the Raw value for
-Attribute 123 in this form.
-
-.I N,raw48
-\- Print the Raw value of Attribute N as a 48-bit unsigned base-10
-integer.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw48\' prints Raw values for ALL Attributes in
-this form.  The form (for example) \'123,raw48\' only prints the Raw
-value for Attribute 123 in this form.
+reset if uncorrectable sector are reallocated.  This sets \'-U 198+\'
+if no other \'-U\' directive is specified.
 
 .TP
 .B \-P TYPE
@@ -2149,4 +2067,4 @@ smartmontools home page at \fBhttp://smartmontools.sourceforge.net/#references\f
 
 .SH
 SVN ID OF THIS PAGE:
-$Id: smartd.8.in 2921 2009-09-20 19:19:32Z samm2 $
+$Id: smartd.8.in 2977 2009-10-30 22:29:05Z chrfranke $
index 9b4ae478fd6cf75695db5d536038b7feac670ea7..1fdee49d02a52d9a7363089a6cafeb6496da4c9d 100644 (file)
@@ -1,7 +1,7 @@
 .ig
 Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
-$Id: smartd.conf.5.in 2921 2009-09-20 19:19:32Z samm2 $
+$Id: smartd.conf.5.in 2977 2009-10-30 22:29:05Z chrfranke $
 
 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
@@ -57,8 +57,7 @@ Under FreeBSD,
 \fBsmartd\fP
 will try to open all existing ATA devices (with entries in /dev)
 .B /dev/ad[0-9]+
-and all existing SCSI devices
-.B /dev/da[0-9]+.  
+and all existing SCSI devices (using CAM subsystem).  
 Under NetBSD/OpenBSD, 
 \fBsmartd\fP
 will try to open all existing ATA devices (with entries in /dev)
@@ -285,8 +284,8 @@ along with the \'\-d areca,N\' Directive (see below).  The individual
 SATA disks hosted by the Areca controller appear to \fBsmartd\fP as
 normal ATA devices.  Hence all the ATA directives can be used for
 these disks.  Areca firmware version 1.46 or later which supports
-smartmontools must be used; Please see the \fBsmartctl\fP man page for
-further details.
+smartmontools must be used; Please see the \fBsmartctl\fP(8) man page
+for further details.
 
 .TP
 .B \-d TYPE
@@ -358,14 +357,14 @@ you may use \fBany\fP of the 3ware SCSI logical devices /dev/sd? to
 address \fBany\fP of the physical disks (3ware ports), error and log
 messages will make the most sense if you always list the 3ware SCSI
 logical device corresponding to the particular physical disks.  Please
-see the \fBsmartctl\fP man page for further details.
+see the \fBsmartctl\fP(8) man page for further details.
 
 ATA disks behind 3ware controllers may alternatively be accessed via a
 character device interface /dev/twe0-15 (3ware 6000/7000/8000
 controllers) and /dev/twa0-15 (3ware 9000 series controllers).  Note
 that the 9000 series controllers may \fBonly\fP be accessed using the
 character device interface /dev/twa0-15 and not the SCSI device
-interface /dev/sd?.  Please see the \fBsmartctl\fP man page for
+interface /dev/sd?.  Please see the \fBsmartctl\fP(8) man page for
 further details.
 
 Note that older 3w-xxxx drivers do not pass the \'Enable Autosave\'
@@ -394,9 +393,7 @@ inclusive) denotes which disk on the controller is monitored.  In log
 files and email messages this disk will be identified as cciss_disk_XX
 with XX in the range from 00 to 15 inclusive.
 
-.B 3ware and cciss controllers are currently ONLY supported under Linux and FreeBSD.
-
-.B MegaRAID and Areca controllers are currently ONLY supported under Linux.
+.B 3ware, MegaRAID, Areca and cciss controllers are currently ONLY supported under Linux.
 
 .I hpt,L/M/N
 \- the device consists of one or more ATA disks connected to a HighPoint
@@ -1170,105 +1167,23 @@ values for \'\-F\' (see the \'\-P\' option below).
 [Please see the \fBsmartctl \-F\fP command-line option.]
 
 .TP
-.B \-v N,OPTION
-Modifies the labeling for Attribute N, for disks which use
-non-standard Attribute definitions.  This is useful in connection with
-the Attribute tracking/reporting Directives.
-
-This Directive may appear multiple times. Valid arguments to this
-Directive are:
+.B \-v ID,FORMAT[,NAME]
+[ATA only] Sets a vendor\-specific raw value print FORMAT and
+optional NAME for Attribute ID.
+This directive may be used multiple times.
+Please see \fBsmartctl -v\fP command-line option for further details.
 
-.I 9,minutes
-\- Raw Attribute number 9 is power-on time in minutes.  Its raw value
-will be displayed in the form \'Xh+Ym\'.  Here X is hours, and Y is
-minutes in the range 0-59 inclusive.  Y is always printed with two
-digits, for example \'06\' or \'31\' or \'00\'.
-
-.I 9,seconds
-\- Raw Attribute number 9 is power-on time in seconds.  Its raw value
-will be displayed in the form \'Xh+Ym+Zs\'.  Here X is hours, Y is
-minutes in the range 0-59 inclusive, and Z is seconds in the range
-0-59 inclusive.  Y and Z are always printed with two digits, for
-example \'06\' or \'31\' or \'00\'.
-
-.I 9,halfminutes
-\- Raw Attribute number 9 is power-on time, measured in units of 30
-seconds.  This format is used by some Samsung disks.  Its raw value
-will be displayed in the form \'Xh+Ym\'.  Here X is hours, and Y is
-minutes in the range 0-59 inclusive.  Y is always printed with two
-digits, for example \'06\' or \'31\' or \'00\'.
-
-.I 9,temp
-\- Raw Attribute number 9 is the disk temperature in Celsius.
-
-.I 192,emergencyretractcyclect
-\- Raw Attribute number 192 is the Emergency Retract Cycle Count.
-
-.I 193,loadunload
-\- Raw Attribute number 193 contains two values. The first is the
-number of load cycles.  The second is the number of unload cycles.
-The difference between these two values is the number of times that
-the drive was unexpectedly powered off (also called an emergency
-unload). As a rule of thumb, the mechanical stress created by one
-emergency unload is equivalent to that created by one hundred normal
-unloads.
-
-.I 194,10xCelsius
-\- Raw Attribute number 194 is ten times the disk temperature in
-Celsius.  This is used by some Samsung disks (example: model SV1204H
-with RK100-13 firmware).
-
-.I 194,unknown
-\- Raw Attribute number 194 is NOT the disk temperature, and its
-interpretation is unknown. This is primarily useful for the -P
-(presets) Directive.
+The following arguments affect smartd warning output:
 
 .I 197,increasing
 \- Raw Attribute number 197 (Current Pending Sector Count) is not
-reset if uncorrectable sectors are reallocated.  This also sets
-\'-C 197+\' if no other \'-C\' directive is specified.
+reset if uncorrectable sectors are reallocated.  This sets \'-C 197+\'
+if no other \'-C\' directive is specified.
 
 .I 198,increasing
 \- Raw Attribute number 198 (Offline Uncorrectable Sector Count) is not
-reset if uncorrectable sector are reallocated.  This also sets
-\'-U 198+\' if no other \'-U\' directive is specified.
-
-.I 198,offlinescanuncsectorct
-\- Raw Attribute number 198 is the Offline Scan UNC Sector Count.
-
-.I 200,writeerrorcount
-\- Raw Attribute number 200 is the Write Error Count.
-
-.I 201,detectedtacount
-\- Raw Attribute number 201 is the Detected TA Count.
-
-.I 220,temp
-\- Raw Attribute number 220 is the disk temperature in Celsius.
-
-Note: a table of hard drive models, listing which Attribute
-corresponds to temperature, can be found at:
-\fBhttp://www.guzu.net/linux/hddtemp.db\fP
-
-.I N,raw8
-\- Print the Raw value of Attribute N as six 8-bit unsigned base-10
-integers.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw8\' prints Raw values for ALL Attributes in this
-form.  The form (for example) \'123,raw8\' only prints the Raw value for
-Attribute 123 in this form.
-
-.I N,raw16
-\- Print the Raw value of Attribute N as three 16-bit unsigned base-10
-integers.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw16\' prints Raw values for ALL Attributes in this
-form.  The form (for example) \'123,raw16\' only prints the Raw value for
-Attribute 123 in this form.
-
-.I N,raw48
-\- Print the Raw value of Attribute N as a 48-bit unsigned base-10
-integer.  This may be useful for decoding the meaning of the Raw
-value.  The form \'N,raw48\' prints Raw values for ALL Attributes in
-this form.  The form (for example) \'123,raw48\' only prints the Raw
-value for Attribute 123 in this form.
+reset if uncorrectable sector are reallocated.  This sets \'-U 198+\'
+if no other \'-U\' directive is specified.
 
 .TP
 .B \-P TYPE
@@ -1484,4 +1399,4 @@ SEE ALSO:
 
 .SH
 SVN ID OF THIS PAGE:
-$Id: smartd.conf.5.in 2921 2009-09-20 19:19:32Z samm2 $
+$Id: smartd.conf.5.in 2977 2009-10-30 22:29:05Z chrfranke $
index efaa226d31c17d942daa79c02f31e3da1d10bcf7..43164a6c78fe573c4b9ebd4388cd231a7f628d6a 100644 (file)
@@ -122,7 +122,7 @@ extern "C" int getdomainname(char *, int); // no declaration in header files!
 
 #define ARGUSED(x) ((void)(x))
 
-const char * smartd_cpp_cvsid = "$Id: smartd.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
+const char * smartd_cpp_cvsid = "$Id: smartd.cpp 2984 2009-11-14 22:46:31Z chrfranke $"
                                 CONFIG_H_CVSID EXTERN_H_CVSID;
 
 extern const char *reportbug;
@@ -283,8 +283,7 @@ struct dev_config
 
   attribute_flags monitor_attr_flags;     // MONITOR_* flags for each attribute
 
-  // TODO: Encapsulate, add get/set functions
-  unsigned char attributedefs[256];       // -v options, see end of extern.h for def
+  ata_vendor_attr_defs attribute_defs;    // -v options
 
   dev_config();
 };
@@ -315,7 +314,6 @@ dev_config::dev_config()
   curr_pending_incr(false), offl_pending_incr(false),
   curr_pending_set(false),  offl_pending_set(false)
 {
-  memset(attributedefs, 0, sizeof(attributedefs));
 }
 
 
@@ -353,9 +351,10 @@ struct persistent_dev_state
   struct ata_attribute {
     unsigned char id;
     unsigned char val;
+    unsigned char worst; // Byte needed for 'raw64' attribute only.
     uint64_t raw;
 
-    ata_attribute() : id(0), val(0), raw(0) { }
+    ata_attribute() : id(0), val(0), worst(0), raw(0) { }
   };
   ata_attribute ata_attributes[NUMBER_ATA_SMART_ATTRIBUTES];
 
@@ -447,10 +446,11 @@ void dev_state::update_persistent_state()
     ata_attribute & pa = ata_attributes[i];
     pa.id = ta.id;
     if (ta.id == 0) {
-      pa.val = 0; pa.raw = 0;
+      pa.val = pa.worst = 0; pa.raw = 0;
       continue;
     }
     pa.val = ta.current;
+    pa.worst = ta.worst;
     pa.raw =            ta.raw[0]
            | (          ta.raw[1] <<  8)
            | (          ta.raw[2] << 16)
@@ -468,10 +468,12 @@ void dev_state::update_temp_state()
     ata_smart_attribute & ta = smartval.vendor_attributes[i];
     ta.id = pa.id;
     if (pa.id == 0) {
-      ta.current = 0; memset(ta.raw, 0, sizeof(ta.raw));
+      ta.current = ta.worst = 0;
+      memset(ta.raw, 0, sizeof(ta.raw));
       continue;
     }
     ta.current = pa.val;
+    ta.worst = pa.worst;
     ta.raw[0] = (unsigned char) pa.raw;
     ta.raw[1] = (unsigned char)(pa.raw >>  8);
     ta.raw[2] = (unsigned char)(pa.raw >> 16);
@@ -496,22 +498,23 @@ static bool parse_dev_state_line(const char * line, persistent_dev_state & state
        "((count)" // (10 (11)
        "|(first-sent-time)" // (12)
        "|(last-sent-time)" // (13)
-       ")" // 14)
+       ")" // 10)
       ")" // 8)
      "|(ata-smart-attribute\\.([0-9]+)\\." // (14 (15)
-       "((id)" // (16)
-       "|(val)" // (17)
-       "|(raw)" // (18)
-       ")" // 19)
+       "((id)" // (16 (17)
+       "|(val)" // (18)
+       "|(worst)" // (19)
+       "|(raw)" // (20)
+       ")" // 16)
       ")" // 14)
      ")" // 1)
-     " *= *([0-9]+)[ \n]*$", // (20)
+     " *= *([0-9]+)[ \n]*$", // (21)
     REG_EXTENDED
   );
   if (regex.empty())
     throw std::logic_error("parse_dev_state_line: invalid regex");
 
-  const int nmatch = 1+20;
+  const int nmatch = 1+21;
   regmatch_t match[nmatch];
   if (!regex.execute(line, nmatch, match))
     return false;
@@ -556,6 +559,8 @@ static bool parse_dev_state_line(const char * line, persistent_dev_state & state
       state.ata_attributes[i].id = (unsigned char)val;
     else if (match[++m].rm_so >= 0)
       state.ata_attributes[i].val = (unsigned char)val;
+    else if (match[++m].rm_so >= 0)
+      state.ata_attributes[i].worst = (unsigned char)val;
     else if (match[++m].rm_so >= 0)
       state.ata_attributes[i].raw = val;
     else
@@ -655,6 +660,7 @@ static bool write_dev_state(const char * path, const persistent_dev_state & stat
       continue;
     write_dev_state_line(f, "ata-smart-attribute", i, "id", pa.id);
     write_dev_state_line(f, "ata-smart-attribute", i, "val", pa.val);
+    write_dev_state_line(f, "ata-smart-attribute", i, "worst", pa.worst);
     write_dev_state_line(f, "ata-smart-attribute", i, "raw", pa.raw);
   }
 
@@ -1420,16 +1426,18 @@ void Directives() {
    arguments to the option opt or NULL on failure. */
 const char *GetValidArgList(char opt) {
   switch (opt) {
+  case 'A':
+  case 's':
+    return "<PATH_PREFIX>";
   case 'c':
     return "<FILE_NAME>, -";
-  case 's':
-    return "valid_regular_expression";
   case 'l':
     return "daemon, local0, local1, local2, local3, local4, local5, local6, local7";
   case 'q':
     return "nodev, errors, nodevstartup, never, onecheck, showtests";
   case 'r':
     return "ioctl[,N], ataioctl[,N], scsiioctl[,N]";
+  case 'B':
   case 'p':
     return "<FILE_NAME>";
   case 'i':
@@ -1442,6 +1450,18 @@ const char *GetValidArgList(char opt) {
 /* prints help information for command syntax */
 void Usage (void){
   PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");
+  PrintOut(LOG_INFO,"  -A PREFIX, --attributelog=PREFIX\n");
+  PrintOut(LOG_INFO,"        Log ATA attribute information to {PREFIX}MODEL-SERIAL.ata.csv\n");
+#ifdef SMARTMONTOOLS_ATTRIBUTELOG
+  PrintOut(LOG_INFO,"        [default is "SMARTMONTOOLS_ATTRIBUTELOG"MODEL-SERIAL.ata.csv]\n");
+#endif
+  PrintOut(LOG_INFO,"\n");
+  PrintOut(LOG_INFO,"  -B [+]FILE, --drivedb=[+]FILE\n");
+  PrintOut(LOG_INFO,"        Read and replace [add] drive database from FILE\n");
+#ifdef SMARTMONTOOLS_DRIVEDBDIR
+  PrintOut(LOG_INFO,"        [default is "SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h]\n");
+#endif
+  PrintOut(LOG_INFO,"\n");
   PrintOut(LOG_INFO,"  -c NAME|-, --configfile=NAME|-\n");
   PrintOut(LOG_INFO,"        Read configuration file NAME or stdin [default is %s]\n\n", configfile);
   PrintOut(LOG_INFO,"  -d, --debug\n");
@@ -1472,12 +1492,6 @@ void Usage (void){
   PrintOut(LOG_INFO,"        Save disk states to {PREFIX}MODEL-SERIAL.TYPE.state\n");
 #ifdef SMARTMONTOOLS_SAVESTATES
   PrintOut(LOG_INFO,"        [default is "SMARTMONTOOLS_SAVESTATES"MODEL-SERIAL.TYPE.state]\n");
-#endif
-  PrintOut(LOG_INFO,"\n");
-  PrintOut(LOG_INFO,"  -B [+]FILE, --drivedb=[+]FILE\n");
-  PrintOut(LOG_INFO,"        Read and replace [add] drive database from FILE\n");
-#ifdef SMARTMONTOOLS_DRIVEDBDIR
-  PrintOut(LOG_INFO,"        [default is "SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h]\n");
 #endif
   PrintOut(LOG_INFO,"\n");
 #ifdef _WIN32
@@ -1605,7 +1619,7 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
     PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name);
   else {
     // do whatever applypresets decides to do.
-    if (!apply_presets(&drive, cfg.attributedefs, cfg.fix_firmwarebug, fix_swapped_id))
+    if (!apply_presets(&drive, cfg.attribute_defs, cfg.fix_firmwarebug, fix_swapped_id))
       PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name);
     else
       PrintOut(LOG_INFO, "Device: %s, found in smartd database.\n", name);
@@ -1613,10 +1627,10 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
 
   // Set default '-C 197[+]' if no '-C ID' is specified.
   if (!cfg.curr_pending_set)
-    cfg.curr_pending_id = get_unc_attr_id(false, cfg.attributedefs, cfg.curr_pending_incr);
+    cfg.curr_pending_id = get_unc_attr_id(false, cfg.attribute_defs, cfg.curr_pending_incr);
   // Set default '-U 198[+]' if no '-U ID' is specified.
   if (!cfg.offl_pending_set)
-    cfg.offl_pending_id = get_unc_attr_id(true, cfg.attributedefs, cfg.offl_pending_incr);
+    cfg.offl_pending_id = get_unc_attr_id(true, cfg.attribute_defs, cfg.offl_pending_incr);
 
   // If requested, show which presets would be used for this drive
   if (cfg.showpresets) {
@@ -1704,20 +1718,20 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
 
     // see if the necessary Attribute is there to monitor offline or
     // current pending sectors or temperature
-    if (cfg.curr_pending_id && ATAReturnAttributeRawValue(cfg.curr_pending_id, &state.smartval) < 0) {
+    if (cfg.curr_pending_id && ata_find_attr_index(cfg.curr_pending_id, state.smartval) < 0) {
       PrintOut(LOG_INFO,"Device: %s, can't monitor Current Pending Sector count - no Attribute %d\n",
                name, cfg.curr_pending_id);
       cfg.curr_pending_id = 0;
     }
     
-    if (cfg.offl_pending_id && ATAReturnAttributeRawValue(cfg.offl_pending_id, &state.smartval) < 0) {
+    if (cfg.offl_pending_id && ata_find_attr_index(cfg.offl_pending_id, state.smartval) < 0) {
       PrintOut(LOG_INFO,"Device: %s, can't monitor Offline Uncorrectable Sector count - no Attribute %d\n",
                name, cfg.offl_pending_id);
       cfg.offl_pending_id = 0;
     }
 
     if (   (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
-        && !ATAReturnTemperatureValue(&state.smartval, cfg.attributedefs)) {
+        && !ata_return_temperature_value(&state.smartval, cfg.attribute_defs)) {
       PrintOut(LOG_CRIT, "Device: %s, can't monitor Temperature, ignoring -W Directive\n", name);
       cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
     }
@@ -1991,75 +2005,6 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
   return 0;
 }
 
-
-struct changedattribute_t {
-  unsigned char newval;
-  unsigned char oldval;
-  unsigned char id;
-  unsigned char prefail;
-  unsigned char sameraw;
-};
-
-// We compare old and new values of the n'th attribute.  Note that n
-// is NOT the attribute ID number.. If (Normalized & Raw) equal,
-// then return 0, else nonzero.
-static int ATACompareValues(changedattribute_t *delta,
-                            struct ata_smart_values *newv,
-                            struct ata_smart_values *oldv,
-                            struct ata_smart_thresholds_pvt *thresholds,
-                            int n, const char * name)
-{
-  struct ata_smart_attribute *now,*was;
-  struct ata_smart_threshold_entry *thre;
-  unsigned char oldval,newval;
-  int sameraw;
-
-  // check that attribute number in range, and no null pointers
-  if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !newv || !oldv || !thresholds)
-    return 0;
-  
-  // pointers to disk's values and vendor's thresholds
-  now=newv->vendor_attributes+n;
-  was=oldv->vendor_attributes+n;
-  thre=thresholds->thres_entries+n;
-
-  // consider only valid attributes
-  if (!now->id || !was->id || !thre->id)
-    return 0;
-  
-  
-  // issue warning if they don't have the same ID in all structures:
-  if ( (now->id != was->id) || (now->id != thre->id) ){
-    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n",
-             name, (int)now->id, (int)was->id, (int)thre->id);
-    return 0;
-  }
-
-  // new and old values of Normalized Attributes
-  newval=now->current;
-  oldval=was->current;
-
-  // See if the RAW values are unchanged (ie, the same)
-  if (memcmp(now->raw, was->raw, 6))
-    sameraw=0;
-  else
-    sameraw=1;
-  
-  // if any values out of the allowed range, or if the values haven't
-  // changed, return 0
-  if (!newval || !oldval || newval>0xfe || oldval>0xfe || (oldval==newval && sameraw))
-    return 0;
-  
-  // values have changed.  Construct output and return
-  delta->newval=newval;
-  delta->oldval=oldval;
-  delta->id=now->id;
-  delta->prefail=ATTRIBUTE_FLAGS_PREFAILURE(now->flags);
-  delta->sameraw=sameraw;
-
-  return 1;
-}
-
 // If the self-test log has got more self-test errors (or more recent
 // self-test errors) recorded, then notify user.
 static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi)
@@ -2428,13 +2373,18 @@ static void check_pending(const dev_config & cfg, dev_state & state,
                           const ata_smart_values & smartval,
                           int mailtype, const char * msg)
 {
+  // Find attribute index
+  int i = ata_find_attr_index(id, smartval);
+  if (!(i >= 0 && ata_find_attr_index(id, state.smartval) == i))
+    return;
+
   // No report if no sectors pending.
-  int64_t rawval = ATAReturnAttributeRawValue(id, &smartval);
-  if (rawval <= 0)
+  uint64_t rawval = ata_get_attr_raw_value(smartval.vendor_attributes[i], cfg.attribute_defs);
+  if (rawval == 0)
     return;
 
   // If attribute is not reset, report only sector count increases.
-  int64_t prev_rawval = ATAReturnAttributeRawValue(id, &state.smartval);
+  uint64_t prev_rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs);
   if (!(!increase_only || prev_rawval < rawval))
     return;
 
@@ -2527,6 +2477,103 @@ static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned
   }
 }
 
+// Check normalized and raw attribute values.
+static void check_attribute(const dev_config & cfg, dev_state & state,
+                            const ata_smart_attribute & attr,
+                            const ata_smart_attribute & prev,
+                            const ata_smart_threshold_entry & thre)
+{
+  // Check attribute and threshold
+  ata_attr_state attrstate = ata_get_attr_state(attr, thre, cfg.attribute_defs);
+  if (attrstate == ATTRSTATE_NON_EXISTING)
+    return;
+
+  // If requested, check for usage attributes that have failed.
+  if (   cfg.usagefailed && attrstate == ATTRSTATE_FAILED_NOW
+      && !cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGN_FAILUSE)) {
+    std::string attrname = ata_get_smart_attr_name(attr.id, cfg.attribute_defs);
+    PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", cfg.name.c_str(), attr.id, attrname.c_str());
+    MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", cfg.name.c_str(), attr.id, attrname.c_str());
+    state.must_write = true;
+  }
+
+  // Return if we're not tracking this type of attribute
+  bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(attr.flags);
+  if (!(   ( prefail && cfg.prefail)
+        || (!prefail && cfg.usage  )))
+    return;
+
+  // Return if '-I ID' was specified
+  if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGNORE))
+    return;
+
+  // Issue warning if they don't have the same ID in all structures.
+  if (attr.id != prev.id || attrstate == ATTRSTATE_BAD_THRESHOLD) {
+    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n",
+             cfg.name.c_str(), attr.id, prev.id, thre.id);
+    return;
+  }
+
+  // Compare normalized values if valid.
+  bool valchanged = false;
+  if (attrstate > ATTRSTATE_NO_NORMVAL) {
+    if (attr.current != prev.current)
+      valchanged = true;
+  }
+
+  // Compare raw values if requested.
+  bool rawchanged = false;
+  if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW)) {
+    if (   ata_get_attr_raw_value(attr, cfg.attribute_defs)
+        != ata_get_attr_raw_value(prev, cfg.attribute_defs))
+      rawchanged = true;
+  }
+
+  // Return if no change
+  if (!(valchanged || rawchanged))
+    return;
+
+  // Format value strings
+  std::string currstr, prevstr;
+  if (attrstate == ATTRSTATE_NO_NORMVAL) {
+    // Print raw values only
+    currstr = strprintf("%s (Raw)",
+      ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
+    prevstr = strprintf("%s (Raw)",
+      ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
+  }
+  else if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_PRINT)) {
+    // Print normalized and raw values
+    currstr = strprintf("%d [Raw %s]", attr.current,
+      ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
+    prevstr = strprintf("%d [Raw %s]", prev.current,
+      ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
+  }
+  else {
+    // Print normalized values only
+    currstr = strprintf("%d", attr.current);
+    prevstr = strprintf("%d", prev.current);
+  }
+
+  // Format message
+  std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %s to %s",
+                              cfg.name.c_str(), (prefail ? "Prefailure" : "Usage"), attr.id,
+                              ata_get_smart_attr_name(attr.id, cfg.attribute_defs).c_str(),
+                              prevstr.c_str(), currstr.c_str());
+
+  // Report this change as critical ?
+  if (   (valchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_AS_CRIT))
+      || (rawchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_AS_CRIT))) {
+    PrintOut(LOG_CRIT, "%s\n", msg.c_str());
+    MailWarning(cfg, state, 2, "%s", msg.c_str());
+  }
+  else {
+    PrintOut(LOG_INFO, "%s\n", msg.c_str());
+  }
+  state.must_write = true;
+}
+
+
 static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev, bool allow_selftests)
 {
   const char * name = cfg.name.c_str();
@@ -2637,10 +2684,9 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
   if (   cfg.usagefailed || cfg.prefail || cfg.usage
       || cfg.curr_pending_id || cfg.offl_pending_id
       || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit || cfg.selftest) {
-    struct ata_smart_values     curval;
-    struct ata_smart_thresholds_pvt * thresh = &state.smartthres;
 
-    // Read current attribute values. *drive contains old values and thresholds
+    // Read current attribute values.
+    ata_smart_values curval;
     if (ataReadSmartValues(atadev, &curval)){
       PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
       MailWarning(cfg, state, 6, "Device: %s, failed to read SMART Attribute Data", name);
@@ -2660,96 +2706,20 @@ static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device
 
       // check temperature limits
       if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
-        CheckTemperature(cfg, state, ATAReturnTemperatureValue(&curval, cfg.attributedefs), 0);
+        CheckTemperature(cfg, state, ata_return_temperature_value(&curval, cfg.attribute_defs), 0);
 
       if (cfg.usagefailed || cfg.prefail || cfg.usage) {
 
-       // look for failed usage attributes, or track usage or prefail attributes
+        // look for failed usage attributes, or track usage or prefail attributes
         for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
+          check_attribute(cfg, state,
+                          curval.vendor_attributes[i],
+                          state.smartval.vendor_attributes[i],
+                          state.smartthres.thres_entries[i]);
+        }
 
-         // This block looks for usage attributes that have failed.
-         // Prefail attributes that have failed are returned with a
-         // positive sign. No failure returns 0. Usage attributes<0.
-          int att;
-         if (cfg.usagefailed && ((att=ataCheckAttribute(&curval, thresh, i))<0)){
-           
-           // are we ignoring failures of this attribute?
-           att *= -1;
-            if (!cfg.monitor_attr_flags.is_set(att, MONITOR_IGN_FAILUSE)) {
-             char attname[64], *loc=attname;
-             
-             // get attribute name & skip white space
-             ataPrintSmartAttribName(loc, att, cfg.attributedefs);
-             while (*loc && *loc==' ') loc++;
-             
-             // warning message
-             PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
-             MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %s.", name, loc);
-              state.must_write = true;
-           }
-         }
-         
-         // This block tracks usage or prefailure attributes to see if
-         // they are changing.  It also looks for changes in RAW values
-         // if this has been requested by user.
-          changedattribute_t delta;
-         if ((cfg.usage || cfg.prefail) && ATACompareValues(&delta, &curval, &state.smartval, thresh, i, name)){
-
-            // Continue if we're not tracking this type of attribute
-            if (!(   ( delta.prefail && cfg.prefail)
-                  || (!delta.prefail && cfg.usage   )))
-              continue;
-
-            // Continue if '-I ID' was specified
-            unsigned char id = delta.id;
-            if (cfg.monitor_attr_flags.is_set(id, MONITOR_IGNORE))
-              continue;
-
-           // if the only change is the raw value, and we're not
-           // tracking raw value, then continue loop over attributes
-            if (   !delta.sameraw && delta.newval == delta.oldval
-                && !cfg.monitor_attr_flags.is_set(id, MONITOR_RAW))
-             continue;
-
-            // get attribute name, skip spaces
-            char attname[64], *loc = attname;
-            ataPrintSmartAttribName(loc, id, cfg.attributedefs);
-            while (*loc && *loc==' ')
-              loc++;
-
-            // has the user asked for us to print raw values?
-            char newrawstring[64], oldrawstring[64];
-            if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) {
-              // get raw values (as a string) and add to printout
-              char rawstring[64];
-              ataPrintSmartAttribRawValue(rawstring, curval.vendor_attributes+i, cfg.attributedefs);
-              sprintf(newrawstring, " [Raw %s]", rawstring);
-              ataPrintSmartAttribRawValue(rawstring, state.smartval.vendor_attributes+i, cfg.attributedefs);
-              sprintf(oldrawstring, " [Raw %s]", rawstring);
-            }
-            else
-              newrawstring[0]=oldrawstring[0]='\0';
-
-            // Format message
-            std::string msg = strprintf("Device: %s, SMART %s Attribute: %s changed from %d%s to %d%s",
-                                        name, (delta.prefail ? "Prefailure" : "Usage"), loc,
-                                        delta.oldval, oldrawstring, delta.newval, newrawstring);
-
-            // Report this change as critical ?
-            if (   (delta.newval != delta.oldval && cfg.monitor_attr_flags.is_set(id, MONITOR_AS_CRIT))
-                || (!delta.sameraw               && cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_AS_CRIT))) {
-              PrintOut(LOG_CRIT, "%s\n", msg.c_str());
-              MailWarning(cfg, state, 2, "%s", msg.c_str());
-            }
-            else {
-              PrintOut(LOG_INFO, "%s\n", msg.c_str());
-            }
-            state.must_write = true;
-         } // endof block tracking usage or prefailure
-       } // end of loop over attributes
-       
         if (cfg.selftest) {
-          // Log changes of self-test executions status
+          // Log changes of self-test execution status
           if (   curval.self_test_exec_status != state.smartval.self_test_exec_status
               || (!allow_selftests && curval.self_test_exec_status != 0x00)          )
             log_self_test_exec_status(name, curval.self_test_exec_status);
@@ -3400,7 +3370,7 @@ static int ParseToken(char * token, dev_config & cfg)
     // non-default vendor-specific attribute meaning
     if (!(arg=strtok(NULL,delim))) {
       missingarg = 1;
-    } else if (parse_attribute_def(arg, cfg.attributedefs)) {
+    } else if (!parse_attribute_def(arg, cfg.attribute_defs, PRIOR_USER)) {
       badarg = 1;
     }
     break;
@@ -4130,8 +4100,7 @@ static void RegisterDevices(const dev_config_vector & conf_entries, smart_device
     dev_config cfg = conf_entries[i];
 
     // get device of appropriate type
-    // TODO: exception handling
-    smart_device * dev = 0;
+    smart_device_auto_ptr dev;
     bool scanning = false;
 
     // Device may already be detected during devicescan
@@ -4156,10 +4125,10 @@ static void RegisterDevices(const dev_config_vector & conf_entries, smart_device
     smart_device::device_info oldinfo = dev->get_info();
 
     // Open with autodetect support, may return 'better' device
-    dev = dev->autodetect_open();
+    dev.replace( dev->autodetect_open() );
 
     // Report if type has changed
-    if (/* ent->dev_type && */ oldinfo.dev_type != dev->get_dev_type())
+    if (oldinfo.dev_type != dev->get_dev_type())
       PrintOut(LOG_INFO,"Device: %s, type changed from '%s' to '%s'\n",
         cfg.name.c_str(), oldinfo.dev_type.c_str(), dev->get_dev_type());
 
@@ -4169,7 +4138,6 @@ static void RegisterDevices(const dev_config_vector & conf_entries, smart_device
       // If no debug and scanning - don't print errors
       if (debugmode || !scanning)
         PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", dev->get_info_name(), dev->get_errmsg());
-      delete dev;
       continue;
     }
 
@@ -4184,33 +4152,30 @@ static void RegisterDevices(const dev_config_vector & conf_entries, smart_device
     if (dev->is_ata()){
       if (ATADeviceScan(cfg, state, dev->to_ata())) {
         CanNotRegister(cfg.name.c_str(), "ATA", cfg.lineno, scanning);
-        delete dev; dev = 0;
-      }
-      else {
-        // move onto the list of ata devices
-        configs.push_back(cfg);
-        states.push_back(state);
-        devices.push_back(dev);
+        dev.reset();
       }
     }
-    
     // or register SCSI devices
     else if (dev->is_scsi()){
       if (SCSIDeviceScan(cfg, state, dev->to_scsi())) {
         CanNotRegister(cfg.name.c_str(), "SCSI", cfg.lineno, scanning);
-        delete dev; dev = 0;
-      }
-      else {
-        // move onto the list of scsi devices
-        configs.push_back(cfg);
-        states.push_back(state);
-        devices.push_back(dev);
+        dev.reset();
       }
     }
-    
+    else {
+      PrintOut(LOG_INFO, "Device: %s, neither ATA nor SCSI device\n", cfg.name.c_str());
+      dev.reset();
+    }
+
+    if (dev) {
+      // move onto the list of devices
+      configs.push_back(cfg);
+      states.push_back(state);
+      devices.push_back(dev);
+    }
     // if device is explictly listed and we can't register it, then
     // exit unless the user has specified that the device is removable
-    if (!dev && !scanning) {
+    else if (!scanning) {
       if (cfg.removable || quit==2)
         PrintOut(LOG_INFO, "Device %s not available\n", cfg.name.c_str());
       else {
index 511adc5f105dfed67a6d730331aa168f17741461..806732009dabaef5204a96692f4d05ef856293bc 100644 (file)
@@ -50,7 +50,7 @@
 #include "atacmds.h"
 #include "dev_interface.h"
 
-const char * utility_cpp_cvsid = "$Id: utility.cpp 2915 2009-09-18 21:17:37Z chrfranke $"
+const char * utility_cpp_cvsid = "$Id: utility.cpp 2991 2009-12-03 19:53:21Z chrfranke $"
                                  UTILITY_H_CVSID INT64_H_CVSID;
 
 const char * packet_types[] = {
@@ -102,21 +102,23 @@ std::string format_version_info(const char * prog_name, bool full /*= false*/)
     "software, and you are welcome to redistribute it under\n"
     "the terms of the GNU General Public License Version 2.\n"
     "See http://www.gnu.org for further details.\n"
-    "\n"
+    "\n",
+    prog_name
+  );
+  info += strprintf(
     "smartmontools release "PACKAGE_VERSION
       " dated "SMARTMONTOOLS_RELEASE_DATE" at "SMARTMONTOOLS_RELEASE_TIME"\n"
     "smartmontools SVN rev "SMARTMONTOOLS_SVN_REV
       " dated "SMARTMONTOOLS_SVN_DATE" at "SMARTMONTOOLS_SVN_TIME"\n"
     "smartmontools build host: "SMARTMONTOOLS_BUILD_HOST"\n"
     "smartmontools build configured: "SMARTMONTOOLS_CONFIGURE_DATE "\n"
-    "%s compile dated "__DATE__" at "__TIME__"\n",
-    prog_name, prog_name
-  );
-  info += strprintf(
-    "smartmontools configure arguments: %s\n",
-      (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
-       SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]")
+    "%s compile dated "__DATE__" at "__TIME__"\n"
+    "smartmontools configure arguments: ",
+    prog_name
   );
+  info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ?
+           SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]");
+  info += '\n';
 
   return info;
 }