From 29f23b20ad4e9bdaf83bea5418e3f667b7ba5e79 Mon Sep 17 00:00:00 2001
From: ballen4705 <ballen4705@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Thu, 7 Nov 2002 11:00:56 +0000
Subject: [PATCH] release 31

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@220 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG          | 17 +++++++-
 sm5/TODO               |  6 ++-
 sm5/atacmds.c          | 20 +++------
 sm5/atacmds.cpp        | 20 +++------
 sm5/atacmds.h          | 10 ++++-
 sm5/ataprint.c         | 95 ++++++++++++++++++++++++++++++++----------
 sm5/ataprint.cpp       | 95 ++++++++++++++++++++++++++++++++----------
 sm5/extern.h           |  5 ++-
 sm5/smartctl.8         | 57 ++++++++++++++++++++-----
 sm5/smartctl.c         | 56 ++++++++++++++++---------
 sm5/smartctl.cpp       | 56 ++++++++++++++++---------
 sm5/smartctl.h         | 13 +++++-
 sm5/smartd.c           |  4 +-
 sm5/smartd.cpp         |  4 +-
 sm5/smartmontools.spec | 43 ++++++++++++-------
 15 files changed, 352 insertions(+), 149 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 86d5ea1c4..72e7c8b29 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.36 2002/11/04 13:32:08 ballen4705 Exp $
+$Id: CHANGELOG,v 1.37 2002/11/07 11:00:55 ballen4705 Exp $
 
 Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
@@ -25,6 +25,21 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 CURRENT RELEASE (see VERSION file in this directory):
 
+smartmontools-5.0.31
+
+  smartctl: added new options -W, -U, and -P to control if and how the
+  smartctl exits if an error is detected in either a SMART data
+  structure checksum, or a SMART command returns an error.
+
+  modified manual page to break options into slightly more logical
+  categories.
+
+  reformatted 'usage' message order to agree with man page ordering
+
+  modified .spec file so that locale information now contains
+  character set definition.   Changed pt_BR to pt since we do not use any
+  aspect other than language.  See man setlocale.
+
 smartmontools-5.0.30
   smartctl: added new options -n and -N to force device to be ATA or SCSI
   smartctl: no longer dies silently if device path does not start/dev/X
diff --git a/sm5/TODO b/sm5/TODO
index 23c17e8ae..0ad17549a 100644
--- a/sm5/TODO
+++ b/sm5/TODO
@@ -4,7 +4,7 @@ Home page of code is: http://smartmontools.sourceforge.net
 
 Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
-$Id: TODO,v 1.19 2002/10/30 10:18:37 ballen4705 Exp $
+$Id: TODO,v 1.20 2002/11/07 11:00:55 ballen4705 Exp $
 
 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free
@@ -62,6 +62,10 @@ Add following config file directives:
   -f                    enable autosave of attributes
   -o                    enable automatic offline testing
 
+Use daemon (8) function instead of do-it-yourself daemon_init().  But,
+does it close all open file descriptors?  Must read glibc code to see:
+documentation unclear.
+
 
 General Fixes
 -------------
diff --git a/sm5/atacmds.c b/sm5/atacmds.c
index f1a3bf671..35cfbf364 100644
--- a/sm5/atacmds.c
+++ b/sm5/atacmds.c
@@ -25,12 +25,11 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <syslog.h>
 #include <errno.h>
 #include <stdlib.h>
 #include "atacmds.h"
 
-const char *CVSid1="$Id: atacmds.c,v 1.36 2002/10/30 10:18:37 ballen4705 Exp $" CVSID1;
+const char *CVSid1="$Id: atacmds.c,v 1.37 2002/11/07 11:00:55 ballen4705 Exp $" CVSID1;
 
 // These Drive Identity tables are taken from hdparm 5.2, and are also
 // given in the ATA/ATAPI specs for the IDENTIFY DEVICE command.  Note
@@ -117,15 +116,6 @@ const int actual_ver[] = {
   0		/* 0x001d-0xfffe    		*/
 };
 
-// Used to warn users about invalid checksums.  However we will not
-// abort on invalid checksums.
-void checksumwarning(const char *string){
-  pout("Warning! %s error: invalid SMART checksum.\n",string);
-  fprintf(stderr,"Warning! %s error: invalid SMART checksum.\n",string);
-  syslog(LOG_INFO,"Warning! %s error: invalid SMART checksum.\n",string);
-  return;
-}
-
 // We no longer use this function, because the IOCTL appears to return
 // only the drive identity at the time that the system was booted
 // (perhaps from the BIOS.  It doesn't correctly reflect the current
@@ -299,7 +289,7 @@ int ataReadSmartValues(int device, struct ata_smart_values *data){
   
   // verify that checksum vanishes
   if (chksum)
-    checksumwarning("SMART Data Structure");
+    checksumwarning("SMART Attribute Data Structure");
   
   // copy data and return
   memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE,ATA_SMART_SEC_SIZE);
@@ -324,7 +314,7 @@ int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data){
   for (i=0;i<ATA_SMART_SEC_SIZE;i++)
     chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
   if (chksum)
-    checksumwarning("SMART Self-Test Log");
+    checksumwarning("SMART Self-Test Log Structure");
   
   // copy data back to the user and return
   memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE); 
