From 26a7af76efd50783ac1d1a9016d3b3e65aff2868 Mon Sep 17 00:00:00 2001
From: ballen4705 <ballen4705@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Tue, 22 Oct 2002 16:49:16 +0000
Subject: [PATCH]     smartctl now returns sensible values (bitmask).  See
 smartctl.h     for the values.  I may add some additional values as time goes
 on,     so this is prelimiary.

    The SMART status check now uses the correct ATA call.  If failure
    is detected we search through attributes to list the failed ones.
    If the SMART status check shows GOOD, we then look to see if their
    are any usage attributes or prefail attributes have failed at any
    time.  If so we print them.

    Modified function that prints vendor attributes to say if the
    attribute has currently failed or has ever failed.


git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@86 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG    |  12 +++++-
 sm5/ataprint.c   | 109 +++++++++++++++++++++++++++++------------------
 sm5/ataprint.cpp | 109 +++++++++++++++++++++++++++++------------------
 sm5/ataprint.h   |   4 +-
 sm5/smartctl.8   |  18 ++++++--
 sm5/smartctl.c   |  42 +++++++++---------
 sm5/smartctl.cpp |  42 +++++++++---------
 sm5/smartctl.h   |  26 ++++++++++-
 8 files changed, 231 insertions(+), 131 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 834f014f3..0a7c02ab0 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.13 2002/10/22 11:40:52 ballen4705 Exp $
+$Id: CHANGELOG,v 1.14 2002/10/22 16:49:15 ballen4705 Exp $
 
 Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
@@ -29,6 +29,16 @@ NOTES FOR NEXT RELEASE:
 
 smartmontools-5.0-11
 
+    smartctl now returns sensible values (bitmask).  See smartctl.h
+    for the values.  I may add some additional values as time goes on,
+    so this is prelimiary.
+
+    The SMART status check now uses the correct ATA call.  If failure
+    is detected we search through attributes to list the failed ones.
+    If the SMART status check shows GOOD, we then look to see if their
+    are any usage attributes or prefail attributes have failed at any
+    time.  If so we print them.
+
     Modified function that prints vendor attributes to say if the
     attribute has currently failed or has ever failed.
 
diff --git a/sm5/ataprint.c b/sm5/ataprint.c
index 41bbcde8f..d946656d3 100644
--- a/sm5/ataprint.c
+++ b/sm5/ataprint.c
@@ -28,7 +28,7 @@
 #include "smartctl.h"
 #include "extern.h"
 
-const char *CVSid4="$Id: ataprint.c,v 1.22 2002/10/22 15:37:15 ballen4705 Exp $\n"
+const char *CVSid4="$Id: ataprint.c,v 1.23 2002/10/22 16:49:16 ballen4705 Exp $\n"
 	           "\t" CVSID2 "\t" CVSID3 "\t" CVSID6 ;
 
 // Function for printing ASCII byte-swapped strings, skipping white
@@ -401,7 +401,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values data,
       
       // is this currently failed, or has it ever failed?
       if (failednow)
-	status="FAILED NOW!";
+	status="FAILED_NOW!";
       else if (failedever)
 	status="In_the_past";
       else
@@ -412,7 +412,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values data,
       
       // printing line for each valid attribute
       type=disk->status.flag.prefailure?"Pre-fail":"Old_age";
