diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG index 0a7c02ab00e97034f92933751c2c5c7664d07333..749c459ef112c5e1470375e14d4ec6355cc35fa3 100644 --- a/sm5/CHANGELOG +++ b/sm5/CHANGELOG @@ -1,6 +1,6 @@ CHANGELOG for smartmontools -$Id: CHANGELOG,v 1.14 2002/10/22 16:49:15 ballen4705 Exp $ +$Id: CHANGELOG,v 1.15 2002/10/23 12:24:23 ballen4705 Exp $ Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> @@ -29,9 +29,25 @@ NOTES FOR NEXT RELEASE: smartmontools-5.0-11 + Minor change in philosophy: if a SMART command fails or the device + appears incapable of a SMART command that the user has asked for, + complain by printing an error message, but go ahead and try + anyway. Since unimplemented SMART commands should just return an + error but not cause disk problems, this should't cause any + difficulty. + + Added two new flags: q and Q. q is quiet mode - only print: For + the -l option, errors recorded in the SMART error log; For the -L + option, errors recorded in the device self-test log; For the -c + SMART "disk failing" status or device attributes (pre-failure or + usage) which failed either now or in the past; For the -v option + device attributes (pre-failure or usage) which failed either now + or in the past. Q is Very Quiet mode: Print no ouput. The only + way to learn about what was found is to use the exit status of + smartctl. + 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. + for the values, and the man page for documentation. The SMART status check now uses the correct ATA call. If failure is detected we search through attributes to list the failed ones. @@ -43,7 +59,7 @@ smartmontools-5.0-11 attribute has currently failed or has ever failed. -p option now prints out license info and CVS strings for all - modules in the code. + modules in the code, nicely formatted. Previous versions of this code (and Smartsuite) only generate SMART failure errors if the value of an attribute is below the diff --git a/sm5/README b/sm5/README index 5c58b41aacb087e008bb5cfa278b224d2a6fe31a..711a3ccacea74118de7bf55aa950140bc23ca1b2 100644 --- a/sm5/README +++ b/sm5/README @@ -110,6 +110,8 @@ v Prints only the vendor specific S.M.A.R.T. attributes & thresholds l Prints only the S.M.A.R.T. error log L Prints only the S.M.A.R.T. self-test log a Prints all parameters for i,c,g,v,t,l,L +q Quiet operation; only show errors in error log, or self-test log, or smart status +Q Very quiet operation: only output is via the returned status Modify Display for Vendor-specific S.M.A.R.T. Raw Attribute Data: m Converts Raw Attribute-009 from minutes to hours (Hitachi) @@ -183,4 +185,4 @@ Fax: (408) 867-2115 E-Mail: 250-1752@mcimail.com. -$Id: README,v 1.7 2002/10/16 18:54:06 ballen4705 Exp $ +$Id: README,v 1.8 2002/10/23 12:24:23 ballen4705 Exp $ diff --git a/sm5/atacmds.c b/sm5/atacmds.c index f686a5741ebb97fc345a2fc358352d88d1ef1ee0..52706b833185f3b6554db1a3ba7b292e3fcebbd8 100644 --- a/sm5/atacmds.c +++ b/sm5/atacmds.c @@ -30,7 +30,7 @@ #include <errno.h> #include "atacmds.h" -const char *CVSid1="$Id: atacmds.c,v 1.18 2002/10/22 14:57:43 ballen4705 Exp $\n" "\t" CVSID1 ; +const char *CVSid1="$Id: atacmds.c,v 1.19 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" 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 @@ -121,7 +121,7 @@ const int actual_ver[] = { // Used to warn users about invalid checksums. However we will not // abort on invalid checksums. void checksumwarning(const char *string){ - printf("Warning! %s error: invalid checksum.\n",string); + pout("Warning! %s error: invalid checksum.\n",string); fprintf(stderr,"Warning! %s error: invalid checksum.\n",string); syslog(LOG_INFO,"Warning! %s error: invalid checksum.\n",string); return; @@ -419,7 +419,7 @@ int ataEnableAutoSave(int device){ unsigned char parms[4] = {WIN_SMART, 241, SMART_AUTOSAVE, 0}; if (ioctl(device, HDIO_DRIVE_CMD, parms)){ - perror ("SMART Enable Auto-save failed"); + perror("SMART Enable Auto-save failed"); return -1; } return 0; @@ -429,7 +429,7 @@ int ataDisableAutoSave(int device){ unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTOSAVE, 0}; if (ioctl(device, HDIO_DRIVE_CMD, parms)){ - perror ("SMART Disable Auto-save failed"); + perror("SMART Disable Auto-save failed"); return -1; } return 0; @@ -453,7 +453,7 @@ int ataDisableAutoOffline (int device ){ unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTO_OFFLINE, 0}; if (ioctl(device , HDIO_DRIVE_CMD, parms)){ - perror ("SMART Disable Automatic Offline failed"); + perror("SMART Disable Automatic Offline failed"); return -1; } return 0; @@ -504,7 +504,7 @@ int ataSmartStatus2(int device){ parms[5]=normal_cyl_hi; if (ioctl(device,HDIO_DRIVE_TASK,parms)){ - perror ("SMART Status command failed."); + perror("SMART Status command failed"); return -1; } @@ -517,16 +517,16 @@ int ataSmartStatus2(int device){ return 1; // We haven't gotten output that makes sense; print out some debugging info - perror("SMART Status command failed:"); - printf("Please get assistance from %s\n",PROJECTHOME); - printf("Register values returned from SMART Status command are:\n"); - printf("CMD=0x%02x\n",parms[0]); - printf("FR =0x%02x\n",parms[1]); - printf("NS =0x%02x\n",parms[2]); - printf("SC =0x%02x\n",parms[3]); - printf("CL =0x%02x\n",parms[4]); - printf("CH =0x%02x\n",parms[5]); - printf("SEL=0x%02x\n",parms[6]); + perror("SMART Status command failed"); + pout("Please get assistance from %s\n",PROJECTHOME); + pout("Register values returned from SMART Status command are:\n"); + pout("CMD=0x%02x\n",parms[0]); + pout("FR =0x%02x\n",parms[1]); + pout("NS =0x%02x\n",parms[2]); + pout("SC =0x%02x\n",parms[3]); + pout("CL =0x%02x\n",parms[4]); + pout("CH =0x%02x\n",parms[5]); + pout("SEL=0x%02x\n",parms[6]); return -1; } @@ -557,23 +557,23 @@ int ataSmartTest(int device, int testtype){ sprintf(cmdmsg,"Abort SMART off-line mode self-test routine"); else sprintf(cmdmsg,"Execute SMART %s routine immediately in %s mode",type,captive); - printf("Sending command: \"%s\".\n",cmdmsg); + pout("Sending command: \"%s\".\n",cmdmsg); // Now send the command to test errornum=ioctl(device, HDIO_DRIVE_CMD, parms); if (!(errornum && errno==EIO && (testtype=SHORT_CAPTIVE_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST))){ char errormsg[128]; - sprintf(errormsg,"Command \"%s\" failed.",cmdmsg); - perror (errormsg); + sprintf(errormsg,"Command \"%s\" failed",cmdmsg); + perror(errormsg); fprintf(stderr,"\n"); return -1; } // Since the command succeeded, tell user if (testtype==ABORT_SELF_TEST) - printf("Self-testing aborted!\n"); + pout("Self-testing aborted!\n"); else - printf("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg); + pout("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg); return 0; } diff --git a/sm5/atacmds.cpp b/sm5/atacmds.cpp index ed64f54862bebde0e59729ac3dac12aa5a15d676..98eabac4dafbc7161af9df09aca04d6d4756b4b6 100644 --- a/sm5/atacmds.cpp +++ b/sm5/atacmds.cpp @@ -30,7 +30,7 @@ #include <errno.h> #include "atacmds.h" -const char *CVSid1="$Id: atacmds.cpp,v 1.18 2002/10/22 14:57:43 ballen4705 Exp $\n" "\t" CVSID1 ; +const char *CVSid1="$Id: atacmds.cpp,v 1.19 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" 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 @@ -121,7 +121,7 @@ const int actual_ver[] = { // Used to warn users about invalid checksums. However we will not // abort on invalid checksums. void checksumwarning(const char *string){ - printf("Warning! %s error: invalid checksum.\n",string); + pout("Warning! %s error: invalid checksum.\n",string); fprintf(stderr,"Warning! %s error: invalid checksum.\n",string); syslog(LOG_INFO,"Warning! %s error: invalid checksum.\n",string); return; @@ -419,7 +419,7 @@ int ataEnableAutoSave(int device){ unsigned char parms[4] = {WIN_SMART, 241, SMART_AUTOSAVE, 0}; if (ioctl(device, HDIO_DRIVE_CMD, parms)){ - perror ("SMART Enable Auto-save failed"); + perror("SMART Enable Auto-save failed"); return -1; } return 0; @@ -429,7 +429,7 @@ int ataDisableAutoSave(int device){ unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTOSAVE, 0}; if (ioctl(device, HDIO_DRIVE_CMD, parms)){ - perror ("SMART Disable Auto-save failed"); + perror("SMART Disable Auto-save failed"); return -1; } return 0; @@ -453,7 +453,7 @@ int ataDisableAutoOffline (int device ){ unsigned char parms[4] = {WIN_SMART, 0, SMART_AUTO_OFFLINE, 0}; if (ioctl(device , HDIO_DRIVE_CMD, parms)){ - perror ("SMART Disable Automatic Offline failed"); + perror("SMART Disable Automatic Offline failed"); return -1; } return 0; @@ -504,7 +504,7 @@ int ataSmartStatus2(int device){ parms[5]=normal_cyl_hi; if (ioctl(device,HDIO_DRIVE_TASK,parms)){ - perror ("SMART Status command failed."); + perror("SMART Status command failed"); return -1; } @@ -517,16 +517,16 @@ int ataSmartStatus2(int device){ return 1; // We haven't gotten output that makes sense; print out some debugging info - perror("SMART Status command failed:"); - printf("Please get assistance from %s\n",PROJECTHOME); - printf("Register values returned from SMART Status command are:\n"); - printf("CMD=0x%02x\n",parms[0]); - printf("FR =0x%02x\n",parms[1]); - printf("NS =0x%02x\n",parms[2]); - printf("SC =0x%02x\n",parms[3]); - printf("CL =0x%02x\n",parms[4]); - printf("CH =0x%02x\n",parms[5]); - printf("SEL=0x%02x\n",parms[6]); + perror("SMART Status command failed"); + pout("Please get assistance from %s\n",PROJECTHOME); + pout("Register values returned from SMART Status command are:\n"); + pout("CMD=0x%02x\n",parms[0]); + pout("FR =0x%02x\n",parms[1]); + pout("NS =0x%02x\n",parms[2]); + pout("SC =0x%02x\n",parms[3]); + pout("CL =0x%02x\n",parms[4]); + pout("CH =0x%02x\n",parms[5]); + pout("SEL=0x%02x\n",parms[6]); return -1; } @@ -557,23 +557,23 @@ int ataSmartTest(int device, int testtype){ sprintf(cmdmsg,"Abort SMART off-line mode self-test routine"); else sprintf(cmdmsg,"Execute SMART %s routine immediately in %s mode",type,captive); - printf("Sending command: \"%s\".\n",cmdmsg); + pout("Sending command: \"%s\".\n",cmdmsg); // Now send the command to test errornum=ioctl(device, HDIO_DRIVE_CMD, parms); if (!(errornum && errno==EIO && (testtype=SHORT_CAPTIVE_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST))){ char errormsg[128]; - sprintf(errormsg,"Command \"%s\" failed.",cmdmsg); - perror (errormsg); + sprintf(errormsg,"Command \"%s\" failed",cmdmsg); + perror(errormsg); fprintf(stderr,"\n"); return -1; } // Since the command succeeded, tell user if (testtype==ABORT_SELF_TEST) - printf("Self-testing aborted!\n"); + pout("Self-testing aborted!\n"); else - printf("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg); + pout("Drive command \"%s\" successful.\nTesting has begun.\n",cmdmsg); return 0; } diff --git a/sm5/atacmds.h b/sm5/atacmds.h index c5a9c6c4e697ba928e088a07f3a4b76c450e5cb4..8e3a612a7a527607cfb7fc0500fa6491df02b786 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.16 2002/10/22 14:57:43 ballen4705 Exp $\n" +#define CVSID1 "$Id: atacmds.h,v 1.17 2002/10/23 12:24:24 ballen4705 Exp $\n" #endif // These are the major and minor versions for smartd and smartctl @@ -373,4 +373,11 @@ int ataSmartTest(int device, int testtype); int TestTime(struct ata_smart_values data,int testtype); +// like printf() except that we can control it better.... +void pout(char *fmt, ...); + +// MACROS to control printing behavior +#define QUIETON {if (quietmode) veryquietmode=0;} +#define QUIETOFF {if (quietmode && !veryquietmode) veryquietmode=1;} + #endif /* _ATACMDS_H_ */ diff --git a/sm5/ataprint.c b/sm5/ataprint.c index d0148f8584fdc51fc37369af61895ef3573833a6..38e9d60a2d65088d04f241b66a02bda1a0f31bf1 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.24 2002/10/22 20:35:42 ballen4705 Exp $\n" +const char *CVSid4="$Id: ataprint.c,v 1.25 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" CVSID2 "\t" CVSID3 "\t" CVSID6 ; // Function for printing ASCII byte-swapped strings, skipping white @@ -51,9 +51,9 @@ void printswap(char *in, unsigned int n){ // and do the printing starting from first non-white space if (n-i) - printf("%.*s\n",(int)(n-i),out+i); + pout("%.*s\n",(int)(n-i),out+i); else - printf("[No Information Found]\n"); + pout("[No Information Found]\n"); return; } @@ -65,13 +65,13 @@ void ataPrintDriveInfo (struct hd_driveid drive){ char unknown[64]; // print out model, serial # and firmware versions (byte-swap ASCI strings) - printf("Device Model: "); + pout("Device Model: "); printswap(drive.model,40); - printf("Serial Number: "); + pout("Serial Number: "); printswap(drive.serial_no,20); - printf("Firmware Version: "); + pout("Firmware Version: "); printswap(drive.fw_rev,8); // now get ATA version info @@ -90,14 +90,14 @@ void ataPrintDriveInfo (struct hd_driveid drive){ // http://www.t13.org/project/d2008r6.pdf to see this. So it's not // enough to check if we are ATA-3. Version=-3 indicates ATA-3 // BEFORE Revision 3. - printf("ATA Version is: %i\n",version>0?version:-1*version); - printf("ATA Standard is: %s\n",description); + pout("ATA Version is: %i\n",version>0?version:-1*version); + pout("ATA Standard is: %s\n",description); if (version>=3) return; - printf("SMART is only available in ATA Version 3 Revision 3 or greater.\n"); - printf("We will try to proceed in spite of this.\n"); + pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n"); + pout("We will try to proceed in spite of this.\n"); return; } @@ -107,48 +107,48 @@ void ataPrintDriveInfo (struct hd_driveid drive){ void PrintSmartOfflineStatus ( struct ata_smart_values data) { - printf ("Off-line data collection status: "); + pout ("Off-line data collection status: "); switch (data.offline_data_collection_status){ case 0x00: case 0x80: - printf ("(0x%02x)\tOffline data collection activity was\n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was\n\t\t\t\t\t", data.offline_data_collection_status); - printf("never started.\n"); + pout("never started.\n"); break; case 0x01: case 0x81: - printf ("(0x%02x)\tReserved.\n", + pout ("(0x%02x)\tReserved.\n", data.offline_data_collection_status); break; case 0x02: case 0x82: - printf ("(0x%02x)\tOffline data collection activity \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("completed without error.\n"); + pout ("completed without error.\n"); break; case 0x03: case 0x83: - printf ("(0x%02x)\tReserved.\n", + pout ("(0x%02x)\tReserved.\n", data.offline_data_collection_status); break; case 0x04: case 0x84: - printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("suspended by an interrupting command from host.\n"); + pout ("suspended by an interrupting command from host.\n"); break; case 0x05: case 0x85: - printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("aborted by an interrupting command from host.\n"); + pout ("aborted by an interrupting command from host.\n"); break; case 0x06: case 0x86: - printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("aborted by the device with a fatal error.\n"); + pout ("aborted by the device with a fatal error.\n"); break; default: if ( ((data.offline_data_collection_status >= 0x07) && @@ -156,12 +156,12 @@ void PrintSmartOfflineStatus ( struct ata_smart_values data) ((data.offline_data_collection_status >= 0xc0) && (data.offline_data_collection_status <= 0xff)) ) { - printf ("(0x%02x)\tVendor Specific.\n", + pout ("(0x%02x)\tVendor Specific.\n", data.offline_data_collection_status); } else { - printf ("(0x%02x)\tReserved.\n", + pout ("(0x%02x)\tReserved.\n", data.offline_data_collection_status); } } @@ -171,64 +171,64 @@ void PrintSmartOfflineStatus ( struct ata_smart_values data) void PrintSmartSelfExecStatus ( struct ata_smart_values data) { - printf ("Self-test execution status: "); + pout ("Self-test execution status: "); switch (data.self_test_exec_status >> 4) { case 0: - printf ("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", data.self_test_exec_status); - printf ("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n"); + pout ("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n"); break; case 1: - printf ("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t", + pout ("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the host.\n"); + pout ("the host.\n"); break; case 2: - printf ("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t", + pout ("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t", data.self_test_exec_status); - printf ("by the host with a hard or soft reset.\n"); + pout ("by the host with a hard or soft reset.\n"); break; case 3: - printf ("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t", + pout ("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t", data.self_test_exec_status); - printf ("occurred while the device was executing\n\t\t\t\t\t"); - printf ("its self-test routine and the device \n\t\t\t\t\t"); - printf ("was unable to complete the self-test \n\t\t\t\t\t"); - printf ("routine.\n"); + pout ("occurred while the device was executing\n\t\t\t\t\t"); + pout ("its self-test routine and the device \n\t\t\t\t\t"); + pout ("was unable to complete the self-test \n\t\t\t\t\t"); + pout ("routine.\n"); break; case 4: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("a test element that failed and the test\n\t\t\t\t\t"); - printf ("element that failed is not known.\n"); + pout ("a test element that failed and the test\n\t\t\t\t\t"); + pout ("element that failed is not known.\n"); break; case 5: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the electrical element of the test\n\t\t\t\t\t"); - printf ("failed.\n"); + pout ("the electrical element of the test\n\t\t\t\t\t"); + pout ("failed.\n"); break; case 6: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the servo (and/or seek) element of the \n\t\t\t\t\t"); - printf ("test failed.\n"); + pout ("the servo (and/or seek) element of the \n\t\t\t\t\t"); + pout ("test failed.\n"); break; case 7: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the read element of the test failed.\n"); + pout ("the read element of the test failed.\n"); break; case 15: - printf ("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t", + pout ("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t", data.self_test_exec_status); - printf ("%1d0%% of test remaining.\n", + pout ("%1d0%% of test remaining.\n", data.self_test_exec_status & 0x0f); break; default: - printf ("(%4d)\tReserved.\n", + pout ("(%4d)\tReserved.\n", data.self_test_exec_status); break; } @@ -239,8 +239,8 @@ void PrintSmartSelfExecStatus ( struct ata_smart_values data) void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values data) { - printf ("Total time to complete off-line \n"); - printf ("data collection: \t\t (%4d) seconds.\n", + pout ("Total time to complete off-line \n"); + pout ("data collection: \t\t (%4d) seconds.\n", data.total_time_to_complete_off_line); } @@ -248,33 +248,33 @@ void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values data) void PrintSmartOfflineCollectCap ( struct ata_smart_values data) { - printf ("Offline data collection\n"); - printf ("capabilities: \t\t\t (0x%02x) ", + pout ("Offline data collection\n"); + pout ("capabilities: \t\t\t (0x%02x) ", data.offline_data_collection_capability); if (data.offline_data_collection_capability == 0x00) { - printf ("\tOff-line data collection not supported.\n"); + pout ("\tOff-line data collection not supported.\n"); } else { - printf( "%s\n", isSupportExecuteOfflineImmediate(data)? + pout( "%s\n", isSupportExecuteOfflineImmediate(data)? "SMART execute Offline immediate." : "No SMART execute Offline immediate."); - printf( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? + pout( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? "Automatic timer ON/OFF support.": "No Automatic timer ON/OFF support."); - printf( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)? + pout( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)? "Abort Offline collection upon new\n\t\t\t\t\tcommand.": "Suspend Offline collection upon new\n\t\t\t\t\tcommand."); - printf( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? + pout( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? "Offline surface scan supported.": "No Offline surface scan supported."); - printf( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? + pout( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? "Self-test supported.": "No Self-test supported."); } @@ -284,23 +284,23 @@ void PrintSmartOfflineCollectCap ( struct ata_smart_values data) void PrintSmartCapability ( struct ata_smart_values data) { - printf ("SMART capabilities: "); - printf ("(0x%04x)\t", data.smart_capability); + pout ("SMART capabilities: "); + pout ("(0x%04x)\t", data.smart_capability); if (data.smart_capability == 0x00) { - printf ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n"); + pout ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n"); } else { - printf( "%s\n", (data.smart_capability & 0x01)? + pout( "%s\n", (data.smart_capability & 0x01)? "Saves SMART data before entering\n\t\t\t\t\tpower-saving mode.": "Does not save SMART data before\n\t\t\t\t\tentering power-saving mode."); if ( data.smart_capability & 0x02 ) { - printf ("\t\t\t\t\tSupports SMART auto save timer.\n"); + pout ("\t\t\t\t\tSupports SMART auto save timer.\n"); } } } @@ -310,15 +310,15 @@ void PrintSmartCapability ( struct ata_smart_values data) void PrintSmartErrorLogCapability ( struct ata_smart_values data) { - printf ("Error logging capability: "); + pout ("Error logging capability: "); if ( isSmartErrorLogCapable(data) ) { - printf (" (0x%02x)\tError logging supported.\n", + pout (" (0x%02x)\tError logging supported.\n", data.errorlog_capability); } else { - printf (" (0x%02x)\tError logging NOT supported.\n", + pout (" (0x%02x)\tError logging NOT supported.\n", data.errorlog_capability); } } @@ -329,15 +329,15 @@ void PrintSmartShortSelfTestPollingTime ( struct ata_smart_values data) { if ( isSupportSelfTest(data) ) { - printf ("Short self-test routine \n"); - printf ("recommended polling time: \t (%4d) minutes.\n", + pout ("Short self-test routine \n"); + pout ("recommended polling time: \t (%4d) minutes.\n", data.short_test_completion_time); } else { - printf ("Short self-test routine \n"); - printf ("recommended polling time: \t Not Supported.\n"); + pout ("Short self-test routine \n"); + pout ("recommended polling time: \t Not Supported.\n"); } } @@ -346,14 +346,14 @@ void PrintSmartExtendedSelfTestPollingTime ( struct ata_smart_values data) { if ( isSupportSelfTest(data) ) { - printf ("Extended self-test routine \n"); - printf ("recommended polling time: \t (%4d) minutes.\n", + pout ("Extended self-test routine \n"); + pout ("recommended polling time: \t (%4d) minutes.\n", data.extend_test_completion_time); } else { - printf ("Extended self-test routine \n"); - printf ("recommended polling time: \t Not Supported.\n"); + pout ("Extended self-test routine \n"); + pout ("recommended polling time: \t Not Supported.\n"); } } @@ -392,10 +392,10 @@ void PrintSmartAttribWithThres (struct ata_smart_values data, // print header only if needed if (needheader){ if (!onlyfailed){ - printf ("SMART Data Structure revision number: %i\n",data.revnumber); - printf ("Vendor Specific SMART Attributes with Thresholds:\n"); + pout ("SMART Attributes Data Structure revision number: %i\n",data.revnumber); + pout ("Vendor Specific SMART Attributes with Thresholds:\n"); } - printf("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE\n"); + pout("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE\n"); needheader=0; } @@ -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%-12s", + pout(" 0x%04x %.3i %.3i %.3i %-9s%-12s", disk->status.all, disk->current, disk->worst, thre->threshold, type, status); @@ -428,64 +428,50 @@ void PrintSmartAttribWithThres (struct ata_smart_values data, case 9: if (smart009minutes) // minutes - printf ("%llu h + %2llu m\n",rawvalue/60,rawvalue%60); + pout ("%llu h + %2llu m\n",rawvalue/60,rawvalue%60); else // hours - printf ("%llu\n", rawvalue); //stored in hours + pout ("%llu\n", rawvalue); //stored in hours break; // Temperature case 194: - printf ("%u", disk->raw[0]); + pout ("%u", disk->raw[0]); if (rawvalue==disk->raw[0]) - printf("\n"); + pout("\n"); else // The other bytes are in use. Try IBM's model - printf(" (Lifetime Min/Max %u/%u)\n",disk->raw[2], + pout(" (Lifetime Min/Max %u/%u)\n",disk->raw[2], disk->raw[4]); break; default: - printf("%llu\n", rawvalue); + pout("%llu\n", rawvalue); } } } + if (!needheader) pout("\n"); } -void ataPrintGeneralSmartValues ( struct ata_smart_values data) -{ - printf ("\nGeneral SMART Values: \n"); - - PrintSmartOfflineStatus (data); - printf("\n"); - - if (isSupportSelfTest(data)) - { - PrintSmartSelfExecStatus (data); - printf("\n"); - } - - PrintSmartTotalTimeCompleteOffline (data); - printf("\n"); - - PrintSmartOfflineCollectCap (data); - printf("\n"); - - PrintSmartCapability ( data); - printf("\n"); - - PrintSmartErrorLogCapability (data); - printf ("\n"); - - if (isSupportSelfTest(data)) - { - PrintSmartShortSelfTestPollingTime (data); - printf ("\n"); - - PrintSmartExtendedSelfTestPollingTime (data); - printf ("\n"); - } - +void ataPrintGeneralSmartValues(struct ata_smart_values data){ + pout ("General SMART Values:\n"); + + PrintSmartOfflineStatus(data); + + if (isSupportSelfTest(data)){ + PrintSmartSelfExecStatus (data); + } + + PrintSmartTotalTimeCompleteOffline(data); + PrintSmartOfflineCollectCap(data); + PrintSmartCapability(data); + + PrintSmartErrorLogCapability(data); + if (isSupportSelfTest(data)){ + PrintSmartShortSelfTestPollingTime (data); + PrintSmartExtendedSelfTestPollingTime (data); + } + pout("\n"); } // Is not (currently) used in ANY code @@ -493,12 +479,12 @@ void ataPrintSmartThresholds (struct ata_smart_thresholds data) { int i; - printf ("SMART Thresholds\n"); - printf ("SMART Threshold Revision Number: %i\n", data.revnumber); + pout ("SMART Thresholds\n"); + pout ("SMART Threshold Revision Number: %i\n", data.revnumber); for ( i = 0 ; i < NUMBER_ATA_SMART_ATTRIBUTES ; i++) { if (data.thres_entries[i].id) - printf ("Attribute %3i threshold: %02x (%2i)\n", + pout ("Attribute %3i threshold: %02x (%2i)\n", data.thres_entries[i].id, data.thres_entries[i].threshold, data.thres_entries[i].threshold); @@ -519,45 +505,41 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) { int i,j,k; - printf ("\nSMART Error Log\n"); - printf ( "SMART Error Logging Version: %i\n", data.revnumber); + pout ("SMART Error Log Version: %i\n", data.revnumber); // if no errors logged, return - if ( ! data.error_log_pointer) - { - printf ("No Errors Logged\n"); - return; - } - + if (!data.error_log_pointer){ + pout ("No Errors Logged\n\n"); + return; + } + QUIETON; // if log pointer out of range, return if ( data.error_log_pointer>5 ){ - printf("Invalid Error log index = %02x (T13/1321D rev 1c" - "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n", - data.error_log_pointer); + pout("Invalid Error log index = %02x (T13/1321D rev 1c" + "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n\n", + data.error_log_pointer); return; } // starting printing error log info if (data.ata_error_count<=5) - printf ( "ATA Error Count: %u\n", data.ata_error_count); + pout ( "ATA Error Count:y %u\n", data.ata_error_count); else - printf ( "ATA Error Count: %u (only the most recent five errors are shown below)\n", - data.ata_error_count); - - printf( "Acronyms used below:\n"); - printf( "DCR = Device Control Register\n"); - printf( "FR = Features Register\n"); - printf( "SC = Sector Count Register\n"); - printf( "SN = Sector Number Register\n"); - printf( "CL = Cylinder Low Register\n"); - printf( "CH = Cylinder High Register\n"); - printf( "D/H = Device/Head Register\n"); - printf( "CR = Content written to Command Register\n"); - printf( "ER = Error register\n"); - printf( "STA = Status register\n\n"); - printf( "Timestamp is time (in seconds) since the command that caused an error was accepted,\n"); - printf( "measured from the time the disk was powered-on, during the session when the error occurred.\n"); - printf( "Note: timestamp \"wraps\" after 1193.046 hours = 49.710 days = 2^32 seconds.\n"); + pout ( "ATA Error Count: %u (only the most recent five errors are shown below)\n", + data.ata_error_count); + + pout("\tDCR = Device Control Register\n"); + pout("\tFR = Features Register\n"); + pout("\tSC = Sector Count Register\n"); + pout("\tSN = Sector Number Register\n"); + pout("\tCL = Cylinder Low Register\n"); + pout("\tCH = Cylinder High Register\n"); + pout("\tD/H = Device/Head Register\n"); + pout("\tCR = Content written to Command Register\n"); + pout("\tER = Error register\n"); + pout("\tSTA = Status register\n"); + pout("Timestamp is seconds since the previous disk power-on.\n"); + pout("Note: timestamp \"wraps\" after 2^32 sec = 49.710 days.\n\n"); // now step through the five error log data structures (table 39 of spec) for (k = 4; k >= 0; k-- ) { @@ -576,13 +558,13 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) case 0x04: msgstate="doing SMART off-line or self test"; break; default: msgstate="in a vendor specific or reserved state"; } - printf("\nError Log Structure %i:\n",5-k); + pout("Error Log Structure %i:\n",5-k); // See table 42 of ATA5 spec - printf("Error occurred at disk power-on lifetime: %u hours\n", + pout("Error occurred at disk power-on lifetime: %u hours\n", data.errorlog_struct[i].error_struct.timestamp); - printf("When the command that caused the error occurred, the device was %s.\n",msgstate); - printf("After command completion occurred, registers were:\n"); - printf("ER:%02x SC:%02x SN:%02x CL:%02x CH:%02x D/H:%02x ST:%02x\n", + pout("When the command that caused the error occurred, the device was %s.\n",msgstate); + pout("After command completion occurred, registers were:\n"); + pout("ER:%02x SC:%02x SN:%02x CL:%02x CH:%02x D/H:%02x ST:%02x\n", data.errorlog_struct[i].error_struct.error_register, data.errorlog_struct[i].error_struct.sector_count, data.errorlog_struct[i].error_struct.sector_number, @@ -590,14 +572,14 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) data.errorlog_struct[i].error_struct.cylinder_high, data.errorlog_struct[i].error_struct.drive_head, data.errorlog_struct[i].error_struct.status); - printf("Sequence of commands leading to the command that caused the error were:\n"); - printf("DCR FR SC SN CL CH D/H CR Timestamp\n"); + pout("Sequence of commands leading to the command that caused the error were:\n"); + pout("DCR FR SC SN CL CH D/H CR Timestamp\n"); for ( j = 4; j >= 0; j--){ struct ata_smart_errorlog_command_struct *thiscommand=&(data.errorlog_struct[i].commands[j]); // Spec says: unused data command structures shall be zero filled if (nonempty((unsigned char*)thiscommand,sizeof(*thiscommand))) - printf ( " %02x %02x %02x %02x %02x %02x %02x %02x %u.%03u\n", + pout ( " %02x %02x %02x %02x %02x %02x %02x %02x %u.%03u\n", thiscommand->devicecontrolreg, thiscommand->featuresreg, thiscommand->sector_count, @@ -608,24 +590,27 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) thiscommand->commandreg, (unsigned int)(thiscommand->timestamp / 1000), (unsigned int)(thiscommand->timestamp % 1000)); - } + } + pout("\n"); } - } + } + QUIETOFF; return; } - -void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries){ +// return value is number of entries found where the self-test showed an error +int ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries){ int i,j,noheaderprinted=1; + int retval=0; if (allentries) - printf("SMART Self-test log, version number %u\n",data.revnumber); + pout("SMART Self-test log, version number %u\n",data.revnumber); if (data.revnumber!=0x01 && allentries) - printf("Warning - structure revision number does not match spec!\n"); + pout("Warning - structure revision number does not match spec!\n"); if (data.mostrecenttest==0){ if (allentries) - printf("No self-tests have been logged\n"); - return; + pout("No self-tests have been logged\n\n"); + return 0; } // print log @@ -664,6 +649,8 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries) default:msgstat="Unknown test status "; } + retval+=errorfound; + sprintf(percent,"%1d0%%",(log->selfteststatus)&0xf); if (log->lbafirstfailure==0xffffffff || log->lbafirstfailure==0x00000000) sprintf(firstlba,"%s",""); @@ -671,18 +658,21 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries) sprintf(firstlba,"0x%08x",log->lbafirstfailure); if (noheaderprinted && (allentries || errorfound)){ - printf("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); + pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); noheaderprinted=0; } if (allentries || errorfound) - printf("#%2d %s %s %s %8u %s\n",21-i,msgtest,msgstat, + pout("#%2d %s %s %s %8u %s\n",21-i,msgtest,msgstat, percent,log->timestamp,firstlba); } - else - return; + else { + pout("\n"); + return retval; + } } - return; + pout("\n"); + return retval; } void ataPseudoCheckSmart ( struct ata_smart_values data, @@ -695,11 +685,11 @@ void ataPseudoCheckSmart ( struct ata_smart_values data, data.vendor_attributes[i].status.flag.prefailure && (data.vendor_attributes[i].current <= thresholds.thres_entries[i].threshold) && (thresholds.thres_entries[i].threshold != 0xFE)){ - printf("Attribute ID %i Failed\n",data.vendor_attributes[i].id); + pout("Attribute ID %i Failed\n",data.vendor_attributes[i].id); failed = 1; } } - printf("%s\n", ( failed )? + pout("%s\n", ( failed )? "SMART overall-health self-assessment test result: FAILED!\n" "Drive failure expected in less than 24 hours. SAVE ALL DATA": "SMART overall-health self-assessment test result: PASSED"); @@ -806,7 +796,7 @@ void ataPrintSmartAttribName ( unsigned char id ){ name="Unknown_Attribute"; break; } - printf("%3d %-23s",id,name); + pout("%3d %-23s",id,name); } /**** @@ -827,66 +817,69 @@ int ataPrintMain (int fd){ // 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"); + pout("Smartctl: Hard Drive Read Identity Failed\n\n"); returnval|=FAILID; } // Print most drive identity information if requested if (driveinfo){ - printf("\n=== START OF INFORMATION SECTION ===\n"); + pout("=== START OF INFORMATION SECTION ===\n"); ataPrintDriveInfo(drive); } // now check if drive supports SMART; otherwise time to exit if (!ataSmartSupport(drive)){ - printf("SMART support is: Unavailable - device lacks SMART capability.\n"); - printf(" Checking to be sure by trying SMART ENABLE command.\n"); + pout("SMART support is: Unavailable - device lacks SMART capability.\n"); + pout(" Checking to be sure by trying SMART ENABLE command.\n"); if (ataEnableSmart(fd)){ - printf(" No SMART functionality found. Sorry.\n"); + pout(" No SMART functionality found. Sorry.\n"); return returnval|FAILSMART; } else - printf(" SMART appears to work. Continuing.\n"); + pout(" SMART appears to work. Continuing.\n"); + if (!driveinfo) pout("\n"); } // Now print remaining drive info: is SMART enabled? if (driveinfo){ - printf("SMART support is: Available - device has SMART capability.\n"); + pout("SMART support is: Available - device has SMART capability.\n"); if (ataDoesSmartWork(fd)) - printf("SMART support is: Enabled\n"); + pout("SMART support is: Enabled\n"); else - printf("SMART support is: Disabled\n"); + pout("SMART support is: Disabled\n"); + pout("\n"); } + // START OF THE ENABLE/DISABLE SECTION OF THE CODE if (smartenable || smartdisable || smartautosaveenable || smartautosavedisable || smartautoofflineenable || smartautoofflinedisable) - printf("\n=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); + pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); // Enable/Disable SMART commands if (smartenable){ if (ataEnableSmart(fd)) { - printf("Smartctl: SMART Enable Failed.\n\n"); + pout("Smartctl: SMART Enable Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Enabled.\n"); + pout("SMART Enabled.\n"); } // From here on, every command requires that SMART be enabled... if (!ataDoesSmartWork(fd)) { - printf("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE ); + pout("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE ); return returnval; } // Turn off SMART on device if (smartdisable){ if (ataDisableSmart(fd)) { - printf( "Smartctl: SMART Disable Failed.\n\n"); + pout( "Smartctl: SMART Disable Failed.\n\n"); returnval|=FAILSMART; } - printf("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE); + pout("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE); return returnval; } @@ -898,84 +891,95 @@ int ataPrintMain (int fd){ // Enable/Disable Auto-save attributes if (smartautosaveenable){ if (ataEnableAutoSave(fd)){ - printf( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n"); + pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Attribute Autosave Enabled.\n"); + pout("SMART Attribute Autosave Enabled.\n"); } if (smartautosavedisable){ if (ataDisableAutoSave(fd)){ - printf( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n"); + pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Attribute Autosave Disabled.\n"); + pout("SMART Attribute Autosave Disabled.\n"); } // for everything else read values and thresholds are needed if (ataReadSmartValues(fd, &smartval)){ - printf("Smartctl: SMART Read Values failed.\n\n"); + pout("Smartctl: SMART Read Values failed.\n\n"); returnval|=FAILSMART; } if (ataReadSmartThresholds(fd, &smartthres)){ - printf("Smartctl: SMART Read Thresholds failed.\n\n"); + pout("Smartctl: SMART Read Thresholds failed.\n\n"); returnval|=FAILSMART; } // Enable/Disable Off-line testing if (smartautoofflineenable){ if (!isSupportAutomaticTimer(smartval)){ - printf("Device does not support SMART Automatic Timers.\n\n"); + pout("Warning: device does not support SMART Automatic Timers.\n\n"); } if (ataEnableAutoOffline(fd)){ - printf( "Smartctl: SMART Enable Automatic Offline Failed.\n\n"); + pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n"); returnval|=FAILSMART; } else - printf ("SMART Automatic Offline Testing Enabled every four hours.\n"); + pout ("SMART Automatic Offline Testing Enabled every four hours.\n"); } if (smartautoofflinedisable){ if (!isSupportAutomaticTimer(smartval)){ - printf("Device does not support SMART Automatic Timers.\n\n"); + pout("Warning: device does not support SMART Automatic Timers.\n\n"); } if (ataDisableAutoOffline(fd)){ - printf("Smartctl: SMART Disable Automatic Offline Failed.\n\n"); + pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Automatic Offline Testing Disabled.\n"); + pout("SMART Automatic Offline Testing Disabled.\n"); } + // all this for a newline! + if (smartenable || smartdisable || + smartautosaveenable || smartautosavedisable || + smartautoofflineenable || smartautoofflinedisable) + pout("\n"); + // START OF READ-ONLY OPTIONS APART FROM -p and -i if (checksmart || generalsmartvalues || smartvendorattrib || smarterrorlog || smartselftestlog) - printf("\n=== START OF READ SMART DATA SECTION ===\n"); + pout("=== START OF READ SMART DATA SECTION ===\n"); // Check SMART status (use previously returned value) if (checksmart){ if (code) { - printf("SMART overall-health self-assessment test result: FAILED!\n" + QUIETON; + pout("SMART overall-health self-assessment test result: FAILED!\n" "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); + QUIETOFF; if (ataCheckSmart(smartval, smartthres,1)){ + QUIETON; returnval|=FAILATTR; - printf("Failed Attributes:\n"); + pout("Failed Attributes:\n"); PrintSmartAttribWithThres(smartval, smartthres,1); } - else { - printf("No failed Attributes found.\n"); - } - printf("\n"); + else + pout("No failed Attributes found.\n\n"); returnval|=FAILSTATUS; + QUIETOFF; } else { - printf("SMART overall-health self-assessment test result: PASSED\n"); + pout("SMART overall-health self-assessment test result: PASSED\n"); if (ataCheckSmart(smartval, smartthres,0)){ - printf("Marginal attributes:\n"); + QUIETON; + pout("But please note the following marginal attributes:\n"); PrintSmartAttribWithThres(smartval, smartthres,2); returnval|=FAILAGE; } - printf("\n"); + else + pout("\n"); } + QUIETOFF; } // Print general SMART values @@ -983,32 +987,42 @@ int ataPrintMain (int fd){ ataPrintGeneralSmartValues(smartval); // Print vendor-specific attributes - if (smartvendorattrib) - PrintSmartAttribWithThres(smartval, smartthres,0); + if (smartvendorattrib){ + QUIETON; + PrintSmartAttribWithThres(smartval, smartthres,quietmode?2:0); + QUIETOFF; + } // Print SMART error log if (smarterrorlog){ if (!isSmartErrorLogCapable(smartval)) - printf("Device does not support Error Logging\n"); + pout("Warning: device does not support Error Logging\n"); if (ataReadErrorLog(fd, &smarterror)){ - printf("Smartctl: SMART Errorlog Read Failed\n"); + pout("Smartctl: SMART Errorlog Read Failed\n"); returnval|=FAILSMART; } - else + else { + QUIETON; ataPrintSmartErrorlog(smarterror); + QUIETOFF; + } } // Print SMART self-test log if (smartselftestlog){ if (!isSmartErrorLogCapable(smartval)) - printf("Device does not support Self Test Logging\n"); + pout("Warning: device does not support Self Test Logging\n"); else { if(ataReadSelfTestLog(fd, &smartselftest)){ - printf("Smartctl: SMART Self Test Log Read Failed\n"); + pout("Smartctl: SMART Self Test Log Read Failed\n"); returnval|=FAILSMART; } - else - ataPrintSmartSelfTestlog(smartselftest,1); + else { + QUIETON; + if (ataPrintSmartSelfTestlog(smartselftest,!quietmode)) + returnval|=FAILLOG; + QUIETOFF; + } } } @@ -1016,13 +1030,13 @@ int ataPrintMain (int fd){ if (testcase==-1) return returnval; - printf("\n=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n"); + pout("=== 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"); + pout("Warning: device does not support Execute Off-Line Immediate function.\n\n"); else if (!isSupportSelfTest(smartval)) - printf ("ERROR: device does not support Self-Test functions.\n\n"); + pout ("Warning: device does not support Self-Test functions.\n\n"); // Now do the test if (ataSmartTest(fd, testcase)) @@ -1030,11 +1044,11 @@ int ataPrintMain (int fd){ // Tell user how long test will take to complete if ((timewait=TestTime(smartval,testcase))){ - printf ("Please wait %d %s for test to complete.\n", + pout ("Please wait %d %s for test to complete.\n", timewait, testcase==OFFLINE_FULL_SCAN?"seconds":"minutes"); if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST) - printf ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT); + pout ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT); } return returnval; } diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp index 624527273f91bc854c440870e4d8ca2ff9b09aca..3608014f676f41902b733759e1d0dbb22c9b30dc 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.24 2002/10/22 20:35:42 ballen4705 Exp $\n" +const char *CVSid4="$Id: ataprint.cpp,v 1.25 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" CVSID2 "\t" CVSID3 "\t" CVSID6 ; // Function for printing ASCII byte-swapped strings, skipping white @@ -51,9 +51,9 @@ void printswap(char *in, unsigned int n){ // and do the printing starting from first non-white space if (n-i) - printf("%.*s\n",(int)(n-i),out+i); + pout("%.*s\n",(int)(n-i),out+i); else - printf("[No Information Found]\n"); + pout("[No Information Found]\n"); return; } @@ -65,13 +65,13 @@ void ataPrintDriveInfo (struct hd_driveid drive){ char unknown[64]; // print out model, serial # and firmware versions (byte-swap ASCI strings) - printf("Device Model: "); + pout("Device Model: "); printswap(drive.model,40); - printf("Serial Number: "); + pout("Serial Number: "); printswap(drive.serial_no,20); - printf("Firmware Version: "); + pout("Firmware Version: "); printswap(drive.fw_rev,8); // now get ATA version info @@ -90,14 +90,14 @@ void ataPrintDriveInfo (struct hd_driveid drive){ // http://www.t13.org/project/d2008r6.pdf to see this. So it's not // enough to check if we are ATA-3. Version=-3 indicates ATA-3 // BEFORE Revision 3. - printf("ATA Version is: %i\n",version>0?version:-1*version); - printf("ATA Standard is: %s\n",description); + pout("ATA Version is: %i\n",version>0?version:-1*version); + pout("ATA Standard is: %s\n",description); if (version>=3) return; - printf("SMART is only available in ATA Version 3 Revision 3 or greater.\n"); - printf("We will try to proceed in spite of this.\n"); + pout("SMART is only available in ATA Version 3 Revision 3 or greater.\n"); + pout("We will try to proceed in spite of this.\n"); return; } @@ -107,48 +107,48 @@ void ataPrintDriveInfo (struct hd_driveid drive){ void PrintSmartOfflineStatus ( struct ata_smart_values data) { - printf ("Off-line data collection status: "); + pout ("Off-line data collection status: "); switch (data.offline_data_collection_status){ case 0x00: case 0x80: - printf ("(0x%02x)\tOffline data collection activity was\n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was\n\t\t\t\t\t", data.offline_data_collection_status); - printf("never started.\n"); + pout("never started.\n"); break; case 0x01: case 0x81: - printf ("(0x%02x)\tReserved.\n", + pout ("(0x%02x)\tReserved.\n", data.offline_data_collection_status); break; case 0x02: case 0x82: - printf ("(0x%02x)\tOffline data collection activity \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("completed without error.\n"); + pout ("completed without error.\n"); break; case 0x03: case 0x83: - printf ("(0x%02x)\tReserved.\n", + pout ("(0x%02x)\tReserved.\n", data.offline_data_collection_status); break; case 0x04: case 0x84: - printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("suspended by an interrupting command from host.\n"); + pout ("suspended by an interrupting command from host.\n"); break; case 0x05: case 0x85: - printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("aborted by an interrupting command from host.\n"); + pout ("aborted by an interrupting command from host.\n"); break; case 0x06: case 0x86: - printf ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", + pout ("(0x%02x)\tOffline data collection activity was \n\t\t\t\t\t", data.offline_data_collection_status); - printf ("aborted by the device with a fatal error.\n"); + pout ("aborted by the device with a fatal error.\n"); break; default: if ( ((data.offline_data_collection_status >= 0x07) && @@ -156,12 +156,12 @@ void PrintSmartOfflineStatus ( struct ata_smart_values data) ((data.offline_data_collection_status >= 0xc0) && (data.offline_data_collection_status <= 0xff)) ) { - printf ("(0x%02x)\tVendor Specific.\n", + pout ("(0x%02x)\tVendor Specific.\n", data.offline_data_collection_status); } else { - printf ("(0x%02x)\tReserved.\n", + pout ("(0x%02x)\tReserved.\n", data.offline_data_collection_status); } } @@ -171,64 +171,64 @@ void PrintSmartOfflineStatus ( struct ata_smart_values data) void PrintSmartSelfExecStatus ( struct ata_smart_values data) { - printf ("Self-test execution status: "); + pout ("Self-test execution status: "); switch (data.self_test_exec_status >> 4) { case 0: - printf ("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", data.self_test_exec_status); - printf ("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n"); + pout ("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n"); break; case 1: - printf ("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t", + pout ("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the host.\n"); + pout ("the host.\n"); break; case 2: - printf ("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t", + pout ("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t", data.self_test_exec_status); - printf ("by the host with a hard or soft reset.\n"); + pout ("by the host with a hard or soft reset.\n"); break; case 3: - printf ("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t", + pout ("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t", data.self_test_exec_status); - printf ("occurred while the device was executing\n\t\t\t\t\t"); - printf ("its self-test routine and the device \n\t\t\t\t\t"); - printf ("was unable to complete the self-test \n\t\t\t\t\t"); - printf ("routine.\n"); + pout ("occurred while the device was executing\n\t\t\t\t\t"); + pout ("its self-test routine and the device \n\t\t\t\t\t"); + pout ("was unable to complete the self-test \n\t\t\t\t\t"); + pout ("routine.\n"); break; case 4: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("a test element that failed and the test\n\t\t\t\t\t"); - printf ("element that failed is not known.\n"); + pout ("a test element that failed and the test\n\t\t\t\t\t"); + pout ("element that failed is not known.\n"); break; case 5: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the electrical element of the test\n\t\t\t\t\t"); - printf ("failed.\n"); + pout ("the electrical element of the test\n\t\t\t\t\t"); + pout ("failed.\n"); break; case 6: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the servo (and/or seek) element of the \n\t\t\t\t\t"); - printf ("test failed.\n"); + pout ("the servo (and/or seek) element of the \n\t\t\t\t\t"); + pout ("test failed.\n"); break; case 7: - printf ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", + pout ("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", data.self_test_exec_status); - printf ("the read element of the test failed.\n"); + pout ("the read element of the test failed.\n"); break; case 15: - printf ("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t", + pout ("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t", data.self_test_exec_status); - printf ("%1d0%% of test remaining.\n", + pout ("%1d0%% of test remaining.\n", data.self_test_exec_status & 0x0f); break; default: - printf ("(%4d)\tReserved.\n", + pout ("(%4d)\tReserved.\n", data.self_test_exec_status); break; } @@ -239,8 +239,8 @@ void PrintSmartSelfExecStatus ( struct ata_smart_values data) void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values data) { - printf ("Total time to complete off-line \n"); - printf ("data collection: \t\t (%4d) seconds.\n", + pout ("Total time to complete off-line \n"); + pout ("data collection: \t\t (%4d) seconds.\n", data.total_time_to_complete_off_line); } @@ -248,33 +248,33 @@ void PrintSmartTotalTimeCompleteOffline ( struct ata_smart_values data) void PrintSmartOfflineCollectCap ( struct ata_smart_values data) { - printf ("Offline data collection\n"); - printf ("capabilities: \t\t\t (0x%02x) ", + pout ("Offline data collection\n"); + pout ("capabilities: \t\t\t (0x%02x) ", data.offline_data_collection_capability); if (data.offline_data_collection_capability == 0x00) { - printf ("\tOff-line data collection not supported.\n"); + pout ("\tOff-line data collection not supported.\n"); } else { - printf( "%s\n", isSupportExecuteOfflineImmediate(data)? + pout( "%s\n", isSupportExecuteOfflineImmediate(data)? "SMART execute Offline immediate." : "No SMART execute Offline immediate."); - printf( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? + pout( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? "Automatic timer ON/OFF support.": "No Automatic timer ON/OFF support."); - printf( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)? + pout( "\t\t\t\t\t%s\n", isSupportOfflineAbort(data)? "Abort Offline collection upon new\n\t\t\t\t\tcommand.": "Suspend Offline collection upon new\n\t\t\t\t\tcommand."); - printf( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? + pout( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? "Offline surface scan supported.": "No Offline surface scan supported."); - printf( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? + pout( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? "Self-test supported.": "No Self-test supported."); } @@ -284,23 +284,23 @@ void PrintSmartOfflineCollectCap ( struct ata_smart_values data) void PrintSmartCapability ( struct ata_smart_values data) { - printf ("SMART capabilities: "); - printf ("(0x%04x)\t", data.smart_capability); + pout ("SMART capabilities: "); + pout ("(0x%04x)\t", data.smart_capability); if (data.smart_capability == 0x00) { - printf ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n"); + pout ("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n"); } else { - printf( "%s\n", (data.smart_capability & 0x01)? + pout( "%s\n", (data.smart_capability & 0x01)? "Saves SMART data before entering\n\t\t\t\t\tpower-saving mode.": "Does not save SMART data before\n\t\t\t\t\tentering power-saving mode."); if ( data.smart_capability & 0x02 ) { - printf ("\t\t\t\t\tSupports SMART auto save timer.\n"); + pout ("\t\t\t\t\tSupports SMART auto save timer.\n"); } } } @@ -310,15 +310,15 @@ void PrintSmartCapability ( struct ata_smart_values data) void PrintSmartErrorLogCapability ( struct ata_smart_values data) { - printf ("Error logging capability: "); + pout ("Error logging capability: "); if ( isSmartErrorLogCapable(data) ) { - printf (" (0x%02x)\tError logging supported.\n", + pout (" (0x%02x)\tError logging supported.\n", data.errorlog_capability); } else { - printf (" (0x%02x)\tError logging NOT supported.\n", + pout (" (0x%02x)\tError logging NOT supported.\n", data.errorlog_capability); } } @@ -329,15 +329,15 @@ void PrintSmartShortSelfTestPollingTime ( struct ata_smart_values data) { if ( isSupportSelfTest(data) ) { - printf ("Short self-test routine \n"); - printf ("recommended polling time: \t (%4d) minutes.\n", + pout ("Short self-test routine \n"); + pout ("recommended polling time: \t (%4d) minutes.\n", data.short_test_completion_time); } else { - printf ("Short self-test routine \n"); - printf ("recommended polling time: \t Not Supported.\n"); + pout ("Short self-test routine \n"); + pout ("recommended polling time: \t Not Supported.\n"); } } @@ -346,14 +346,14 @@ void PrintSmartExtendedSelfTestPollingTime ( struct ata_smart_values data) { if ( isSupportSelfTest(data) ) { - printf ("Extended self-test routine \n"); - printf ("recommended polling time: \t (%4d) minutes.\n", + pout ("Extended self-test routine \n"); + pout ("recommended polling time: \t (%4d) minutes.\n", data.extend_test_completion_time); } else { - printf ("Extended self-test routine \n"); - printf ("recommended polling time: \t Not Supported.\n"); + pout ("Extended self-test routine \n"); + pout ("recommended polling time: \t Not Supported.\n"); } } @@ -392,10 +392,10 @@ void PrintSmartAttribWithThres (struct ata_smart_values data, // print header only if needed if (needheader){ if (!onlyfailed){ - printf ("SMART Data Structure revision number: %i\n",data.revnumber); - printf ("Vendor Specific SMART Attributes with Thresholds:\n"); + pout ("SMART Attributes Data Structure revision number: %i\n",data.revnumber); + pout ("Vendor Specific SMART Attributes with Thresholds:\n"); } - printf("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE\n"); + pout("ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE WHEN_FAILED RAW_VALUE\n"); needheader=0; } @@ -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%-12s", + pout(" 0x%04x %.3i %.3i %.3i %-9s%-12s", disk->status.all, disk->current, disk->worst, thre->threshold, type, status); @@ -428,64 +428,50 @@ void PrintSmartAttribWithThres (struct ata_smart_values data, case 9: if (smart009minutes) // minutes - printf ("%llu h + %2llu m\n",rawvalue/60,rawvalue%60); + pout ("%llu h + %2llu m\n",rawvalue/60,rawvalue%60); else // hours - printf ("%llu\n", rawvalue); //stored in hours + pout ("%llu\n", rawvalue); //stored in hours break; // Temperature case 194: - printf ("%u", disk->raw[0]); + pout ("%u", disk->raw[0]); if (rawvalue==disk->raw[0]) - printf("\n"); + pout("\n"); else // The other bytes are in use. Try IBM's model - printf(" (Lifetime Min/Max %u/%u)\n",disk->raw[2], + pout(" (Lifetime Min/Max %u/%u)\n",disk->raw[2], disk->raw[4]); break; default: - printf("%llu\n", rawvalue); + pout("%llu\n", rawvalue); } } } + if (!needheader) pout("\n"); } -void ataPrintGeneralSmartValues ( struct ata_smart_values data) -{ - printf ("\nGeneral SMART Values: \n"); - - PrintSmartOfflineStatus (data); - printf("\n"); - - if (isSupportSelfTest(data)) - { - PrintSmartSelfExecStatus (data); - printf("\n"); - } - - PrintSmartTotalTimeCompleteOffline (data); - printf("\n"); - - PrintSmartOfflineCollectCap (data); - printf("\n"); - - PrintSmartCapability ( data); - printf("\n"); - - PrintSmartErrorLogCapability (data); - printf ("\n"); - - if (isSupportSelfTest(data)) - { - PrintSmartShortSelfTestPollingTime (data); - printf ("\n"); - - PrintSmartExtendedSelfTestPollingTime (data); - printf ("\n"); - } - +void ataPrintGeneralSmartValues(struct ata_smart_values data){ + pout ("General SMART Values:\n"); + + PrintSmartOfflineStatus(data); + + if (isSupportSelfTest(data)){ + PrintSmartSelfExecStatus (data); + } + + PrintSmartTotalTimeCompleteOffline(data); + PrintSmartOfflineCollectCap(data); + PrintSmartCapability(data); + + PrintSmartErrorLogCapability(data); + if (isSupportSelfTest(data)){ + PrintSmartShortSelfTestPollingTime (data); + PrintSmartExtendedSelfTestPollingTime (data); + } + pout("\n"); } // Is not (currently) used in ANY code @@ -493,12 +479,12 @@ void ataPrintSmartThresholds (struct ata_smart_thresholds data) { int i; - printf ("SMART Thresholds\n"); - printf ("SMART Threshold Revision Number: %i\n", data.revnumber); + pout ("SMART Thresholds\n"); + pout ("SMART Threshold Revision Number: %i\n", data.revnumber); for ( i = 0 ; i < NUMBER_ATA_SMART_ATTRIBUTES ; i++) { if (data.thres_entries[i].id) - printf ("Attribute %3i threshold: %02x (%2i)\n", + pout ("Attribute %3i threshold: %02x (%2i)\n", data.thres_entries[i].id, data.thres_entries[i].threshold, data.thres_entries[i].threshold); @@ -519,45 +505,41 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) { int i,j,k; - printf ("\nSMART Error Log\n"); - printf ( "SMART Error Logging Version: %i\n", data.revnumber); + pout ("SMART Error Log Version: %i\n", data.revnumber); // if no errors logged, return - if ( ! data.error_log_pointer) - { - printf ("No Errors Logged\n"); - return; - } - + if (!data.error_log_pointer){ + pout ("No Errors Logged\n\n"); + return; + } + QUIETON; // if log pointer out of range, return if ( data.error_log_pointer>5 ){ - printf("Invalid Error log index = %02x (T13/1321D rev 1c" - "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n", - data.error_log_pointer); + pout("Invalid Error log index = %02x (T13/1321D rev 1c" + "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n\n", + data.error_log_pointer); return; } // starting printing error log info if (data.ata_error_count<=5) - printf ( "ATA Error Count: %u\n", data.ata_error_count); + pout ( "ATA Error Count:y %u\n", data.ata_error_count); else - printf ( "ATA Error Count: %u (only the most recent five errors are shown below)\n", - data.ata_error_count); - - printf( "Acronyms used below:\n"); - printf( "DCR = Device Control Register\n"); - printf( "FR = Features Register\n"); - printf( "SC = Sector Count Register\n"); - printf( "SN = Sector Number Register\n"); - printf( "CL = Cylinder Low Register\n"); - printf( "CH = Cylinder High Register\n"); - printf( "D/H = Device/Head Register\n"); - printf( "CR = Content written to Command Register\n"); - printf( "ER = Error register\n"); - printf( "STA = Status register\n\n"); - printf( "Timestamp is time (in seconds) since the command that caused an error was accepted,\n"); - printf( "measured from the time the disk was powered-on, during the session when the error occurred.\n"); - printf( "Note: timestamp \"wraps\" after 1193.046 hours = 49.710 days = 2^32 seconds.\n"); + pout ( "ATA Error Count: %u (only the most recent five errors are shown below)\n", + data.ata_error_count); + + pout("\tDCR = Device Control Register\n"); + pout("\tFR = Features Register\n"); + pout("\tSC = Sector Count Register\n"); + pout("\tSN = Sector Number Register\n"); + pout("\tCL = Cylinder Low Register\n"); + pout("\tCH = Cylinder High Register\n"); + pout("\tD/H = Device/Head Register\n"); + pout("\tCR = Content written to Command Register\n"); + pout("\tER = Error register\n"); + pout("\tSTA = Status register\n"); + pout("Timestamp is seconds since the previous disk power-on.\n"); + pout("Note: timestamp \"wraps\" after 2^32 sec = 49.710 days.\n\n"); // now step through the five error log data structures (table 39 of spec) for (k = 4; k >= 0; k-- ) { @@ -576,13 +558,13 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) case 0x04: msgstate="doing SMART off-line or self test"; break; default: msgstate="in a vendor specific or reserved state"; } - printf("\nError Log Structure %i:\n",5-k); + pout("Error Log Structure %i:\n",5-k); // See table 42 of ATA5 spec - printf("Error occurred at disk power-on lifetime: %u hours\n", + pout("Error occurred at disk power-on lifetime: %u hours\n", data.errorlog_struct[i].error_struct.timestamp); - printf("When the command that caused the error occurred, the device was %s.\n",msgstate); - printf("After command completion occurred, registers were:\n"); - printf("ER:%02x SC:%02x SN:%02x CL:%02x CH:%02x D/H:%02x ST:%02x\n", + pout("When the command that caused the error occurred, the device was %s.\n",msgstate); + pout("After command completion occurred, registers were:\n"); + pout("ER:%02x SC:%02x SN:%02x CL:%02x CH:%02x D/H:%02x ST:%02x\n", data.errorlog_struct[i].error_struct.error_register, data.errorlog_struct[i].error_struct.sector_count, data.errorlog_struct[i].error_struct.sector_number, @@ -590,14 +572,14 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) data.errorlog_struct[i].error_struct.cylinder_high, data.errorlog_struct[i].error_struct.drive_head, data.errorlog_struct[i].error_struct.status); - printf("Sequence of commands leading to the command that caused the error were:\n"); - printf("DCR FR SC SN CL CH D/H CR Timestamp\n"); + pout("Sequence of commands leading to the command that caused the error were:\n"); + pout("DCR FR SC SN CL CH D/H CR Timestamp\n"); for ( j = 4; j >= 0; j--){ struct ata_smart_errorlog_command_struct *thiscommand=&(data.errorlog_struct[i].commands[j]); // Spec says: unused data command structures shall be zero filled if (nonempty((unsigned char*)thiscommand,sizeof(*thiscommand))) - printf ( " %02x %02x %02x %02x %02x %02x %02x %02x %u.%03u\n", + pout ( " %02x %02x %02x %02x %02x %02x %02x %02x %u.%03u\n", thiscommand->devicecontrolreg, thiscommand->featuresreg, thiscommand->sector_count, @@ -608,24 +590,27 @@ void ataPrintSmartErrorlog (struct ata_smart_errorlog data) thiscommand->commandreg, (unsigned int)(thiscommand->timestamp / 1000), (unsigned int)(thiscommand->timestamp % 1000)); - } + } + pout("\n"); } - } + } + QUIETOFF; return; } - -void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries){ +// return value is number of entries found where the self-test showed an error +int ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries){ int i,j,noheaderprinted=1; + int retval=0; if (allentries) - printf("SMART Self-test log, version number %u\n",data.revnumber); + pout("SMART Self-test log, version number %u\n",data.revnumber); if (data.revnumber!=0x01 && allentries) - printf("Warning - structure revision number does not match spec!\n"); + pout("Warning - structure revision number does not match spec!\n"); if (data.mostrecenttest==0){ if (allentries) - printf("No self-tests have been logged\n"); - return; + pout("No self-tests have been logged\n\n"); + return 0; } // print log @@ -664,6 +649,8 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries) default:msgstat="Unknown test status "; } + retval+=errorfound; + sprintf(percent,"%1d0%%",(log->selfteststatus)&0xf); if (log->lbafirstfailure==0xffffffff || log->lbafirstfailure==0x00000000) sprintf(firstlba,"%s",""); @@ -671,18 +658,21 @@ void ataPrintSmartSelfTestlog (struct ata_smart_selftestlog data,int allentries) sprintf(firstlba,"0x%08x",log->lbafirstfailure); if (noheaderprinted && (allentries || errorfound)){ - printf("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); + pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); noheaderprinted=0; } if (allentries || errorfound) - printf("#%2d %s %s %s %8u %s\n",21-i,msgtest,msgstat, + pout("#%2d %s %s %s %8u %s\n",21-i,msgtest,msgstat, percent,log->timestamp,firstlba); } - else - return; + else { + pout("\n"); + return retval; + } } - return; + pout("\n"); + return retval; } void ataPseudoCheckSmart ( struct ata_smart_values data, @@ -695,11 +685,11 @@ void ataPseudoCheckSmart ( struct ata_smart_values data, data.vendor_attributes[i].status.flag.prefailure && (data.vendor_attributes[i].current <= thresholds.thres_entries[i].threshold) && (thresholds.thres_entries[i].threshold != 0xFE)){ - printf("Attribute ID %i Failed\n",data.vendor_attributes[i].id); + pout("Attribute ID %i Failed\n",data.vendor_attributes[i].id); failed = 1; } } - printf("%s\n", ( failed )? + pout("%s\n", ( failed )? "SMART overall-health self-assessment test result: FAILED!\n" "Drive failure expected in less than 24 hours. SAVE ALL DATA": "SMART overall-health self-assessment test result: PASSED"); @@ -806,7 +796,7 @@ void ataPrintSmartAttribName ( unsigned char id ){ name="Unknown_Attribute"; break; } - printf("%3d %-23s",id,name); + pout("%3d %-23s",id,name); } /**** @@ -827,66 +817,69 @@ int ataPrintMain (int fd){ // 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"); + pout("Smartctl: Hard Drive Read Identity Failed\n\n"); returnval|=FAILID; } // Print most drive identity information if requested if (driveinfo){ - printf("\n=== START OF INFORMATION SECTION ===\n"); + pout("=== START OF INFORMATION SECTION ===\n"); ataPrintDriveInfo(drive); } // now check if drive supports SMART; otherwise time to exit if (!ataSmartSupport(drive)){ - printf("SMART support is: Unavailable - device lacks SMART capability.\n"); - printf(" Checking to be sure by trying SMART ENABLE command.\n"); + pout("SMART support is: Unavailable - device lacks SMART capability.\n"); + pout(" Checking to be sure by trying SMART ENABLE command.\n"); if (ataEnableSmart(fd)){ - printf(" No SMART functionality found. Sorry.\n"); + pout(" No SMART functionality found. Sorry.\n"); return returnval|FAILSMART; } else - printf(" SMART appears to work. Continuing.\n"); + pout(" SMART appears to work. Continuing.\n"); + if (!driveinfo) pout("\n"); } // Now print remaining drive info: is SMART enabled? if (driveinfo){ - printf("SMART support is: Available - device has SMART capability.\n"); + pout("SMART support is: Available - device has SMART capability.\n"); if (ataDoesSmartWork(fd)) - printf("SMART support is: Enabled\n"); + pout("SMART support is: Enabled\n"); else - printf("SMART support is: Disabled\n"); + pout("SMART support is: Disabled\n"); + pout("\n"); } + // START OF THE ENABLE/DISABLE SECTION OF THE CODE if (smartenable || smartdisable || smartautosaveenable || smartautosavedisable || smartautoofflineenable || smartautoofflinedisable) - printf("\n=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); + pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); // Enable/Disable SMART commands if (smartenable){ if (ataEnableSmart(fd)) { - printf("Smartctl: SMART Enable Failed.\n\n"); + pout("Smartctl: SMART Enable Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Enabled.\n"); + pout("SMART Enabled.\n"); } // From here on, every command requires that SMART be enabled... if (!ataDoesSmartWork(fd)) { - printf("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE ); + pout("SMART Disabled. Use option -%c to enable it.\n", SMARTENABLE ); return returnval; } // Turn off SMART on device if (smartdisable){ if (ataDisableSmart(fd)) { - printf( "Smartctl: SMART Disable Failed.\n\n"); + pout( "Smartctl: SMART Disable Failed.\n\n"); returnval|=FAILSMART; } - printf("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE); + pout("SMART Disabled. Use option -%c to enable it.\n",SMARTENABLE); return returnval; } @@ -898,84 +891,95 @@ int ataPrintMain (int fd){ // Enable/Disable Auto-save attributes if (smartautosaveenable){ if (ataEnableAutoSave(fd)){ - printf( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n"); + pout( "Smartctl: SMART Enable Attribute Autosave Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Attribute Autosave Enabled.\n"); + pout("SMART Attribute Autosave Enabled.\n"); } if (smartautosavedisable){ if (ataDisableAutoSave(fd)){ - printf( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n"); + pout( "Smartctl: SMART Disable Attribute Autosave Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Attribute Autosave Disabled.\n"); + pout("SMART Attribute Autosave Disabled.\n"); } // for everything else read values and thresholds are needed if (ataReadSmartValues(fd, &smartval)){ - printf("Smartctl: SMART Read Values failed.\n\n"); + pout("Smartctl: SMART Read Values failed.\n\n"); returnval|=FAILSMART; } if (ataReadSmartThresholds(fd, &smartthres)){ - printf("Smartctl: SMART Read Thresholds failed.\n\n"); + pout("Smartctl: SMART Read Thresholds failed.\n\n"); returnval|=FAILSMART; } // Enable/Disable Off-line testing if (smartautoofflineenable){ if (!isSupportAutomaticTimer(smartval)){ - printf("Device does not support SMART Automatic Timers.\n\n"); + pout("Warning: device does not support SMART Automatic Timers.\n\n"); } if (ataEnableAutoOffline(fd)){ - printf( "Smartctl: SMART Enable Automatic Offline Failed.\n\n"); + pout( "Smartctl: SMART Enable Automatic Offline Failed.\n\n"); returnval|=FAILSMART; } else - printf ("SMART Automatic Offline Testing Enabled every four hours.\n"); + pout ("SMART Automatic Offline Testing Enabled every four hours.\n"); } if (smartautoofflinedisable){ if (!isSupportAutomaticTimer(smartval)){ - printf("Device does not support SMART Automatic Timers.\n\n"); + pout("Warning: device does not support SMART Automatic Timers.\n\n"); } if (ataDisableAutoOffline(fd)){ - printf("Smartctl: SMART Disable Automatic Offline Failed.\n\n"); + pout("Smartctl: SMART Disable Automatic Offline Failed.\n\n"); returnval|=FAILSMART; } else - printf("SMART Automatic Offline Testing Disabled.\n"); + pout("SMART Automatic Offline Testing Disabled.\n"); } + // all this for a newline! + if (smartenable || smartdisable || + smartautosaveenable || smartautosavedisable || + smartautoofflineenable || smartautoofflinedisable) + pout("\n"); + // START OF READ-ONLY OPTIONS APART FROM -p and -i if (checksmart || generalsmartvalues || smartvendorattrib || smarterrorlog || smartselftestlog) - printf("\n=== START OF READ SMART DATA SECTION ===\n"); + pout("=== START OF READ SMART DATA SECTION ===\n"); // Check SMART status (use previously returned value) if (checksmart){ if (code) { - printf("SMART overall-health self-assessment test result: FAILED!\n" + QUIETON; + pout("SMART overall-health self-assessment test result: FAILED!\n" "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); + QUIETOFF; if (ataCheckSmart(smartval, smartthres,1)){ + QUIETON; returnval|=FAILATTR; - printf("Failed Attributes:\n"); + pout("Failed Attributes:\n"); PrintSmartAttribWithThres(smartval, smartthres,1); } - else { - printf("No failed Attributes found.\n"); - } - printf("\n"); + else + pout("No failed Attributes found.\n\n"); returnval|=FAILSTATUS; + QUIETOFF; } else { - printf("SMART overall-health self-assessment test result: PASSED\n"); + pout("SMART overall-health self-assessment test result: PASSED\n"); if (ataCheckSmart(smartval, smartthres,0)){ - printf("Marginal attributes:\n"); + QUIETON; + pout("But please note the following marginal attributes:\n"); PrintSmartAttribWithThres(smartval, smartthres,2); returnval|=FAILAGE; } - printf("\n"); + else + pout("\n"); } + QUIETOFF; } // Print general SMART values @@ -983,32 +987,42 @@ int ataPrintMain (int fd){ ataPrintGeneralSmartValues(smartval); // Print vendor-specific attributes - if (smartvendorattrib) - PrintSmartAttribWithThres(smartval, smartthres,0); + if (smartvendorattrib){ + QUIETON; + PrintSmartAttribWithThres(smartval, smartthres,quietmode?2:0); + QUIETOFF; + } // Print SMART error log if (smarterrorlog){ if (!isSmartErrorLogCapable(smartval)) - printf("Device does not support Error Logging\n"); + pout("Warning: device does not support Error Logging\n"); if (ataReadErrorLog(fd, &smarterror)){ - printf("Smartctl: SMART Errorlog Read Failed\n"); + pout("Smartctl: SMART Errorlog Read Failed\n"); returnval|=FAILSMART; } - else + else { + QUIETON; ataPrintSmartErrorlog(smarterror); + QUIETOFF; + } } // Print SMART self-test log if (smartselftestlog){ if (!isSmartErrorLogCapable(smartval)) - printf("Device does not support Self Test Logging\n"); + pout("Warning: device does not support Self Test Logging\n"); else { if(ataReadSelfTestLog(fd, &smartselftest)){ - printf("Smartctl: SMART Self Test Log Read Failed\n"); + pout("Smartctl: SMART Self Test Log Read Failed\n"); returnval|=FAILSMART; } - else - ataPrintSmartSelfTestlog(smartselftest,1); + else { + QUIETON; + if (ataPrintSmartSelfTestlog(smartselftest,!quietmode)) + returnval|=FAILLOG; + QUIETOFF; + } } } @@ -1016,13 +1030,13 @@ int ataPrintMain (int fd){ if (testcase==-1) return returnval; - printf("\n=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n"); + pout("=== 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"); + pout("Warning: device does not support Execute Off-Line Immediate function.\n\n"); else if (!isSupportSelfTest(smartval)) - printf ("ERROR: device does not support Self-Test functions.\n\n"); + pout ("Warning: device does not support Self-Test functions.\n\n"); // Now do the test if (ataSmartTest(fd, testcase)) @@ -1030,11 +1044,11 @@ int ataPrintMain (int fd){ // Tell user how long test will take to complete if ((timewait=TestTime(smartval,testcase))){ - printf ("Please wait %d %s for test to complete.\n", + pout ("Please wait %d %s for test to complete.\n", timewait, testcase==OFFLINE_FULL_SCAN?"seconds":"minutes"); if (testcase!=SHORT_CAPTIVE_SELF_TEST && testcase!=EXTEND_CAPTIVE_SELF_TEST) - printf ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT); + pout ("Use smartctl -%c to abort test.\n", SMARTSELFTESTABORT); } return returnval; } diff --git a/sm5/ataprint.h b/sm5/ataprint.h index afd9ea46a42dcf322aead97f72b1659f14792737..8906bd05283a1d39efadefde258d974fd356dd56 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.10 2002/10/22 20:35:42 ballen4705 Exp $\n" +#define CVSID2 "$Id: ataprint.h,v 1.11 2002/10/23 12:24:24 ballen4705 Exp $\n" #endif #include <stdio.h> @@ -49,7 +49,8 @@ void PrintSmartAttribWithThres (struct ata_smart_values data, struct ata_smart_thresholds thresholds, int onlyfailed); -void ataPrintSmartSelfTestlog(struct ata_smart_selftestlog data, int allentries); +// returns number of entries that had logged errors +int ataPrintSmartSelfTestlog(struct ata_smart_selftestlog data, int allentries); void ataPseudoCheckSmart (struct ata_smart_values , struct ata_smart_thresholds ); diff --git a/sm5/extern.h b/sm5/extern.h index 0d50f27059f9cf0a5c72f2f376820cd297f62898..d9b0f9ee4ab02ec57bf3e7dcd01a518ed1c64e3a 100644 --- a/sm5/extern.h +++ b/sm5/extern.h @@ -27,7 +27,7 @@ #ifndef CVSID3 -#define CVSID3 "$Id: extern.h,v 1.7 2002/10/22 09:44:55 ballen4705 Exp $\n" +#define CVSID3 "$Id: extern.h,v 1.8 2002/10/23 12:24:24 ballen4705 Exp $\n" #endif extern unsigned char driveinfo; @@ -51,4 +51,6 @@ extern unsigned char smartautosaveenable; extern unsigned char smartautosavedisable; extern unsigned char smart009minutes; extern int testcase; +extern unsigned char quietmode; +extern unsigned char veryquietmode; #endif diff --git a/sm5/smartctl.8 b/sm5/smartctl.8 index a5659bae192eb4bd8ded8256c9f50620f3f12cba..1f2529f17d6f5a1301edc5a9ecb90826a91d1e99 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.14 2002/10/22 16:49:16 ballen4705 Exp $ +\# $Id: smartctl.8,v 1.15 2002/10/23 12:24:24 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/10/22 16:49:16 $" "smartmontools-5.0" +.TH SMARTCTL 8 "$Date: 2002/10/23 12:24:24 $" "smartmontools-5.0" .SH NAME smartctl \- S.M.A.R.T. control utility .SH SYNOPSIS -.B smartctl \-[piaedtTfFcgvlLm[O|S|s|X|x|A]] device +.B smartctl \-[piqQaedtTfFcgvlLm[O|S|s|X|x|A]] device .SH DESCRIPTION .B smartctl @@ -34,7 +34,11 @@ below) .B smartctl is a command line utility designed to perform S.M.A.R.T. tasks such as printing the S.M.A.R.T. self-test and error logs, and enabling and -disabling S.M.A.R.T. automatic testing. +disabling S.M.A.R.T. automatic testing. Note: if the user issues a +S.M.A.R.T. command that is (apparently) not implemented by the device, +we print a warning message but issue the command anyway. This should +not cause problems: unimplemented S.M.A.R.T. commands issued to a +drive are ignored and return an error. .B smartctl also provides limited TapeAlerts support for some SCSI tape drives and @@ -81,6 +85,21 @@ 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 q +Quiet mode: Only print: For the '\-l' option, +errors recorded in the SMART error log; For the '\-L' option, +errors recorded in the device self-test log; For the '\-c' +SMART "disk failing" status or device attributes +(pre-failure or usage) which failed either now or +in the past; For the '\-v' option device attributes (pre-failure or usage) +which failed either now or in the past. +.TP +.B Q +Very Quiet mode: Print no ouput. The only way to learn about what was +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. @@ -317,16 +336,35 @@ 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 +value are as follows: +.TP +.B Bit 0: +Command line did not parse. +.TP +.B Bit 1: +Device open failed, or device did not return an IDENTIFY DEVICE structure. +.TP +.B Bit 2: +Some SMART command to the disk failed. +.TP +.B Bit 3: +SMART status check returned "DISK FAILING". +.TP +.B Bit 4: +SMART status check returned "DISK OK" but we found prefail attributes <= threshold. +.TP +.B 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. +past. +.TP +.B Bit 6: +The device error log contains records of errors. +.TP +.B Bit 7: +The device self-test log contains records of errors. .PP .SH AUTHOR Bruce Allen @@ -401,4 +439,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.14 2002/10/22 16:49:16 ballen4705 Exp $ +$Id: smartctl.8,v 1.15 2002/10/23 12:24:24 ballen4705 Exp $ diff --git a/sm5/smartctl.c b/sm5/smartctl.c index 3e17e69704e931e95d9569940565756eb75b3ab9..14b1387de82e471501906ab681c06fd5115ac536 100644 --- a/sm5/smartctl.c +++ b/sm5/smartctl.c @@ -30,6 +30,7 @@ #include <sys/fcntl.h> #include <sys/types.h> #include <string.h> +#include <stdarg.h> #include "smartctl.h" #include "atacmds.h" #include "ataprint.h" @@ -37,7 +38,7 @@ #include "scsiprint.h" extern const char *CVSid1, *CVSid2, *CVSid4, *CVSid5; -const char* CVSid6="$Id: smartctl.c,v 1.14 2002/10/22 16:49:16 ballen4705 Exp $\n" +const char* CVSid6="$Id: smartctl.c,v 1.15 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" CVSID1 "\t" CVSID2 "\t" CVSID4 "\t" CVSID5 "\t" CVSID6 ; unsigned char driveinfo = FALSE; @@ -61,28 +62,115 @@ unsigned char smartautosaveenable = FALSE; unsigned char smartautosavedisable = FALSE; unsigned char printcopyleft = FALSE; unsigned char smart009minutes = FALSE; +unsigned char quietmode = FALSE; +unsigned char veryquietmode = FALSE; int testcase = -1; -/* void Usage (void) - prints help information for command syntax */ +void printslogan(){ + pout("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION); + pout("Home page of smartctl is %s\n\n",PROJECTHOME); + return; +} + + + +int massagecvs(char *out,const char *in){ + char filename[128], version[128], date[128]; + int i=0; + const char *savein=in; + + // skip to I of $Id: + while (*in !='\0' && *in!='I') + in++; + + // skip to start of filename + if (!*in) + return 0; + in+=4; + // copy filename + i=0; + while (i<100 && *in!=',' && *in) + filename[i++]=*in++; + filename[i]='\0'; + if (!*in) + return 0; + // skip ,v and space + in+=3; + i=0; + // copy version number + while (i<100 && *in!=' ' && *in) + version[i++]=*in++; + version[i]='\0'; + if (!*in) + return 0; + + // skip space + in++; + // copy date + i=0; + while (i<100 && *in!=' ' && *in) + date[i++]=*in++; + date[i]='\0'; + + sprintf(out,"%-13s revision: %-6s date: %-15s", filename, version, date); + return in-savein; +} + +// prints a single set of CVS ids +void printone(const char *cvsid){ + char strings[512]; + const char *here; + int len,line=1; + here=cvsid; + while ((len=massagecvs(strings,here))){ + switch (line++){ + case 1: + pout("Module:"); + break; + default: + pout(" uses:"); + } + pout(" %s\n",strings); + here+=len; + } + return; +} + +void printcopy(){ + pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n"); + pout("is free software, and you are welcome to redistribute it\n"); + pout("under the terms of the GNU General Public License Version 2.\n"); + pout("See http://www.gnu.org for further details.\n\n"); + pout("CVS version IDs of files used to build this code are:\n"); + printone(CVSid6); + printone(CVSid1); + printone(CVSid2); + printone(CVSid4); + printone(CVSid5); + return; +} + +/* void prints help information for command syntax */ void Usage ( void){ printf( "Usage: smartctl -[options] [device]\n\n"); printf( "Read Only Options:\n"); printf( "\t\t%c\t\tShow version, copyright and license information\n", PRINTCOPYLEFT); - printf( "\t\t%c\t\tShow all S.M.A.R.T. Information (ATA and SCSI)\n", SMARTVERBOSEALL); - printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Info (ATA and SCSI)\n", DRIVEINFO); - printf( "\t\t%c\t\tShow S.M.A.R.T. Status (ATA and SCSI)\n", CHECKSMART); - printf( "\t\t%c\t\tShow S.M.A.R.T. General Attributes (ATA Only)\n", GENERALSMARTVALUES); - printf( "\t\t%c\t\tShow S.M.A.R.T. Vendor Attributes (ATA Only)\n", SMARTVENDORATTRIB); - printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Error Log (ATA Only\n", SMARTERRORLOG); - printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Self Test Log (ATA Only)\n", SMARTSELFTESTLOG); + printf( "\t\t%c\t\tShow all S.M.A.R.T. Information (ATA and SCSI)\n", SMARTVERBOSEALL); + printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Info (ATA and SCSI)\n", DRIVEINFO); + printf( "\t\t%c\t\tShow S.M.A.R.T. Status (ATA and SCSI)\n", CHECKSMART); + printf( "\t\t%c\t\tShow S.M.A.R.T. General Attributes (ATA Only)\n", GENERALSMARTVALUES); + printf( "\t\t%c\t\tShow S.M.A.R.T. Vendor Attributes (ATA Only)\n", SMARTVENDORATTRIB); + printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Error Log (ATA Only\n", SMARTERRORLOG); + printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Self Test Log (ATA Only)\n", SMARTSELFTESTLOG); + printf( "\t\t%c\t\tQuiet: only show SMART drive errors (ATA Only)\n", QUIETMODE); + printf( "\t\t%c\t\tVery Quiet: no display, use exit status (ATA Only)\n", VERYQUIETMODE); printf( "\n"); printf( "Vendor-specific Display Options:\n"); - printf( "\t\t%c\t\tRaw Attribute 009 is minutes (ATA Only)\n", SMART009MINUTES); + printf( "\t\t%c\t\tRaw Attribute 009 is minutes (ATA Only)\n", SMART009MINUTES); printf( "\n"); printf( "Enable/Disable Options:\n"); printf( "\t\t%c\t\tEnable S.M.A.R.T. data collection (ATA and SCSI)\n",SMARTENABLE); @@ -104,7 +192,6 @@ void Usage ( void){ printf("\tsmartctl -a /dev/hda (Prints all S.M.A.R.T. information)\n"); printf("\tsmartctl -X /dev/hda (Executes extended disk self-test)\n\n"); printf("Please see the man pages or %s for further information.\n",PROJECTHOME); - } const char opts[] = { @@ -113,7 +200,7 @@ const char opts[] = { SMARTENABLE, SMARTAUTOOFFLINEENABLE, SMARTAUTOOFFLINEDISABLE, SMARTEXEOFFIMMEDIATE, SMARTSHORTSELFTEST, SMARTEXTENDSELFTEST, SMARTSHORTCAPSELFTEST, SMARTEXTENDCAPSELFTEST, SMARTSELFTESTABORT, - SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,'\0' + SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,QUIETMODE,VERYQUIETMODE,'\0' }; /* Takes command options and sets features to be run */ @@ -125,6 +212,14 @@ void ParseOpts (int argc, char** argv){ opterr=1; while (-1 != (optchar = getopt(argc, argv, opts))) { switch (optchar){ + case QUIETMODE: + quietmode=TRUE; + veryquietmode=TRUE; + break; + case VERYQUIETMODE: + quietmode=FALSE; + veryquietmode=TRUE; + break; case SMART009MINUTES: smart009minutes=TRUE; break; @@ -200,43 +295,60 @@ void ParseOpts (int argc, char** argv){ testcase=ABORT_SELF_TEST; break; default: + veryquietmode=FALSE; + printslogan(); Usage(); exit(FAILCMD); } - - if ( (smartexeoffimmediate + smartshortselftest + - smartextendselftest + smartshortcapselftest + - smartextendcapselftest +smartselftestabort ) > 1){ - Usage(); - printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n"); - exit(FAILCMD); - } } + // error message if user has asked for more than one test + if (1<(smartexeoffimmediate+smartshortselftest+smartextendselftest+ + smartshortcapselftest+smartextendcapselftest+smartselftestabort)){ + veryquietmode=FALSE; + printslogan(); + Usage(); + printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n"); + exit(FAILCMD); + } + + // From here on, normal operations... + printslogan(); + + // Print Copyright/License info if needed + if (printcopyleft){ + printcopy(); + if (argc==2) + exit(0); + } } -/* Main Program */ +// Printing function (controlled by global veryquietmode) +void pout(char *fmt, ...){ + va_list ap; + + // initialize variable argument list + va_start(ap,fmt); + if (veryquietmode){ + va_end(ap); + return; + } + + // print out + vprintf(fmt,ap); + va_end(ap); + return; +} + + +/* Main Program */ int main (int argc, char **argv){ 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); - - // Print Copyright/License info if needed - if (printcopyleft){ - printf("\nsmartctl comes with ABSOLUTELY NO WARRANTY. This\n"); - printf("is free software, and you are welcome to redistribute it\n"); - printf("under the terms of the GNU General Public License Version 2.\n"); - 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) - return 0; - } - + // Further argument checking if (argc != 3){ Usage(); @@ -246,13 +358,13 @@ int main (int argc, char **argv){ // open device - read-only mode is enough to issue needed commands fd = open(device=argv[2], O_RDONLY); - if (fd< 0) { - perror ("Smartctl device open failed:"); + if (fd<0) { + perror("Smartctl device open failed"); return FAILDEV; } if (device[5] == 'h') - retval=ataPrintMain(fd ); + retval=ataPrintMain(fd); else if (device[5] == 's') scsiPrintMain (fd); else { diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp index 467badd2bea195ed5d13593967522b62e65974d3..a52c8386b8042b8fc27853dab175a463dce4e011 100644 --- a/sm5/smartctl.cpp +++ b/sm5/smartctl.cpp @@ -30,6 +30,7 @@ #include <sys/fcntl.h> #include <sys/types.h> #include <string.h> +#include <stdarg.h> #include "smartctl.h" #include "atacmds.h" #include "ataprint.h" @@ -37,7 +38,7 @@ #include "scsiprint.h" extern const char *CVSid1, *CVSid2, *CVSid4, *CVSid5; -const char* CVSid6="$Id: smartctl.cpp,v 1.14 2002/10/22 16:49:16 ballen4705 Exp $\n" +const char* CVSid6="$Id: smartctl.cpp,v 1.15 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" CVSID1 "\t" CVSID2 "\t" CVSID4 "\t" CVSID5 "\t" CVSID6 ; unsigned char driveinfo = FALSE; @@ -61,28 +62,115 @@ unsigned char smartautosaveenable = FALSE; unsigned char smartautosavedisable = FALSE; unsigned char printcopyleft = FALSE; unsigned char smart009minutes = FALSE; +unsigned char quietmode = FALSE; +unsigned char veryquietmode = FALSE; int testcase = -1; -/* void Usage (void) - prints help information for command syntax */ +void printslogan(){ + pout("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION); + pout("Home page of smartctl is %s\n\n",PROJECTHOME); + return; +} + + + +int massagecvs(char *out,const char *in){ + char filename[128], version[128], date[128]; + int i=0; + const char *savein=in; + + // skip to I of $Id: + while (*in !='\0' && *in!='I') + in++; + + // skip to start of filename + if (!*in) + return 0; + in+=4; + // copy filename + i=0; + while (i<100 && *in!=',' && *in) + filename[i++]=*in++; + filename[i]='\0'; + if (!*in) + return 0; + // skip ,v and space + in+=3; + i=0; + // copy version number + while (i<100 && *in!=' ' && *in) + version[i++]=*in++; + version[i]='\0'; + if (!*in) + return 0; + + // skip space + in++; + // copy date + i=0; + while (i<100 && *in!=' ' && *in) + date[i++]=*in++; + date[i]='\0'; + + sprintf(out,"%-13s revision: %-6s date: %-15s", filename, version, date); + return in-savein; +} + +// prints a single set of CVS ids +void printone(const char *cvsid){ + char strings[512]; + const char *here; + int len,line=1; + here=cvsid; + while ((len=massagecvs(strings,here))){ + switch (line++){ + case 1: + pout("Module:"); + break; + default: + pout(" uses:"); + } + pout(" %s\n",strings); + here+=len; + } + return; +} + +void printcopy(){ + pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n"); + pout("is free software, and you are welcome to redistribute it\n"); + pout("under the terms of the GNU General Public License Version 2.\n"); + pout("See http://www.gnu.org for further details.\n\n"); + pout("CVS version IDs of files used to build this code are:\n"); + printone(CVSid6); + printone(CVSid1); + printone(CVSid2); + printone(CVSid4); + printone(CVSid5); + return; +} + +/* void prints help information for command syntax */ void Usage ( void){ printf( "Usage: smartctl -[options] [device]\n\n"); printf( "Read Only Options:\n"); printf( "\t\t%c\t\tShow version, copyright and license information\n", PRINTCOPYLEFT); - printf( "\t\t%c\t\tShow all S.M.A.R.T. Information (ATA and SCSI)\n", SMARTVERBOSEALL); - printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Info (ATA and SCSI)\n", DRIVEINFO); - printf( "\t\t%c\t\tShow S.M.A.R.T. Status (ATA and SCSI)\n", CHECKSMART); - printf( "\t\t%c\t\tShow S.M.A.R.T. General Attributes (ATA Only)\n", GENERALSMARTVALUES); - printf( "\t\t%c\t\tShow S.M.A.R.T. Vendor Attributes (ATA Only)\n", SMARTVENDORATTRIB); - printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Error Log (ATA Only\n", SMARTERRORLOG); - printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Self Test Log (ATA Only)\n", SMARTSELFTESTLOG); + printf( "\t\t%c\t\tShow all S.M.A.R.T. Information (ATA and SCSI)\n", SMARTVERBOSEALL); + printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Info (ATA and SCSI)\n", DRIVEINFO); + printf( "\t\t%c\t\tShow S.M.A.R.T. Status (ATA and SCSI)\n", CHECKSMART); + printf( "\t\t%c\t\tShow S.M.A.R.T. General Attributes (ATA Only)\n", GENERALSMARTVALUES); + printf( "\t\t%c\t\tShow S.M.A.R.T. Vendor Attributes (ATA Only)\n", SMARTVENDORATTRIB); + printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Error Log (ATA Only\n", SMARTERRORLOG); + printf( "\t\t%c\t\tShow S.M.A.R.T. Drive Self Test Log (ATA Only)\n", SMARTSELFTESTLOG); + printf( "\t\t%c\t\tQuiet: only show SMART drive errors (ATA Only)\n", QUIETMODE); + printf( "\t\t%c\t\tVery Quiet: no display, use exit status (ATA Only)\n", VERYQUIETMODE); printf( "\n"); printf( "Vendor-specific Display Options:\n"); - printf( "\t\t%c\t\tRaw Attribute 009 is minutes (ATA Only)\n", SMART009MINUTES); + printf( "\t\t%c\t\tRaw Attribute 009 is minutes (ATA Only)\n", SMART009MINUTES); printf( "\n"); printf( "Enable/Disable Options:\n"); printf( "\t\t%c\t\tEnable S.M.A.R.T. data collection (ATA and SCSI)\n",SMARTENABLE); @@ -104,7 +192,6 @@ void Usage ( void){ printf("\tsmartctl -a /dev/hda (Prints all S.M.A.R.T. information)\n"); printf("\tsmartctl -X /dev/hda (Executes extended disk self-test)\n\n"); printf("Please see the man pages or %s for further information.\n",PROJECTHOME); - } const char opts[] = { @@ -113,7 +200,7 @@ const char opts[] = { SMARTENABLE, SMARTAUTOOFFLINEENABLE, SMARTAUTOOFFLINEDISABLE, SMARTEXEOFFIMMEDIATE, SMARTSHORTSELFTEST, SMARTEXTENDSELFTEST, SMARTSHORTCAPSELFTEST, SMARTEXTENDCAPSELFTEST, SMARTSELFTESTABORT, - SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,'\0' + SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,QUIETMODE,VERYQUIETMODE,'\0' }; /* Takes command options and sets features to be run */ @@ -125,6 +212,14 @@ void ParseOpts (int argc, char** argv){ opterr=1; while (-1 != (optchar = getopt(argc, argv, opts))) { switch (optchar){ + case QUIETMODE: + quietmode=TRUE; + veryquietmode=TRUE; + break; + case VERYQUIETMODE: + quietmode=FALSE; + veryquietmode=TRUE; + break; case SMART009MINUTES: smart009minutes=TRUE; break; @@ -200,43 +295,60 @@ void ParseOpts (int argc, char** argv){ testcase=ABORT_SELF_TEST; break; default: + veryquietmode=FALSE; + printslogan(); Usage(); exit(FAILCMD); } - - if ( (smartexeoffimmediate + smartshortselftest + - smartextendselftest + smartshortcapselftest + - smartextendcapselftest +smartselftestabort ) > 1){ - Usage(); - printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n"); - exit(FAILCMD); - } } + // error message if user has asked for more than one test + if (1<(smartexeoffimmediate+smartshortselftest+smartextendselftest+ + smartshortcapselftest+smartextendcapselftest+smartselftestabort)){ + veryquietmode=FALSE; + printslogan(); + Usage(); + printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n"); + exit(FAILCMD); + } + + // From here on, normal operations... + printslogan(); + + // Print Copyright/License info if needed + if (printcopyleft){ + printcopy(); + if (argc==2) + exit(0); + } } -/* Main Program */ +// Printing function (controlled by global veryquietmode) +void pout(char *fmt, ...){ + va_list ap; + + // initialize variable argument list + va_start(ap,fmt); + if (veryquietmode){ + va_end(ap); + return; + } + + // print out + vprintf(fmt,ap); + va_end(ap); + return; +} + + +/* Main Program */ int main (int argc, char **argv){ 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); - - // Print Copyright/License info if needed - if (printcopyleft){ - printf("\nsmartctl comes with ABSOLUTELY NO WARRANTY. This\n"); - printf("is free software, and you are welcome to redistribute it\n"); - printf("under the terms of the GNU General Public License Version 2.\n"); - 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) - return 0; - } - + // Further argument checking if (argc != 3){ Usage(); @@ -246,13 +358,13 @@ int main (int argc, char **argv){ // open device - read-only mode is enough to issue needed commands fd = open(device=argv[2], O_RDONLY); - if (fd< 0) { - perror ("Smartctl device open failed:"); + if (fd<0) { + perror("Smartctl device open failed"); return FAILDEV; } if (device[5] == 'h') - retval=ataPrintMain(fd ); + retval=ataPrintMain(fd); else if (device[5] == 's') scsiPrintMain (fd); else { diff --git a/sm5/smartctl.h b/sm5/smartctl.h index 41d7ead978cdb634051888565a2650183476d52a..cf815644e7ae002199151f1f8aabd144de61653e 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.8 2002/10/22 16:49:16 ballen4705 Exp $\n" +#define CVSID6 "$Id: smartctl.h,v 1.9 2002/10/23 12:24:24 ballen4705 Exp $\n" #endif /* Defines for command line options */ @@ -51,6 +51,8 @@ #define SMARTAUTOSAVEDISABLE 'F' #define PRINTCOPYLEFT 'p' #define SMART009MINUTES 'm' +#define QUIETMODE 'q' +#define VERYQUIETMODE 'Q' /* Boolean Values */ @@ -62,9 +64,10 @@ // command line did not parse #define FAILCMD (0x01<<0) -// device open failed +// device open failed or could not get identity info #define FAILDEV (0x01<<1) - +#define FAILID (0x01<<1) + // smart command failed #define FAILSMART (0x01<<2) @@ -78,7 +81,10 @@ // attributes have failed in the past #define FAILAGE (0x01<<5) -// Device ID failed -#define FAILID (0x01<<6) +// Device had Errors in the error log +#define FAILERR (0x01<<6) + +// Device had Errors in the self-test log +#define FAILLOG (0x01<<7) #endif diff --git a/sm5/smartd.c b/sm5/smartd.c index 92984b6882e7fa78ed5380b0220b65788425cbb3..e64a57685fadac2c8083aba214ac61adf840ed81 100644 --- a/sm5/smartd.c +++ b/sm5/smartd.c @@ -36,7 +36,7 @@ #include "smartd.h" extern const char *CVSid1, *CVSid2; -const char *CVSid3="$Id: smartd.c,v 1.13 2002/10/22 14:57:43 ballen4705 Exp $\n" +const char *CVSid3="$Id: smartd.c,v 1.14 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" CVSID1 "\t" CVSID4 "\t" CVSID7 ; int daemon_init(void){ @@ -70,6 +70,22 @@ void printout(int priority,char *fmt, ...){ return; } +// Printing function for atacmds +void pout(char *fmt, ...){ + va_list ap; + // initialize variable argument list + va_start(ap,fmt); + va_end(ap); + return; +#if (0) + // print out + vprintf(fmt,ap); + va_end(ap); + return; +#endif +} + + /* prints help information for command syntax */ void Usage ( void){ printout(LOG_INFO,"smartd version %d.%d-%d - S.M.A.R.T. Daemon\n", diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp index 012bd79712769e26ab382673aa27ae41e27a19d0..c400f374bfca679edde04d054c121621c1fad5f9 100644 --- a/sm5/smartd.cpp +++ b/sm5/smartd.cpp @@ -36,7 +36,7 @@ #include "smartd.h" extern const char *CVSid1, *CVSid2; -const char *CVSid3="$Id: smartd.cpp,v 1.13 2002/10/22 14:57:43 ballen4705 Exp $\n" +const char *CVSid3="$Id: smartd.cpp,v 1.14 2002/10/23 12:24:24 ballen4705 Exp $\n" "\t" CVSID1 "\t" CVSID4 "\t" CVSID7 ; int daemon_init(void){ @@ -70,6 +70,22 @@ void printout(int priority,char *fmt, ...){ return; } +// Printing function for atacmds +void pout(char *fmt, ...){ + va_list ap; + // initialize variable argument list + va_start(ap,fmt); + va_end(ap); + return; +#if (0) + // print out + vprintf(fmt,ap); + va_end(ap); + return; +#endif +} + + /* prints help information for command syntax */ void Usage ( void){ printout(LOG_INFO,"smartd version %d.%d-%d - S.M.A.R.T. Daemon\n",