@@ -348,7 +338,7 @@ int ataReadErrorLog (int device, struct ata_smart_errorlog *data){
   for (i=0;i<ATA_SMART_SEC_SIZE;i++)
     chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
   if (chksum)
-    checksumwarning("SMART Error Log");
+    checksumwarning("SMART ATA Error Log Structure");
   
   //copy data back to user and return
   memcpy(data, buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
@@ -372,7 +362,7 @@ int ataReadSmartThresholds (int device, struct ata_smart_thresholds *data){
   for (i=0;i<ATA_SMART_SEC_SIZE;i++)
     chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
   if (chksum)
-    checksumwarning("SMART Attribute Thresholds");
+    checksumwarning("SMART Attribute Thresholds Structure");
   
   // copy data back to user and return
   memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
diff --git a/sm5/atacmds.cpp b/sm5/atacmds.cpp
index acf7c86e7..00c08b0c8 100644
--- a/sm5/atacmds.cpp
+++ b/sm5/atacmds.cpp
@@ -25,12 +25,11 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <syslog.h>
 #include <errno.h>
 #include <stdlib.h>
 #include "atacmds.h"
 
-const char *CVSid1="$Id: atacmds.cpp,v 1.36 2002/10/30 10:18:37 ballen4705 Exp $" CVSID1;
+const char *CVSid1="$Id: atacmds.cpp,v 1.37 2002/11/07 11:00:55 ballen4705 Exp $" CVSID1;
 
 // These Drive Identity tables are taken from hdparm 5.2, and are also
 // given in the ATA/ATAPI specs for the IDENTIFY DEVICE command.  Note
@@ -117,15 +116,6 @@ const int actual_ver[] = {
   0		/* 0x001d-0xfffe    		*/
 };
 
-// Used to warn users about invalid checksums.  However we will not
-// abort on invalid checksums.
-void checksumwarning(const char *string){
-  pout("Warning! %s error: invalid SMART checksum.\n",string);
-  fprintf(stderr,"Warning! %s error: invalid SMART checksum.\n",string);
-  syslog(LOG_INFO,"Warning! %s error: invalid SMART checksum.\n",string);
-  return;
-}
-
 // We no longer use this function, because the IOCTL appears to return
 // only the drive identity at the time that the system was booted
 // (perhaps from the BIOS.  It doesn't correctly reflect the current
@@ -299,7 +289,7 @@ int ataReadSmartValues(int device, struct ata_smart_values *data){
   
   // verify that checksum vanishes
   if (chksum)
-    checksumwarning("SMART Data Structure");
+    checksumwarning("SMART Attribute Data Structure");
   
   // copy data and return
   memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE,ATA_SMART_SEC_SIZE);
@@ -324,7 +314,7 @@ int ataReadSelfTestLog (int device, struct ata_smart_selftestlog *data){
   for (i=0;i<ATA_SMART_SEC_SIZE;i++)
     chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
   if (chksum)
-    checksumwarning("SMART Self-Test Log");
+    checksumwarning("SMART Self-Test Log Structure");
   
   // copy data back to the user and return
   memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE); 
@@ -348,7 +338,7 @@ int ataReadErrorLog (int device, struct ata_smart_errorlog *data){
   for (i=0;i<ATA_SMART_SEC_SIZE;i++)
     chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
   if (chksum)
-    checksumwarning("SMART Error Log");
+    checksumwarning("SMART ATA Error Log Structure");
   
   //copy data back to user and return
   memcpy(data, buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
@@ -372,7 +362,7 @@ int ataReadSmartThresholds (int device, struct ata_smart_thresholds *data){
   for (i=0;i<ATA_SMART_SEC_SIZE;i++)
     chksum+=buf[HDIO_DRIVE_CMD_HDR_SIZE+i];
   if (chksum)
-    checksumwarning("SMART Attribute Thresholds");
+    checksumwarning("SMART Attribute Thresholds Structure");
   
   // copy data back to user and return
   memcpy(data,buf+HDIO_DRIVE_CMD_HDR_SIZE, ATA_SMART_SEC_SIZE);
diff --git a/sm5/atacmds.h b/sm5/atacmds.h
index cbe706cfc..34bd8f74b 100644
--- a/sm5/atacmds.h
+++ b/sm5/atacmds.h
@@ -26,7 +26,7 @@
 #define _ATACMDS_H_
 
 #ifndef CVSID1
-#define CVSID1 "$Id: atacmds.h,v 1.24 2002/10/30 10:18:37 ballen4705 Exp $\n"
+#define CVSID1 "$Id: atacmds.h,v 1.25 2002/11/07 11:00:55 ballen4705 Exp $\n"
 #endif
 
 // These are the major and minor versions for smartd and smartctl
@@ -367,4 +367,12 @@ int ataCheckAttribute(struct ata_smart_values *data,
 		      struct ata_smart_thresholds *thresholds,
 		      int n);
 
+
+// External handler function, for when a checksum is not correct.  Can
+// simply return if no action is desired, or can print error messages
+// as needed, or exit.  Is passed a string with the name of the Data
+// Structure with the incorrect checksum.
+void checksumwarning(const char *string);
+
+
 #endif /* _ATACMDS_H_ */
diff --git a/sm5/ataprint.c b/sm5/ataprint.c
index d2addfb5e..b995b470d 100644
--- a/sm5/ataprint.c
+++ b/sm5/ataprint.c
@@ -24,12 +24,13 @@
 
 #include <ctype.h>
 #include <stdio.h>
+#include <syslog.h>
 #include "atacmds.h"
 #include "ataprint.h"
 #include "smartctl.h"
 #include "extern.h"
 
-const char *CVSid2="$Id: ataprint.c,v 1.41 2002/10/31 17:40:08 ballen4705 Exp $"
+const char *CVSid2="$Id: ataprint.c,v 1.42 2002/11/07 11:00:55 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID6;
 
 // for passing global control variables
@@ -700,6 +701,45 @@ void ataPseudoCheckSmart ( struct ata_smart_values *data,
 }
 
 
+// Compares failure type to policy in effect, and either exits or
+// simply returns to the calling routine.
+void failuretest(type, returnvalue){
+
+  // If this is an error in an "optional" SMART command
+  if (type==OPTIONAL_CMD){
+    if (con->conservative){
+      pout("An optional SMART command has failed: exiting.  To continue, turn off the -%c option\n",
+	   ULTRACONSERVATIVE);
+      exit(returnvalue);
+    }
+    return;
+  }
+
+  // If this is an error in a "mandatory" SMART command
+  if (type==MANDATORY_CMD){
+    if (con->permissive)
+      return;
+    pout("A mandatory SMART command has failed: exiting. To continue, turn on the -%c option\n",
+	 PERMISSIVE);
+    exit(returnvalue);
+  }
+
+  fprintf(stderr,"Smartctl internal error in failuretest(type=%d). Please contact %s\n",type,PROJECTHOME);
+  exit(returnvalue|FAILCMD);
+}
+
+// Used to warn users about invalid checksums.  However we will not
+// abort on invalid checksums.
+void checksumwarning(const char *string){
+  pout("Warning! %s error: invalid SMART checksum.\n",string);
+  fprintf(stderr,"Warning! %s error: invalid SMART checksum.\n",string);
+  syslog(LOG_INFO,"Warning! %s error: invalid SMART checksum.\n",string);
+
+  if (con->checksumfail)
+    exit(FAILSMART);
+
+  return;
+}
 
 // Initialize to zero just in case some SMART routines don't work
 struct hd_driveid drive;
@@ -715,7 +755,7 @@ int ataPrintMain (int fd){
   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
   if (ataReadHDIdentity(fd,&drive)){
     pout("Smartctl: Hard Drive Read Identity Failed\n\n");
-    returnval|=FAILID;
+    failuretest(MANDATORY_CMD, returnval|=FAILID);
   }
   
   // Print most drive identity information if requested
@@ -727,10 +767,11 @@ int ataPrintMain (int fd){
   // now check if drive supports SMART; otherwise time to exit
   if (!ataSmartSupport(&drive)){
     pout("SMART support is: Unavailable - device lacks SMART capability.\n");
+    failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     pout("                  Checking to be sure by trying SMART ENABLE command.\n");
     if (ataEnableSmart(fd)){
       pout("                  No SMART functionality found. Sorry.\n");
-      return returnval|FAILSMART;
+      failuretest(MANDATORY_CMD,returnval|=FAILSMART);
     }
     else
       pout("                  SMART appears to work.  Continuing.\n"); 
@@ -758,7 +799,7 @@ int ataPrintMain (int fd){
   if (con->smartenable){
     if (ataEnableSmart(fd)) {
       pout("Smartctl: SMART Enable Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Enabled.\n");
@@ -774,7 +815,7 @@ int ataPrintMain (int fd){
   if (con->smartdisable){    
     if (ataDisableSmart(fd)) {
       pout( "Smartctl: SMART Disable Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD,returnval|=FAILSMART);
     }
     pout("SMART Disabled. Use option -%c to enable it.\n",(int)SMARTENABLE);
     return returnval;		
@@ -783,13 +824,13 @@ int ataPrintMain (int fd){
   // Let's ALWAYS issue this command to get the SMART status
   code=ataSmartStatus2(fd);
   if (code==-1)
-    returnval|=FAILSMART;
-  
+    failuretest(MANDATORY_CMD, returnval|=FAILSMART);
+
   // Enable/Disable Auto-save attributes
   if (con->smartautosaveenable){
     if (ataEnableAutoSave(fd)){
       pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Attribute Autosave Enabled.\n");
@@ -797,7 +838,7 @@ int ataPrintMain (int fd){
   if (con->smartautosavedisable){
     if (ataDisableAutoSave(fd)){
       pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Attribute Autosave Disabled.\n");
@@ -806,21 +847,22 @@ int ataPrintMain (int fd){
   // for everything else read values and thresholds are needed
   if (ataReadSmartValues(fd, &smartval)){
     pout("Smartctl: SMART Read Values failed.\n\n");
-    returnval|=FAILSMART;
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   }
   if (ataReadSmartThresholds(fd, &smartthres)){
     pout("Smartctl: SMART Read Thresholds failed.\n\n");
-    returnval|=FAILSMART;
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   }
 
   // Enable/Disable Off-line testing
   if (con->smartautoofflineenable){
     if (!isSupportAutomaticTimer(&smartval)){
       pout("Warning: device does not support SMART Automatic Timers.\n\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     if (ataEnableAutoOffline(fd)){
       pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Automatic Offline Testing Enabled every four hours.\n");
@@ -828,10 +870,11 @@ int ataPrintMain (int fd){
   if (con->smartautoofflinedisable){
     if (!isSupportAutomaticTimer(&smartval)){
       pout("Warning: device does not support SMART Automatic Timers.\n\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     if (ataDisableAutoOffline(fd)){
       pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Automatic Offline Testing Disabled.\n");
@@ -900,14 +943,17 @@ int ataPrintMain (int fd){
   
   // Print SMART error log
   if (con->smarterrorlog){
-    if (!isSmartErrorLogCapable(&smartval))
+    if (!isSmartErrorLogCapable(&smartval)){
       pout("Warning: device does not support Error Logging\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    }
     if (ataReadErrorLog(fd, &smarterror)){
       pout("Smartctl: SMART Errorlog Read Failed\n");
-      returnval|=FAILSMART;
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+
     }
     else {
-      // turn on quiet mode inside this
+      // quiet mode is turned on inside ataPrintSmartErrorLog()
       ataPrintSmartErrorlog(&smarterror);
       QUIETOFF(con);
     }
@@ -915,12 +961,14 @@ int ataPrintMain (int fd){
   
   // Print SMART self-test log
   if (con->smartselftestlog){
-    if (!isSmartErrorLogCapable(&smartval))
+    if (!isSmartErrorLogCapable(&smartval)){
       pout("Warning: device does not support Self Test Logging\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    }    
     else {
       if(ataReadSelfTestLog(fd, &smartselftest)){
 	pout("Smartctl: SMART Self Test Log Read Failed\n");
-	returnval|=FAILSMART;
+	failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
       }
       else {
 	QUIETON(con);
@@ -938,14 +986,17 @@ int ataPrintMain (int fd){
   
   pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
   // if doing a self-test, be sure it's supported by the hardware
-  if (con->testcase==OFFLINE_FULL_SCAN &&  !isSupportExecuteOfflineImmediate(&smartval))
+  if (con->testcase==OFFLINE_FULL_SCAN &&  !isSupportExecuteOfflineImmediate(&smartval)){
     pout("Warning: device does not support Execute Off-Line Immediate function.\n\n");
-  else if (!isSupportSelfTest(&smartval))
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+  }
+  else if (!isSupportSelfTest(&smartval)){
     pout("Warning: device does not support Self-Test functions.\n\n");
-  
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+  }
   // Now do the test
   if (ataSmartTest(fd, con->testcase))
-    return returnval|=FAILSMART;
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   
   // Tell user how long test will take to complete  
   if ((timewait=TestTime(&smartval,con->testcase))){ 
diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp
index 3c9ea726c..6f3fc601d 100644
--- a/sm5/ataprint.cpp
+++ b/sm5/ataprint.cpp
@@ -24,12 +24,13 @@
 
 #include <ctype.h>
 #include <stdio.h>
+#include <syslog.h>
 #include "atacmds.h"
 #include "ataprint.h"
 #include "smartctl.h"
 #include "extern.h"
 
-const char *CVSid2="$Id: ataprint.cpp,v 1.41 2002/10/31 17:40:08 ballen4705 Exp $"
+const char *CVSid2="$Id: ataprint.cpp,v 1.42 2002/11/07 11:00:55 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID6;
 
 // for passing global control variables
@@ -700,6 +701,45 @@ void ataPseudoCheckSmart ( struct ata_smart_values *data,
 }
 
 
+// Compares failure type to policy in effect, and either exits or
+// simply returns to the calling routine.
+void failuretest(type, returnvalue){
+
+  // If this is an error in an "optional" SMART command
+  if (type==OPTIONAL_CMD){
+    if (con->conservative){
+      pout("An optional SMART command has failed: exiting.  To continue, turn off the -%c option\n",
+	   ULTRACONSERVATIVE);
+      exit(returnvalue);
+    }
+    return;
+  }
+
+  // If this is an error in a "mandatory" SMART command
+  if (type==MANDATORY_CMD){
+    if (con->permissive)
+      return;
+    pout("A mandatory SMART command has failed: exiting. To continue, turn on the -%c option\n",
+	 PERMISSIVE);
+    exit(returnvalue);
+  }
+
+  fprintf(stderr,"Smartctl internal error in failuretest(type=%d). Please contact %s\n",type,PROJECTHOME);
+  exit(returnvalue|FAILCMD);
+}
+
+// Used to warn users about invalid checksums.  However we will not
+// abort on invalid checksums.
+void checksumwarning(const char *string){
+  pout("Warning! %s error: invalid SMART checksum.\n",string);
+  fprintf(stderr,"Warning! %s error: invalid SMART checksum.\n",string);
+  syslog(LOG_INFO,"Warning! %s error: invalid SMART checksum.\n",string);
+
+  if (con->checksumfail)
+    exit(FAILSMART);
+
+  return;
+}
 
 // Initialize to zero just in case some SMART routines don't work
 struct hd_driveid drive;
@@ -715,7 +755,7 @@ int ataPrintMain (int fd){
   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
   if (ataReadHDIdentity(fd,&drive)){
     pout("Smartctl: Hard Drive Read Identity Failed\n\n");
-    returnval|=FAILID;
+    failuretest(MANDATORY_CMD, returnval|=FAILID);
   }
   
   // Print most drive identity information if requested
@@ -727,10 +767,11 @@ int ataPrintMain (int fd){
   // now check if drive supports SMART; otherwise time to exit
   if (!ataSmartSupport(&drive)){
     pout("SMART support is: Unavailable - device lacks SMART capability.\n");
+    failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     pout("                  Checking to be sure by trying SMART ENABLE command.\n");
     if (ataEnableSmart(fd)){
       pout("                  No SMART functionality found. Sorry.\n");
-      return returnval|FAILSMART;
+      failuretest(MANDATORY_CMD,returnval|=FAILSMART);
     }
     else
       pout("                  SMART appears to work.  Continuing.\n"); 
@@ -758,7 +799,7 @@ int ataPrintMain (int fd){
   if (con->smartenable){
     if (ataEnableSmart(fd)) {
       pout("Smartctl: SMART Enable Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Enabled.\n");
@@ -774,7 +815,7 @@ int ataPrintMain (int fd){
   if (con->smartdisable){    
     if (ataDisableSmart(fd)) {
       pout( "Smartctl: SMART Disable Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD,returnval|=FAILSMART);
     }
     pout("SMART Disabled. Use option -%c to enable it.\n",(int)SMARTENABLE);
     return returnval;		
@@ -783,13 +824,13 @@ int ataPrintMain (int fd){
   // Let's ALWAYS issue this command to get the SMART status
   code=ataSmartStatus2(fd);
   if (code==-1)
-    returnval|=FAILSMART;
-  
+    failuretest(MANDATORY_CMD, returnval|=FAILSMART);
+
   // Enable/Disable Auto-save attributes
   if (con->smartautosaveenable){
     if (ataEnableAutoSave(fd)){
       pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Attribute Autosave Enabled.\n");
@@ -797,7 +838,7 @@ int ataPrintMain (int fd){
   if (con->smartautosavedisable){
     if (ataDisableAutoSave(fd)){
       pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(MANDATORY_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Attribute Autosave Disabled.\n");
@@ -806,21 +847,22 @@ int ataPrintMain (int fd){
   // for everything else read values and thresholds are needed
   if (ataReadSmartValues(fd, &smartval)){
     pout("Smartctl: SMART Read Values failed.\n\n");
-    returnval|=FAILSMART;
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   }
   if (ataReadSmartThresholds(fd, &smartthres)){
     pout("Smartctl: SMART Read Thresholds failed.\n\n");
-    returnval|=FAILSMART;
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   }
 
   // Enable/Disable Off-line testing
   if (con->smartautoofflineenable){
     if (!isSupportAutomaticTimer(&smartval)){
       pout("Warning: device does not support SMART Automatic Timers.\n\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     if (ataEnableAutoOffline(fd)){
       pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Automatic Offline Testing Enabled every four hours.\n");
@@ -828,10 +870,11 @@ int ataPrintMain (int fd){
   if (con->smartautoofflinedisable){
     if (!isSupportAutomaticTimer(&smartval)){
       pout("Warning: device does not support SMART Automatic Timers.\n\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     if (ataDisableAutoOffline(fd)){
       pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n");
-      returnval|=FAILSMART;
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
     }
     else
       pout("SMART Automatic Offline Testing Disabled.\n");
@@ -900,14 +943,17 @@ int ataPrintMain (int fd){
   
   // Print SMART error log
   if (con->smarterrorlog){
-    if (!isSmartErrorLogCapable(&smartval))
+    if (!isSmartErrorLogCapable(&smartval)){
       pout("Warning: device does not support Error Logging\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    }
     if (ataReadErrorLog(fd, &smarterror)){
       pout("Smartctl: SMART Errorlog Read Failed\n");
-      returnval|=FAILSMART;
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+
     }
     else {
-      // turn on quiet mode inside this
+      // quiet mode is turned on inside ataPrintSmartErrorLog()
       ataPrintSmartErrorlog(&smarterror);
       QUIETOFF(con);
     }
@@ -915,12 +961,14 @@ int ataPrintMain (int fd){
   
   // Print SMART self-test log
   if (con->smartselftestlog){
-    if (!isSmartErrorLogCapable(&smartval))
+    if (!isSmartErrorLogCapable(&smartval)){
       pout("Warning: device does not support Self Test Logging\n");
+      failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+    }    
     else {
       if(ataReadSelfTestLog(fd, &smartselftest)){
 	pout("Smartctl: SMART Self Test Log Read Failed\n");
-	returnval|=FAILSMART;
+	failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
       }
       else {
 	QUIETON(con);
@@ -938,14 +986,17 @@ int ataPrintMain (int fd){
   
   pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
   // if doing a self-test, be sure it's supported by the hardware
-  if (con->testcase==OFFLINE_FULL_SCAN &&  !isSupportExecuteOfflineImmediate(&smartval))
+  if (con->testcase==OFFLINE_FULL_SCAN &&  !isSupportExecuteOfflineImmediate(&smartval)){
     pout("Warning: device does not support Execute Off-Line Immediate function.\n\n");
-  else if (!isSupportSelfTest(&smartval))
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+  }
+  else if (!isSupportSelfTest(&smartval)){
     pout("Warning: device does not support Self-Test functions.\n\n");
-  
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
+  }
   // Now do the test
   if (ataSmartTest(fd, con->testcase))
-    return returnval|=FAILSMART;
+    failuretest(OPTIONAL_CMD, returnval|=FAILSMART);
   
   // Tell user how long test will take to complete  
   if ((timewait=TestTime(&smartval,con->testcase))){ 
diff --git a/sm5/extern.h b/sm5/extern.h
index 85ebca773..11ea651ef 100644
--- a/sm5/extern.h
+++ b/sm5/extern.h
@@ -27,7 +27,7 @@
 
 
 #ifndef CVSID3
-#define CVSID3 "$Id: extern.h,v 1.9 2002/10/28 23:46:59 ballen4705 Exp $\n"
+#define CVSID3 "$Id: extern.h,v 1.10 2002/11/07 11:00:56 ballen4705 Exp $\n"
 #endif
 
 // Block used for global control/communications.  If you need more
@@ -57,6 +57,9 @@ typedef struct ataprintmain_s {
   int           testcase;
   unsigned char quietmode;
   unsigned char veryquietmode;
+  unsigned char permissive;
+  unsigned char conservative;
+  unsigned char checksumfail;
 } atamainctrl;
 
 #endif
diff --git a/sm5/smartctl.8 b/sm5/smartctl.8
index dc925651b..335eb39b2 100644
--- a/sm5/smartctl.8
+++ b/sm5/smartctl.8
@@ -1,6 +1,6 @@
 \# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 \#
-\# $Id: smartctl.8,v 1.23 2002/11/04 13:32:08 ballen4705 Exp $
+\# $Id: smartctl.8,v 1.24 2002/11/07 11:00:56 ballen4705 Exp $
 \# 
 \# This program is free software; you can redistribute it and/or modify it
 \# under the terms of the GNU General Public License as published by the Free
@@ -15,11 +15,11 @@
 \# at the Concurrent Systems Laboratory (now part of the Storage Systems
 \# Research Center), Jack Baskin School of Engineering, University of
 \# California, Santa Cruz. http://ssrc.soe.ucsc.edu/
-.TH SMARTCTL 8  "$Date: 2002/11/04 13:32:08 $" "smartmontools-5.0"
+.TH SMARTCTL 8  "$Date: 2002/11/07 11:00:56 $" "smartmontools-5.0"
 .SH NAME
 smartctl \- S.M.A.R.T. control and monitor utility 
 .SH SYNOPSIS
-.B smartctl \-[ViqQaedtTfFcgvlLm[O|S|s|X|x|A]] device
+.B smartctl \-[ViaqQnNPUWedtTfFcgvlLm[O|S|s|X|x|A]] device
 
 .SH DESCRIPTION
 .B smartctl
@@ -94,6 +94,12 @@ firmware version, and ATA Standard version/revision information.
 Says if the device supports S.M.A.R.T., and if so, whether
 S.M.A.R.T. support is currently enabled or disabled.
 .TP
+.B a
+All: Prints all parameters for c,i,g,v,t,l,L (for SCSI c,i).  This prints all
+S.M.A.R.T. information about the disk.
+.TP
+.B RUN-TIME BEHAVIOR:
+.TP
 .B q
 Quiet mode: Only print: For the '\-l' option, if nonzero, the number
 of errors recorded in the SMART error log and the power-on time when
@@ -109,10 +115,6 @@ found is to use the exit status of
 .B smartctl
 (see RETURN VALUES below).
 .TP
-.B a
-All: Prints all parameters for c,i,g,v,t,l,L (for SCSI c,i).  This prints all
-S.M.A.R.T. information about the disk.
-.TP
 .B n
 NotSCSI: Device is an ATA device.
 .TP
@@ -121,7 +123,41 @@ NotATA: Device is a SCSI device. If neither this nor the previous
 option are specified, then
 .B smartctl
 will attempt to guess the device type from the device name.  You can
-use this option or the previous option to over-ride to force the type.
+use this option or the previous option to force the type.
+.TP
+.B P
+Permissive: If a mandatory S.M.A.R.T. command to the
+disk fails, do
+.I not
+exit, but carry on in spite of it. Normally (without this option
+enabled)
+.B smartctl
+would exit with an error if a mandatory command failed.  Here 'mandatory'
+means "Required by the ATA/ATAPI-5 Specification if the
+device implements the S.M.A.R.T. command set."  The 'mandatory'
+S.M.A.R.T. commands are: (1) Enable/Disable Attribute Autosave, (2)
+Enable/Disable S.M.A.R.T., and (3) S.M.A.R.T. Return Status.
+.TP
+.B U
+Ultraconservative: Exit
+.B smartctl
+immediately if an optional S.M.A.R.T. command to the disk fails.
+Normally (without this option enabled)
+.B smartctl
+would just carry on if an optional command fails.  Here "optional"
+means "Not required by the ATA/ATAPI-5 Specification even if the
+device implements the S.M.A.R.T. command set."
+.TP
+.B W
+Warning: Exit
+.B smartctl
+immediately if a checksum error is detected in the: (1) Device
+Identity Structure, (2) S.M.A.R.T. Self-Test Log Structure, (3)
+S.M.A.R.T. Attribute Value Structure, (4) S.M.A.R.T. Attribute
+Threshold Structure, or (5) ATA Error Log Structure.  Normally
+(without this option enabled)
+.B smartctl
+will report the incorrect checksum but will carry on in spite of it.
 .TP
 .B S.M.A.R.T. FEATURE ENABLE/DISABLE COMMANDS:
 .IP
@@ -385,7 +421,8 @@ Command line did not parse.
 Device open failed, or device did not return an IDENTIFY DEVICE structure. 
 .TP
 .B Bit 2:
-Some SMART command to the disk failed. 
+Some SMART command to the disk failed, or there was a checksum error
+in a SMART data structure (see '\-W' option above).
 .TP
 .B Bit 3:
 SMART status check returned "DISK FAILING".
@@ -490,4 +527,4 @@ Please let us know if there is an on\-line source for this document.
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartctl.8,v 1.23 2002/11/04 13:32:08 ballen4705 Exp $
+$Id: smartctl.8,v 1.24 2002/11/07 11:00:56 ballen4705 Exp $
diff --git a/sm5/smartctl.c b/sm5/smartctl.c
index 03e84c67f..e7cc4b943 100644
--- a/sm5/smartctl.c
+++ b/sm5/smartctl.c
@@ -39,7 +39,7 @@
 #include "extern.h"
 
 extern const char *CVSid1, *CVSid2, *CVSid3, *CVSid4; 
-const char* CVSid5="$Id: smartctl.c,v 1.25 2002/11/04 13:32:08 ballen4705 Exp $"
+const char* CVSid5="$Id: smartctl.c,v 1.26 2002/11/07 11:00:56 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID5 CVSID6;
 
 // This is a block containing all the "control variables".  We declare
@@ -77,29 +77,34 @@ void printcopy(){
 /*  void prints help information for command syntax */
 void Usage ( void){
   printf("Usage: smartctl -[options] [device]\n");
-  printf("\nRead Only Options:\n");
-  printf("  %c  Show version, copyright and license info\n", PRINTCOPYLEFT);
-  printf("  %c  Show all SMART Information              (ATA/SCSI)\n",SMARTVERBOSEALL);
+  printf("\nShow Information Options:\n");
+  printf("  %c  Show Version, Copyright and License info\n", PRINTCOPYLEFT);
   printf("  %c  Show SMART Drive Info                   (ATA/SCSI)\n",DRIVEINFO);
-  printf("  %c  Show SMART Status                       (ATA/SCSI)\n",CHECKSMART);
-  printf("  %c  Show SMART General Attributes           (ATA Only)\n",    GENERALSMARTVALUES);
-  printf("  %c  Show SMART Vendor Attributes            (ATA Only)\n",    SMARTVENDORATTRIB);
-  printf("  %c  Show SMART Drive Error Log              (ATA Only\n",     SMARTERRORLOG);
-  printf("  %c  Show SMART Drive Self Test Log          (ATA Only)\n",    SMARTSELFTESTLOG);
-  printf("  %c  Quiet: only show SMART drive errors     (ATA Only)\n",    QUIETMODE);
-  printf("  %c  Very Quiet: no display, use exit status (ATA Only)\n",    VERYQUIETMODE);  
-  printf("  %c  Device is an ATA device                 (ATA Only)\n",    NOTSCSIDEVICE);
-  printf("  %c  Device is a SCSI device                 (SCSI Only)\n",   NOTATADEVICE);
-  printf("\nVendor-specific Display Options:\n");
-  printf("  %c  Raw Attribute 009 is minutes            (ATA Only)\n",    SMART009MINUTES);
-  printf("\nEnable/Disable Options:\n");
-  printf("  %c  Enable  SMART data collection           (ATA/SCSI)\n",SMARTENABLE);
-  printf("  %c  Disable SMART data collection           (ATA/SCSI)\n",SMARTDISABLE);
+  printf("  %c  Show all SMART Information              (ATA/SCSI)\n",SMARTVERBOSEALL);
+  printf("\nRun-time Behavior Options:\n");
+  printf("  %c  Quiet: only show SMART Drive Errors     (ATA Only)\n",    QUIETMODE);
+  printf("  %c  Very Quiet: no display, use Exit Status (ATA Only)\n",    VERYQUIETMODE);  
+  printf("  %c  Device is an ATA Device                 (ATA Only)\n",    NOTSCSIDEVICE);
+  printf("  %c  Device is a SCSI Device                 (SCSI Only)\n",   NOTATADEVICE);
+  printf("  %c  Permissive: continue on Mandatory fails (ATA Only)\n",    PERMISSIVE);
+  printf("  %c  Conservative: exit if Optional Cmd fail (ATA Only)\n",    ULTRACONSERVATIVE);  
+  printf("  %c  Warning: exit if Struct Checksum bad    (ATA Only)\n",    EXITCHECKSUMERROR);
+  printf("\nSMART Feature Enable/Disable Commands:\n");
+  printf("  %c  Enable  SMART data collection           (ATA/SCSI)\n",    SMARTENABLE);
+  printf("  %c  Disable SMART data collection           (ATA/SCSI)\n",    SMARTDISABLE);
   printf("  %c  Enable  SMART Automatic Offline Test    (ATA Only)\n",    SMARTAUTOOFFLINEENABLE);
   printf("  %c  Disable SMART Automatic Offline Test    (ATA Only)\n",    SMARTAUTOOFFLINEDISABLE);
   printf("  %c  Enable  SMART Attribute Autosave        (ATA Only)\n",    SMARTAUTOSAVEENABLE);
   printf("  %c  Disable SMART Attribute Autosave        (ATA Only)\n",    SMARTAUTOSAVEDISABLE);
-  printf("\nTest Options (no more than one):\n");
+  printf("\nRead and Display Data Options:\n");
+  printf("  %c  Show SMART Status                       (ATA/SCSI)\n",    CHECKSMART);
+  printf("  %c  Show SMART General Attributes           (ATA Only)\n",    GENERALSMARTVALUES);
+  printf("  %c  Show SMART Vendor Attributes            (ATA Only)\n",    SMARTVENDORATTRIB);
+  printf("  %c  Show SMART Drive Error Log              (ATA Only\n",     SMARTERRORLOG);
+  printf("  %c  Show SMART Drive Self Test Log          (ATA Only)\n",    SMARTSELFTESTLOG);
+  printf("\nVendor-specific Attribute Display Options:\n");
+  printf("  %c  Raw Attribute id=009 stored in minutes  (ATA Only)\n",    SMART009MINUTES);
+  printf("\nSelf-Test Options (no more than one):\n");
   printf("  %c  Execute Off-line data collection        (ATA/SCSI)\n",    SMARTEXEOFFIMMEDIATE);
   printf("  %c  Execute Short Self Test                 (ATA/SCSI)\n",    SMARTSHORTSELFTEST );
   printf("  %c  Execute Short Self Test (Captive Mode)  (ATA/SCSI)\n",    SMARTSHORTCAPSELFTEST );
@@ -120,7 +125,9 @@ const char opts[] = {
   SMARTEXEOFFIMMEDIATE, SMARTSHORTSELFTEST, SMARTEXTENDSELFTEST, 
   SMARTSHORTCAPSELFTEST, SMARTEXTENDCAPSELFTEST, SMARTSELFTESTABORT,
   SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,
-  QUIETMODE,VERYQUIETMODE,NOTSCSIDEVICE,NOTATADEVICE,'h','?','\0'
+  QUIETMODE,VERYQUIETMODE,NOTSCSIDEVICE,NOTATADEVICE,
+  EXITCHECKSUMERROR,ULTRACONSERVATIVE,PERMISSIVE,
+  'h','?','\0'
 };
 
 unsigned char printcopyleft=0,tryata=0,tryscsi=0;
@@ -136,6 +143,15 @@ void ParseOpts (int argc, char** argv){
   opterr=optopt=0;
   while (-1 != (optchar = getopt(argc, argv, opts))) {
     switch (optchar){
+    case EXITCHECKSUMERROR:
+      con->checksumfail=1;
+      break;
+    case PERMISSIVE:
+      con->permissive=1;
+      break;
+    case ULTRACONSERVATIVE:
+      con->conservative=1;
+      break;
     case NOTATADEVICE:
       tryata=0;
       tryscsi=1;
diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp
index 8e4c0d9d5..b299655a8 100644
--- a/sm5/smartctl.cpp
+++ b/sm5/smartctl.cpp
@@ -39,7 +39,7 @@
 #include "extern.h"
 
 extern const char *CVSid1, *CVSid2, *CVSid3, *CVSid4; 
-const char* CVSid5="$Id: smartctl.cpp,v 1.25 2002/11/04 13:32:08 ballen4705 Exp $"
+const char* CVSid5="$Id: smartctl.cpp,v 1.26 2002/11/07 11:00:56 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID5 CVSID6;
 
 // This is a block containing all the "control variables".  We declare
@@ -77,29 +77,34 @@ void printcopy(){
 /*  void prints help information for command syntax */
 void Usage ( void){
   printf("Usage: smartctl -[options] [device]\n");
-  printf("\nRead Only Options:\n");
-  printf("  %c  Show version, copyright and license info\n", PRINTCOPYLEFT);
-  printf("  %c  Show all SMART Information              (ATA/SCSI)\n",SMARTVERBOSEALL);
+  printf("\nShow Information Options:\n");
+  printf("  %c  Show Version, Copyright and License info\n", PRINTCOPYLEFT);
   printf("  %c  Show SMART Drive Info                   (ATA/SCSI)\n",DRIVEINFO);
-  printf("  %c  Show SMART Status                       (ATA/SCSI)\n",CHECKSMART);
-  printf("  %c  Show SMART General Attributes           (ATA Only)\n",    GENERALSMARTVALUES);
-  printf("  %c  Show SMART Vendor Attributes            (ATA Only)\n",    SMARTVENDORATTRIB);
-  printf("  %c  Show SMART Drive Error Log              (ATA Only\n",     SMARTERRORLOG);
-  printf("  %c  Show SMART Drive Self Test Log          (ATA Only)\n",    SMARTSELFTESTLOG);
-  printf("  %c  Quiet: only show SMART drive errors     (ATA Only)\n",    QUIETMODE);
-  printf("  %c  Very Quiet: no display, use exit status (ATA Only)\n",    VERYQUIETMODE);  
-  printf("  %c  Device is an ATA device                 (ATA Only)\n",    NOTSCSIDEVICE);
-  printf("  %c  Device is a SCSI device                 (SCSI Only)\n",   NOTATADEVICE);
-  printf("\nVendor-specific Display Options:\n");
-  printf("  %c  Raw Attribute 009 is minutes            (ATA Only)\n",    SMART009MINUTES);
-  printf("\nEnable/Disable Options:\n");
-  printf("  %c  Enable  SMART data collection           (ATA/SCSI)\n",SMARTENABLE);
-  printf("  %c  Disable SMART data collection           (ATA/SCSI)\n",SMARTDISABLE);
+  printf("  %c  Show all SMART Information              (ATA/SCSI)\n",SMARTVERBOSEALL);
+  printf("\nRun-time Behavior Options:\n");
+  printf("  %c  Quiet: only show SMART Drive Errors     (ATA Only)\n",    QUIETMODE);
+  printf("  %c  Very Quiet: no display, use Exit Status (ATA Only)\n",    VERYQUIETMODE);  
+  printf("  %c  Device is an ATA Device                 (ATA Only)\n",    NOTSCSIDEVICE);
+  printf("  %c  Device is a SCSI Device                 (SCSI Only)\n",   NOTATADEVICE);
+  printf("  %c  Permissive: continue on Mandatory fails (ATA Only)\n",    PERMISSIVE);
+  printf("  %c  Conservative: exit if Optional Cmd fail (ATA Only)\n",    ULTRACONSERVATIVE);  
+  printf("  %c  Warning: exit if Struct Checksum bad    (ATA Only)\n",    EXITCHECKSUMERROR);
+  printf("\nSMART Feature Enable/Disable Commands:\n");
+  printf("  %c  Enable  SMART data collection           (ATA/SCSI)\n",    SMARTENABLE);
+  printf("  %c  Disable SMART data collection           (ATA/SCSI)\n",    SMARTDISABLE);
   printf("  %c  Enable  SMART Automatic Offline Test    (ATA Only)\n",    SMARTAUTOOFFLINEENABLE);
   printf("  %c  Disable SMART Automatic Offline Test    (ATA Only)\n",    SMARTAUTOOFFLINEDISABLE);
   printf("  %c  Enable  SMART Attribute Autosave        (ATA Only)\n",    SMARTAUTOSAVEENABLE);
   printf("  %c  Disable SMART Attribute Autosave        (ATA Only)\n",    SMARTAUTOSAVEDISABLE);
-  printf("\nTest Options (no more than one):\n");
+  printf("\nRead and Display Data Options:\n");
+  printf("  %c  Show SMART Status                       (ATA/SCSI)\n",    CHECKSMART);
+  printf("  %c  Show SMART General Attributes           (ATA Only)\n",    GENERALSMARTVALUES);
+  printf("  %c  Show SMART Vendor Attributes            (ATA Only)\n",    SMARTVENDORATTRIB);
+  printf("  %c  Show SMART Drive Error Log              (ATA Only\n",     SMARTERRORLOG);
+  printf("  %c  Show SMART Drive Self Test Log          (ATA Only)\n",    SMARTSELFTESTLOG);
+  printf("\nVendor-specific Attribute Display Options:\n");
+  printf("  %c  Raw Attribute id=009 stored in minutes  (ATA Only)\n",    SMART009MINUTES);
+  printf("\nSelf-Test Options (no more than one):\n");
   printf("  %c  Execute Off-line data collection        (ATA/SCSI)\n",    SMARTEXEOFFIMMEDIATE);
   printf("  %c  Execute Short Self Test                 (ATA/SCSI)\n",    SMARTSHORTSELFTEST );
   printf("  %c  Execute Short Self Test (Captive Mode)  (ATA/SCSI)\n",    SMARTSHORTCAPSELFTEST );
@@ -120,7 +125,9 @@ const char opts[] = {
   SMARTEXEOFFIMMEDIATE, SMARTSHORTSELFTEST, SMARTEXTENDSELFTEST, 
   SMARTSHORTCAPSELFTEST, SMARTEXTENDCAPSELFTEST, SMARTSELFTESTABORT,
   SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,
-  QUIETMODE,VERYQUIETMODE,NOTSCSIDEVICE,NOTATADEVICE,'h','?','\0'
+  QUIETMODE,VERYQUIETMODE,NOTSCSIDEVICE,NOTATADEVICE,
+  EXITCHECKSUMERROR,ULTRACONSERVATIVE,PERMISSIVE,
+  'h','?','\0'
 };
 
 unsigned char printcopyleft=0,tryata=0,tryscsi=0;
@@ -136,6 +143,15 @@ void ParseOpts (int argc, char** argv){
   opterr=optopt=0;
   while (-1 != (optchar = getopt(argc, argv, opts))) {
     switch (optchar){
+    case EXITCHECKSUMERROR:
+      con->checksumfail=1;
+      break;
+    case PERMISSIVE:
+      con->permissive=1;
+      break;
+    case ULTRACONSERVATIVE:
+      con->conservative=1;
+      break;
     case NOTATADEVICE:
       tryata=0;
       tryscsi=1;
diff --git a/sm5/smartctl.h b/sm5/smartctl.h
index 1ba80691c..3b18efef9 100644
--- a/sm5/smartctl.h
+++ b/sm5/smartctl.h
@@ -26,7 +26,7 @@
 #define __SMARTCTL_H_
 
 #ifndef CVSID6
-#define CVSID6 "$Id: smartctl.h,v 1.11 2002/11/04 13:32:09 ballen4705 Exp $\n"
+#define CVSID6 "$Id: smartctl.h,v 1.12 2002/11/07 11:00:56 ballen4705 Exp $\n"
 #endif
 
 /* Defines for command line options */ 
@@ -55,6 +55,9 @@
 #define VERYQUIETMODE           'Q'
 #define NOTATADEVICE            'N'
 #define NOTSCSIDEVICE           'n'
+#define EXITCHECKSUMERROR        'W'
+#define ULTRACONSERVATIVE       'U'
+#define PERMISSIVE              'P'
 
 
 /* Boolean Values */
@@ -89,4 +92,12 @@
 // Device had Errors in the self-test log
 #define FAILLOG (0x01<<7)
 
+// Classes of SMART commands.  Here 'mandatory' means "Required by the
+// ATA/ATAPI-5 Specification if the device implements the S.M.A.R.T.
+// command set."  The 'mandatory' S.M.A.R.T.  commands are: (1)
+// Enable/Disable Attribute Autosave, (2) Enable/Disable S.M.A.R.T.,
+// and (3) S.M.A.R.T. Return Status.  All others are optional.
+#define OPTIONAL_CMD 1
+#define MANDATORY_CMD 2
+
 #endif
diff --git a/sm5/smartd.c b/sm5/smartd.c
index df1227ff8..f2f511910 100644
--- a/sm5/smartd.c
+++ b/sm5/smartd.c
@@ -44,7 +44,7 @@
 
 // CVS ID strings
 extern const char *CVSid1, *CVSid2;
-const char *CVSid6="$Id: smartd.c,v 1.51 2002/10/31 17:40:10 ballen4705 Exp $" 
+const char *CVSid6="$Id: smartd.c,v 1.52 2002/11/07 11:00:56 ballen4705 Exp $" 
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
 
 // global variable used for control of printing, passing arguments, etc.
@@ -1151,7 +1151,7 @@ int main (int argc, char **argv){
   // Do we mute printing from ataprint commands?
   con->quietmode=0;
   con->veryquietmode=debugmode?0:1;
-  
+  con->checksumfail=0;
 
   // look in configuration file CONFIGFILE (normally /etc/smartd.conf)
   entries=parseconfigfile();
diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp
index 07b7d8c56..c2f44fc91 100644
--- a/sm5/smartd.cpp
+++ b/sm5/smartd.cpp
@@ -44,7 +44,7 @@
 
 // CVS ID strings
 extern const char *CVSid1, *CVSid2;
-const char *CVSid6="$Id: smartd.cpp,v 1.51 2002/10/31 17:40:10 ballen4705 Exp $" 
+const char *CVSid6="$Id: smartd.cpp,v 1.52 2002/11/07 11:00:56 ballen4705 Exp $" 
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
 
 // global variable used for control of printing, passing arguments, etc.
@@ -1151,7 +1151,7 @@ int main (int argc, char **argv){
   // Do we mute printing from ataprint commands?
   con->quietmode=0;
   con->veryquietmode=debugmode?0:1;
-  
+  con->checksumfail=0;
 
   // look in configuration file CONFIGFILE (normally /etc/smartd.conf)
   entries=parseconfigfile();
diff --git a/sm5/smartmontools.spec b/sm5/smartmontools.spec
index 868943585..166398eb7 100644
--- a/sm5/smartmontools.spec
+++ b/sm5/smartmontools.spec
@@ -1,18 +1,18 @@
-Release:  30
+Release:  31
 Summary:	SMARTmontools - for monitoring S.M.A.R.T. disks and devices
-Summary(de):	SMARTmontools - zur �berwachung von S.M.A.R.T.-Platten und-Ger�ten
-Summary(es):	SMARTmontools - para el seguimiento de discos y dispositivos S.M.A.R.T.
-Summary(fr):	SMARTmontools - pour le suivi des disques et instruments S.M.A.R.T.
-Summary(pt_BR):	SMARTmontools - para monitorar discos e dispositivos S.M.A.R.T.
-Summary(pl):	Monitorowanie i kontrola dysk�w u�ywaj�� S.M.A.R.T.
+Summary(de.iso-8859-1):	SMARTmontools - zur �berwachung von S.M.A.R.T.-Platten und-Ger�ten
+Summary(es.iso-8859-1):	SMARTmontools - para el seguimiento de discos y dispositivos S.M.A.R.T.
+Summary(fr.iso-8859-1):	SMARTmontools - pour le suivi des disques et instruments S.M.A.R.T.
+Summary(pt.iso-8859-1):	SMARTmontools - para monitorar discos e dispositivos S.M.A.R.T.
+Summary(pl.iso-8859-2):	Monitorowanie i kontrola dysk�w u�ywaj�� S.M.A.R.T.
 Name:		smartmontools
 Version:	5.0
 License:	GPL
 Group:		Applications/System
-Group(de):	Applikationen/System
-Group(es):	Aplicaciones/Sistema
-Group(fr):	Applications/Syst�me
-Group(pt_NR):	Aplicativos/Sistema
+Group(de.iso-8859-1):	Applikationen/System
+Group(es.iso-8859-1):	Aplicaciones/Sistema
+Group(fr.iso-8859-1):	Applications/Syst�me
+Group(pt.iso-8859-1):	Aplicativos/Sistema
 Source0:	%{name}-%{version}.tar.gz
 URL:            http://smartmontools.sourceforge.net/
 Prereq:		/sbin/chkconfig
@@ -27,7 +27,7 @@ Packager:       Bruce Allen <smartmontools-support@lists.sourceforge.net>
 # http://ftp1.sourceforge.net/smartmontools/smartmontools-%{version}-%{release}.tar.gz
 
 # CVS ID of this file is:
-# $Id: smartmontools.spec,v 1.46 2002/11/05 02:46:16 ballen4705 Exp $
+# $Id: smartmontools.spec,v 1.47 2002/11/07 11:00:56 ballen4705 Exp $
 
 # Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 # Home page: http://smartmontools.sourceforge.net/
@@ -66,7 +66,7 @@ modern linux distribution.  The most recent versions of this package and
 additional information can be found at the URL:
 http://smartmontools.sourceforge.net/
 
-%description -l de
+%description -l de.iso-8859-1
 Die SMARTmontools steuern und �berwachen Speicherger�te mittels des
 S.M.A.R.T.-Systems (Self-Monitoring, Analysis and Reporting Technology,
 Technologie zur Selbst-�berwachung, Analyse und Berichterstellung), das
@@ -87,7 +87,7 @@ jedem modernen Linux arbeiten.  Die aktuellsten Versionen dieses Pakets
 und zus�tzliche Informationen sind zu finden unter der URL:
 http://smartmontools.sourceforge.net/
 
-%description -l es
+%description -l es.iso-8859-1
 SMARTmontools controla y hace el seguimiento de dispositivos de
 almacenamiento usando el Self-Monitoring, Analysis and Reporting
 Technology System (S.M.A.R.T.) incorporado en discos duros ATA y SCSI. 
@@ -107,7 +107,7 @@ funcionaran sin problemas en cualquier distribucion moderna de linux.
 La version mas reciente de estos programas ademas de informacion
 adicional pueden encontrarse en: http://smartmontools.sourceforge.net/
 
-%description -l fr
+%description -l fr.iso-8859-1
 SMARTmontools contr�le et fait le suivi de p�riph�riques de stockage
 utilisant le syst�me Self-Monitoring, Analysis and Reporting
 Technology (S.M.A.R.T) int�gr�dans les disques durs ATA et SCSI.  Ce
@@ -129,7 +129,7 @@ Les derni
 peuvent �tre trouv�es � l'adresse URL:
 http://smartmontools.sourceforge.net/
 
-%description -l pt_BR
+%description -l pt.iso-8859-1
 SMARTmontools controla e monitora dispositivos de armazenamento
 utilizando o recurso Self-Monitoring, Analysis and Reporting Technology
 System (S.M.A.R.T.) integrado nos discos r�gidos ATA e SCSI, cuja
@@ -148,7 +148,7 @@ Este arquivo RPM 
 Linux.  As mais recentes vers�es deste pacote e informa��es adicionais
 podem ser encontradas em http://smartmontools.sourceforge.net/
 
-%description -l pl
+%description -l pl.iso-8859-2
 Pakiet zawiera dwa programy (smartctl oraz smartd) do kontroli i
 monitorowania system�w przechowywania danych za pomoc� S.M.A.R.T -
 systemu wbudowanego w wi�kszo�� nowych dysk�w ATA oraz SCSI. Pakiet
@@ -213,6 +213,17 @@ fi
 
 %define date	%(echo `LC_ALL="C" date +"%a %b %d %Y"`)
 %changelog
+* Thu Nov 7 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+- modified .spec file so that locale information now contains
+  character set definition.   Changed pt_BR to pt since we do not use any
+  aspect other than language.  See man setlocale.
+- smartctl: added new options -W, -U, and -P to control if and how the
+  smartctl exits if an error is detected in either a SMART data
+  structure checksum, or a SMART command returns an error.
+- modified manual page to break options into slightly more logical
+  categories.
+- reformatted 'usage' message order to agree with man page ordering
+
 * Mon Nov 4 2002 Bruce Allen  <smartmontools-support@lists.sourceforge.net>
 - smartctl: added new options -n and -N to force device to be ATA or SCSI
 - smartctl: no longer dies silently if device path does not start/dev/X
-- 
GitLab