-      printf(" 0x%04x   %.3i   %.3i   %.3i    %-9s%-13s", 
+      printf(" 0x%04x   %.3i   %.3i   %.3i    %-9s%-12s", 
 	     disk->status.all, disk->current, disk->worst,
 	     thre->threshold, type, status);
       
@@ -819,13 +819,15 @@ struct ata_smart_thresholds smartthres;
 struct ata_smart_errorlog smarterror;
 struct ata_smart_selftestlog smartselftest;
 
-void ataPrintMain (int fd){
+int ataPrintMain (int fd){
   int timewait,code;
+  int returnval=0;
   
   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
   if (ataReadHDIdentity(fd,&drive)){
     printf("Smartctl: Hard Drive Read Identity Failed\n\n");
-  }
+    returnval|=FAILID;
+}
   
   // Print most drive identity information if requested
   if (driveinfo){
@@ -839,7 +841,7 @@ void ataPrintMain (int fd){
     printf("                  Checking to be sure by trying SMART ENABLE command.\n");
     if (ataEnableSmart(fd)){
       printf("                  No SMART functionality found. Sorry.\n");
-      exit(0);
+      return returnval|FAILSMART;
     }
     else
       printf("                  SMART appears to work.  Continuing.\n"); 
@@ -864,6 +866,7 @@ void ataPrintMain (int fd){
   if (smartenable){
     if (ataEnableSmart(fd)) {
       printf("Smartctl: SMART Enable Failed.\n\n");
+      returnval|=FAILSMART;
     }
     else
       printf("SMART Enabled.\n");
@@ -872,56 +875,72 @@ void ataPrintMain (int fd){
   // From here on, every command requires that SMART be enabled...
   if (!ataDoesSmartWork(fd)) {
     printf("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE );
-    exit(0);
+    return returnval;
   }
   
   // Turn off SMART on device
   if (smartdisable){    
     if (ataDisableSmart(fd)) {
       printf( "Smartctl: SMART Disable Failed.\n\n");
+      returnval|=FAILSMART;
     }
     printf("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE);
-    exit (0);		
+    return returnval;		
   }
   
   // Let's ALWAYS issue this command to get the SMART status
   code=ataSmartStatus2(fd);
-
+  if (code==-1)
+    returnval|=FAILSMART;
+  
   // Enable/Disable Auto-save attributes
   if (smartautosaveenable){
-    if (ataEnableAutoSave(fd))
+    if (ataEnableAutoSave(fd)){
       printf( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf("SMART Attribute Autosave Enabled.\n");
   }
   if (smartautosavedisable){
-    if (ataDisableAutoSave(fd))
+    if (ataDisableAutoSave(fd)){
       printf( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf("SMART Attribute Autosave Disabled.\n");
   }
   
   // for everything else read values and thresholds are needed
-  if (ataReadSmartValues(fd, &smartval))
+  if (ataReadSmartValues(fd, &smartval)){
     printf("Smartctl: SMART Values Read Failed.\n\n");
-  if (ataReadSmartThresholds(fd, &smartthres))
+    returnval|=FAILSMART;
+  }
+  if (ataReadSmartThresholds(fd, &smartthres)){
     printf("Smartctl: SMART Thresholds Read Failed.\n\n");
-  
+    returnval|=FAILSMART;
+  }
+
   // Enable/Disable Off-line testing
   if (smartautoofflineenable){
-    if (!isSupportAutomaticTimer (smartval)){
+    if (!isSupportAutomaticTimer(smartval)){
       printf("Device does not support SMART Automatic Timers.\n\n");
     }
-    if (ataEnableAutoOffline (fd))
+    if (ataEnableAutoOffline(fd)){
       printf( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf ("SMART Automatic Offline Testing Enabled every four hours.\n");
   }
   if (smartautoofflinedisable){
-    if (!isSupportAutomaticTimer (smartval))
-      printf("Device does not support SMART Automatic Timers.\n\n");		
-    if (ataDisableAutoOffline (fd))
+    if (!isSupportAutomaticTimer(smartval)){
+      printf("Device does not support SMART Automatic Timers.\n\n");
+    }
+    if (ataDisableAutoOffline(fd)){
       printf("Smartctl: SMART Disable Automatic Offline Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf("SMART Automatic Offline Testing Disabled.\n");
   }
@@ -936,25 +955,24 @@ void ataPrintMain (int fd){
       printf("SMART overall-health self-assessment test result: FAILED!\n"
 	     "Drive failure expected in less than 24 hours. SAVE ALL DATA\n");
       if (ataCheckSmart(smartval, smartthres,1)){
-	printf("SMART prefailure attributes shown below are below threshold.\n"
-	       "Use -%c option to investigate\n",SMARTVENDORATTRIB);
-
-	printf("Below is a list of failing attributes.\nUse -%c option to investigate.\n",
-	       SMARTVENDORATTRIB);
+	returnval|=FAILATTR;
+	printf("Failed attributes:\n");
 	PrintSmartAttribWithThres(smartval, smartthres,1);
-	printf("\n");
       }
-      else
-	printf("Unable to confirm any failing attributes.\n");
+      else {
+	printf("No failing attributes found.\n");
+      }      
+      printf("\n");
+      returnval|=FAILSTATUS;
     }
     else {
       printf("SMART overall-health self-assessment test result: PASSED\n");
       if (ataCheckSmart(smartval, smartthres,0)){
-	printf("Note: SMART attributes shown below are below threshold now or were in the past.\n"
-	       "Use -%c option to investigate\n",SMARTVENDORATTRIB);
+	printf("Marginal attributes:\n");
 	PrintSmartAttribWithThres(smartval, smartthres,2);
-	printf("\n");
+	returnval|=FAILAGE;
       }
+      printf("\n");
     }
   }
   
@@ -965,26 +983,34 @@ void ataPrintMain (int fd){
   // Print vendor-specific attributes
   if (smartvendorattrib)
     PrintSmartAttribWithThres(smartval, smartthres,0);
-	
+  
   // Print SMART error log
   if (smarterrorlog){
-    if (!isSmartErrorLogCapable(smartval))
+    if (!isSmartErrorLogCapable(smartval)){
       printf("Device does not support Error Logging\n");
+      returnval|=FAILSMART;
+    }
     else {
-      if (ataReadErrorLog(fd, &smarterror))
+      if (ataReadErrorLog(fd, &smarterror)){
 	printf("Smartctl: SMART Errorlog Read Failed\n");
+	returnval|=FAILSMART;
+      }
       else
 	ataPrintSmartErrorlog(smarterror);
     }
   }
-
+  
   // Print SMART self-test log
   if (smartselftestlog){
-    if (!isSmartErrorLogCapable(smartval))
+    if (!isSmartErrorLogCapable(smartval)){
       printf("Device does not support Self Test Logging\n");
+      returnval|=FAILSMART;
+    }
     else {
-      if(ataReadSelfTestLog(fd, &smartselftest))
+      if(ataReadSelfTestLog(fd, &smartselftest)){
 	printf("Smartctl: SMART Self Test Log Read Failed\n");
+	returnval|=FAILSMART;
+      }
       else
 	ataPrintSmartSelfTestlog(smartselftest); 
     } 
@@ -992,24 +1018,23 @@ void ataPrintMain (int fd){
   
   // START OF THE TESTING SECTION OF THE CODE.  IF NO TESTING, RETURN
   if (testcase==-1)
-    return;
+    return returnval;
 
   printf("\n=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
 
-  
   // if doing a self-test, be sure it's supported by the hardware
   if (testcase==OFFLINE_FULL_SCAN &&  !isSupportExecuteOfflineImmediate(smartval)){
     printf("ERROR: device does not support Execute Off-Line Immediate function.\n\n");
-    exit(-1);
+    return returnval|=FAILSMART;
   }
   else if (!isSupportSelfTest(smartval)){
     printf ("ERROR: device does not support Self-Test functions.\n\n");
-    exit(-1);
+    return returnval|=FAILSMART;
   }
   
   // Now do the test
   if (ataSmartTest(fd, testcase))
-    exit(-1);
+    return returnval|=FAILSMART;
   
   // Tell user how long test will take to complete  
   if ((timewait=TestTime(smartval,testcase))){ 
@@ -1019,5 +1044,5 @@ void ataPrintMain (int fd){
     if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST)
       printf ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT);	
   }    
-  return;
+  return returnval;
 }
diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp
index c856e73aa..b0a492e29 100644
--- a/sm5/ataprint.cpp
+++ b/sm5/ataprint.cpp
@@ -28,7 +28,7 @@
 #include "smartctl.h"
 #include "extern.h"
 
-const char *CVSid4="$Id: ataprint.cpp,v 1.22 2002/10/22 15:37:15 ballen4705 Exp $\n"
+const char *CVSid4="$Id: ataprint.cpp,v 1.23 2002/10/22 16:49:16 ballen4705 Exp $\n"
 	           "\t" CVSID2 "\t" CVSID3 "\t" CVSID6 ;
 
 // Function for printing ASCII byte-swapped strings, skipping white
@@ -401,7 +401,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values data,
       
       // is this currently failed, or has it ever failed?
       if (failednow)
-	status="FAILED NOW!";
+	status="FAILED_NOW!";
       else if (failedever)
 	status="In_the_past";
       else
@@ -412,7 +412,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values data,
       
       // printing line for each valid attribute
       type=disk->status.flag.prefailure?"Pre-fail":"Old_age";
-      printf(" 0x%04x   %.3i   %.3i   %.3i    %-9s%-13s", 
+      printf(" 0x%04x   %.3i   %.3i   %.3i    %-9s%-12s", 
 	     disk->status.all, disk->current, disk->worst,
 	     thre->threshold, type, status);
       
@@ -819,13 +819,15 @@ struct ata_smart_thresholds smartthres;
 struct ata_smart_errorlog smarterror;
 struct ata_smart_selftestlog smartselftest;
 
-void ataPrintMain (int fd){
+int ataPrintMain (int fd){
   int timewait,code;
+  int returnval=0;
   
   // Start by getting Drive ID information.  We need this, to know if SMART is supported.
   if (ataReadHDIdentity(fd,&drive)){
     printf("Smartctl: Hard Drive Read Identity Failed\n\n");
-  }
+    returnval|=FAILID;
+}
   
   // Print most drive identity information if requested
   if (driveinfo){
@@ -839,7 +841,7 @@ void ataPrintMain (int fd){
     printf("                  Checking to be sure by trying SMART ENABLE command.\n");
     if (ataEnableSmart(fd)){
       printf("                  No SMART functionality found. Sorry.\n");
-      exit(0);
+      return returnval|FAILSMART;
     }
     else
       printf("                  SMART appears to work.  Continuing.\n"); 
@@ -864,6 +866,7 @@ void ataPrintMain (int fd){
   if (smartenable){
     if (ataEnableSmart(fd)) {
       printf("Smartctl: SMART Enable Failed.\n\n");
+      returnval|=FAILSMART;
     }
     else
       printf("SMART Enabled.\n");
@@ -872,56 +875,72 @@ void ataPrintMain (int fd){
   // From here on, every command requires that SMART be enabled...
   if (!ataDoesSmartWork(fd)) {
     printf("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE );
-    exit(0);
+    return returnval;
   }
   
   // Turn off SMART on device
   if (smartdisable){    
     if (ataDisableSmart(fd)) {
       printf( "Smartctl: SMART Disable Failed.\n\n");
+      returnval|=FAILSMART;
     }
     printf("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE);
-    exit (0);		
+    return returnval;		
   }
   
   // Let's ALWAYS issue this command to get the SMART status
   code=ataSmartStatus2(fd);
-
+  if (code==-1)
+    returnval|=FAILSMART;
+  
   // Enable/Disable Auto-save attributes
   if (smartautosaveenable){
-    if (ataEnableAutoSave(fd))
+    if (ataEnableAutoSave(fd)){
       printf( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf("SMART Attribute Autosave Enabled.\n");
   }
   if (smartautosavedisable){
-    if (ataDisableAutoSave(fd))
+    if (ataDisableAutoSave(fd)){
       printf( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf("SMART Attribute Autosave Disabled.\n");
   }
   
   // for everything else read values and thresholds are needed
-  if (ataReadSmartValues(fd, &smartval))
+  if (ataReadSmartValues(fd, &smartval)){
     printf("Smartctl: SMART Values Read Failed.\n\n");
-  if (ataReadSmartThresholds(fd, &smartthres))
+    returnval|=FAILSMART;
+  }
+  if (ataReadSmartThresholds(fd, &smartthres)){
     printf("Smartctl: SMART Thresholds Read Failed.\n\n");
-  
+    returnval|=FAILSMART;
+  }
+
   // Enable/Disable Off-line testing
   if (smartautoofflineenable){
-    if (!isSupportAutomaticTimer (smartval)){
+    if (!isSupportAutomaticTimer(smartval)){
       printf("Device does not support SMART Automatic Timers.\n\n");
     }
-    if (ataEnableAutoOffline (fd))
+    if (ataEnableAutoOffline(fd)){
       printf( "Smartctl: SMART Enable Automatic Offline Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf ("SMART Automatic Offline Testing Enabled every four hours.\n");
   }
   if (smartautoofflinedisable){
-    if (!isSupportAutomaticTimer (smartval))
-      printf("Device does not support SMART Automatic Timers.\n\n");		
-    if (ataDisableAutoOffline (fd))
+    if (!isSupportAutomaticTimer(smartval)){
+      printf("Device does not support SMART Automatic Timers.\n\n");
+    }
+    if (ataDisableAutoOffline(fd)){
       printf("Smartctl: SMART Disable Automatic Offline Failed.\n\n");
+      returnval|=FAILSMART;
+    }
     else
       printf("SMART Automatic Offline Testing Disabled.\n");
   }
@@ -936,25 +955,24 @@ void ataPrintMain (int fd){
       printf("SMART overall-health self-assessment test result: FAILED!\n"
 	     "Drive failure expected in less than 24 hours. SAVE ALL DATA\n");
       if (ataCheckSmart(smartval, smartthres,1)){
-	printf("SMART prefailure attributes shown below are below threshold.\n"
-	       "Use -%c option to investigate\n",SMARTVENDORATTRIB);
-
-	printf("Below is a list of failing attributes.\nUse -%c option to investigate.\n",
-	       SMARTVENDORATTRIB);
+	returnval|=FAILATTR;
+	printf("Failed attributes:\n");
 	PrintSmartAttribWithThres(smartval, smartthres,1);
-	printf("\n");
       }
-      else
-	printf("Unable to confirm any failing attributes.\n");
+      else {
+	printf("No failing attributes found.\n");
+      }      
+      printf("\n");
+      returnval|=FAILSTATUS;
     }
     else {
       printf("SMART overall-health self-assessment test result: PASSED\n");
       if (ataCheckSmart(smartval, smartthres,0)){
-	printf("Note: SMART attributes shown below are below threshold now or were in the past.\n"
-	       "Use -%c option to investigate\n",SMARTVENDORATTRIB);
+	printf("Marginal attributes:\n");
 	PrintSmartAttribWithThres(smartval, smartthres,2);
-	printf("\n");
+	returnval|=FAILAGE;
       }
+      printf("\n");
     }
   }
   
@@ -965,26 +983,34 @@ void ataPrintMain (int fd){
   // Print vendor-specific attributes
   if (smartvendorattrib)
     PrintSmartAttribWithThres(smartval, smartthres,0);
-	
+  
   // Print SMART error log
   if (smarterrorlog){
-    if (!isSmartErrorLogCapable(smartval))
+    if (!isSmartErrorLogCapable(smartval)){
       printf("Device does not support Error Logging\n");
+      returnval|=FAILSMART;
+    }
     else {
-      if (ataReadErrorLog(fd, &smarterror))
+      if (ataReadErrorLog(fd, &smarterror)){
 	printf("Smartctl: SMART Errorlog Read Failed\n");
+	returnval|=FAILSMART;
+      }
       else
 	ataPrintSmartErrorlog(smarterror);
     }
   }
-
+  
   // Print SMART self-test log
   if (smartselftestlog){
-    if (!isSmartErrorLogCapable(smartval))
+    if (!isSmartErrorLogCapable(smartval)){
       printf("Device does not support Self Test Logging\n");
+      returnval|=FAILSMART;
+    }
     else {
-      if(ataReadSelfTestLog(fd, &smartselftest))
+      if(ataReadSelfTestLog(fd, &smartselftest)){
 	printf("Smartctl: SMART Self Test Log Read Failed\n");
+	returnval|=FAILSMART;
+      }
       else
 	ataPrintSmartSelfTestlog(smartselftest); 
     } 
@@ -992,24 +1018,23 @@ void ataPrintMain (int fd){
   
   // START OF THE TESTING SECTION OF THE CODE.  IF NO TESTING, RETURN
   if (testcase==-1)
-    return;
+    return returnval;
 
   printf("\n=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n");
 
-  
   // if doing a self-test, be sure it's supported by the hardware
   if (testcase==OFFLINE_FULL_SCAN &&  !isSupportExecuteOfflineImmediate(smartval)){
     printf("ERROR: device does not support Execute Off-Line Immediate function.\n\n");
-    exit(-1);
+    return returnval|=FAILSMART;
   }
   else if (!isSupportSelfTest(smartval)){
     printf ("ERROR: device does not support Self-Test functions.\n\n");
-    exit(-1);
+    return returnval|=FAILSMART;
   }
   
   // Now do the test
   if (ataSmartTest(fd, testcase))
-    exit(-1);
+    return returnval|=FAILSMART;
   
   // Tell user how long test will take to complete  
   if ((timewait=TestTime(smartval,testcase))){ 
@@ -1019,5 +1044,5 @@ void ataPrintMain (int fd){
     if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST)
       printf ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT);	
   }    
-  return;
+  return returnval;
 }
diff --git a/sm5/ataprint.h b/sm5/ataprint.h
index f76076f8c..09cfaa87b 100644
--- a/sm5/ataprint.h
+++ b/sm5/ataprint.h
@@ -26,7 +26,7 @@
 #define _SMART_PRINT_H_
 
 #ifndef CVSID2
-#define CVSID2 "$Id: ataprint.h,v 1.8 2002/10/22 11:40:52 ballen4705 Exp $\n"
+#define CVSID2 "$Id: ataprint.h,v 1.9 2002/10/22 16:49:16 ballen4705 Exp $\n"
 #endif
 
 #include <stdio.h>
@@ -58,6 +58,6 @@ void ataPseudoCheckSmart (struct ata_smart_values ,
 /* prints 20 character string */
 void ataPrintSmartAttribName (unsigned char id);
 
-void ataPrintMain ( int fd );
+int ataPrintMain ( int fd );
 
 #endif
diff --git a/sm5/smartctl.8 b/sm5/smartctl.8
index 51bdca369..a5659bae1 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.13 2002/10/22 12:53:20 ballen4705 Exp $
+\# $Id: smartctl.8,v 1.14 2002/10/22 16:49:16 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,7 +15,7 @@
 \# 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/10/22 12:53:20 $" "smartmontools-5.0"
+.TH SMARTCTL 8  "$Date: 2002/10/22 16:49:16 $" "smartmontools-5.0"
 .SH NAME
 smartctl \- S.M.A.R.T. control utility 
 .SH SYNOPSIS
@@ -315,6 +315,18 @@ the S.M.A.R.T. error log., which can be seen with the '\-l' option.
 shows the vendor attributes, when the disk stores its power-on time
 internally in minutes rather than hours.
 
+.PP
+.SH RETURN VALUES
+
+The return values of smartctl are defined by a bitmask.  For the
+moment this only works on ATA disks.  The different bits in the return
+value are as follows.  Bit 0: Command line did not parse.  Bit 1:
+Device open failed.  Bit 2: SMART command to disk failed.  Bit 3:
+SMART status check returned "DISK FAILING".  Bit 4: SMART status check
+returned "DISK OK" but we found prefail attributes <= threshold.  Bit
+5: SMART status check returned "DISK OK" but we found that some (usage
+or prefail) attributes have been <= threshold at some time in the
+past. Bit 6: Unable to get Device IDENTITY information. 
 .PP
 .SH AUTHOR
 Bruce Allen
@@ -389,4 +401,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.13 2002/10/22 12:53:20 ballen4705 Exp $
+$Id: smartctl.8,v 1.14 2002/10/22 16:49:16 ballen4705 Exp $
diff --git a/sm5/smartctl.c b/sm5/smartctl.c
index 9652f4042..3e17e6970 100644
--- a/sm5/smartctl.c
+++ b/sm5/smartctl.c
@@ -37,7 +37,7 @@
 #include "scsiprint.h"
 
 extern const char *CVSid1, *CVSid2, *CVSid4, *CVSid5; 
-const char* CVSid6="$Id: smartctl.c,v 1.13 2002/10/22 09:50:54 ballen4705 Exp $\n"
+const char* CVSid6="$Id: smartctl.c,v 1.14 2002/10/22 16:49:16 ballen4705 Exp $\n"
 "\t" CVSID1 "\t" CVSID2 "\t" CVSID4 "\t" CVSID5 "\t" CVSID6 ;
 
 unsigned char driveinfo               = FALSE;
@@ -201,7 +201,7 @@ void ParseOpts (int argc, char** argv){
       break;
     default:
       Usage();
-      exit (-1);	
+      exit(FAILCMD);	
     }
     
     if ( (smartexeoffimmediate + smartshortselftest +
@@ -209,7 +209,7 @@ void ParseOpts (int argc, char** argv){
 	  smartextendcapselftest +smartselftestabort ) > 1){
       Usage();
       printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n");
-      exit(-1);
+      exit(FAILCMD);
     }
   }
 }
@@ -217,14 +217,14 @@ void ParseOpts (int argc, char** argv){
 /* Main Program */
 
 int main (int argc, char **argv){
-  int fd;
+  int fd,retval=0;
   char *device;
   
   printf("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION);
   printf("Home page of smartctl is %s\n",PROJECTHOME);
   
   // Part input arguments
-  ParseOpts (argc,argv);
+  ParseOpts(argc,argv);
   
   // Print Copyright/License info if needed
   if (printcopyleft){
@@ -234,29 +234,31 @@ int main (int argc, char **argv){
     printf("See http://www.gnu.org for further details.\n\n");
     printf("CVS version IDs of files used to build this code are:\n%s%s%s%s%s",CVSid1,CVSid2,CVSid4,CVSid5,CVSid6);
     if (argc==2)
-      exit(0);
- }
-
+      return 0;
+  }
+  
   // Further argument checking
-  if ( argc != 3 ){
+  if (argc != 3){
     Usage();
-    exit (-1);
+    return FAILCMD;
   }
-    
+  
   // open device - read-only mode is enough to issue needed commands
-  fd = open ( device=argv[2], O_RDONLY );
+  fd = open(device=argv[2], O_RDONLY);
   
-  if ( fd < 0) {
-    perror ( "Device open failed");
-    exit(-1);
+  if (fd< 0) {
+    perror ("Smartctl device open failed:");
+    return FAILDEV;
   }
   
-  if ( device[5] == 'h')
-    ataPrintMain (fd );
+  if (device[5] == 'h')
+    retval=ataPrintMain(fd );
   else if (device[5] == 's')
     scsiPrintMain (fd);
-  else 
+  else {
     Usage();
-  
-  return 0;
+    return FAILCMD;
+  }
+
+  return retval;
 }
diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp
index f57b2fba3..467badd2b 100644
--- a/sm5/smartctl.cpp
+++ b/sm5/smartctl.cpp
@@ -37,7 +37,7 @@
 #include "scsiprint.h"
 
 extern const char *CVSid1, *CVSid2, *CVSid4, *CVSid5; 
-const char* CVSid6="$Id: smartctl.cpp,v 1.13 2002/10/22 09:50:54 ballen4705 Exp $\n"
+const char* CVSid6="$Id: smartctl.cpp,v 1.14 2002/10/22 16:49:16 ballen4705 Exp $\n"
 "\t" CVSID1 "\t" CVSID2 "\t" CVSID4 "\t" CVSID5 "\t" CVSID6 ;
 
 unsigned char driveinfo               = FALSE;
@@ -201,7 +201,7 @@ void ParseOpts (int argc, char** argv){
       break;
     default:
       Usage();
-      exit (-1);	
+      exit(FAILCMD);	
     }
     
     if ( (smartexeoffimmediate + smartshortselftest +
@@ -209,7 +209,7 @@ void ParseOpts (int argc, char** argv){
 	  smartextendcapselftest +smartselftestabort ) > 1){
       Usage();
       printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n");
-      exit(-1);
+      exit(FAILCMD);
     }
   }
 }
@@ -217,14 +217,14 @@ void ParseOpts (int argc, char** argv){
 /* Main Program */
 
 int main (int argc, char **argv){
-  int fd;
+  int fd,retval=0;
   char *device;
   
   printf("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION);
   printf("Home page of smartctl is %s\n",PROJECTHOME);
   
   // Part input arguments
-  ParseOpts (argc,argv);
+  ParseOpts(argc,argv);
   
   // Print Copyright/License info if needed
   if (printcopyleft){
@@ -234,29 +234,31 @@ int main (int argc, char **argv){
     printf("See http://www.gnu.org for further details.\n\n");
     printf("CVS version IDs of files used to build this code are:\n%s%s%s%s%s",CVSid1,CVSid2,CVSid4,CVSid5,CVSid6);
     if (argc==2)
-      exit(0);
- }
-
+      return 0;
+  }
+  
   // Further argument checking
-  if ( argc != 3 ){
+  if (argc != 3){
     Usage();
-    exit (-1);
+    return FAILCMD;
   }
-    
+  
   // open device - read-only mode is enough to issue needed commands
-  fd = open ( device=argv[2], O_RDONLY );
+  fd = open(device=argv[2], O_RDONLY);
   
-  if ( fd < 0) {
-    perror ( "Device open failed");
-    exit(-1);
+  if (fd< 0) {
+    perror ("Smartctl device open failed:");
+    return FAILDEV;
   }
   
-  if ( device[5] == 'h')
-    ataPrintMain (fd );
+  if (device[5] == 'h')
+    retval=ataPrintMain(fd );
   else if (device[5] == 's')
     scsiPrintMain (fd);
-  else 
+  else {
     Usage();
-  
-  return 0;
+    return FAILCMD;
+  }
+
+  return retval;
 }
diff --git a/sm5/smartctl.h b/sm5/smartctl.h
index d8ec2f2b2..41d7ead97 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.7 2002/10/22 09:44:55 ballen4705 Exp $\n"
+#define CVSID6 "$Id: smartctl.h,v 1.8 2002/10/22 16:49:16 ballen4705 Exp $\n"
 #endif
 
 /* Defines for command line options */ 
@@ -57,4 +57,28 @@
 #define TRUE 0x01
 #define FALSE 0x00
 
+// Return codes (bitmask)
+
+// command line did not parse
+#define FAILCMD   (0x01<<0)
+
+// device open failed
+#define FAILDEV   (0x01<<1)
+        
+// smart command failed
+#define FAILSMART (0x01<<2)
+
+// SMART STATUS returned FAILURE
+#define FAILSTATUS (0x01<<3)
+
+// Attributes found <= threshold with prefail=1
+#define FAILATTR (0x01<<4)
+
+// SMART STATUS returned GOOD but age attributes failed or prefail
+// attributes have failed in the past
+#define FAILAGE (0x01<<5)
+
+// Device ID failed
+#define FAILID (0x01<<6)
+
 #endif
-- 
GitLab