diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG index c8914c375c8b865cbff4278f83592a11f17a2374..c2eb63424704119336dc87dee242c2df5319341e 100644 --- a/sm5/CHANGELOG +++ b/sm5/CHANGELOG @@ -1,6 +1,6 @@ CHANGELOG for smartmontools -$Id: CHANGELOG,v 1.258 2003/11/16 22:49:14 pjwilliams Exp $ +$Id: CHANGELOG,v 1.259 2003/11/17 03:10:40 ballen4705 Exp $ Maintainers / Developers Key: [BA] Bruce Allen @@ -23,6 +23,10 @@ CURRENT DEVELOPMENT VERSION (see VERSION file in this directory): <ADDITIONS TO THE CHANGE LOG SHOULD BE ADDED HERE, PLEASE> + [BA] smartd: deviceclose()->CloseDevice(). Got rid of SCSIDEVELOPMENT + macro-enabled code. Added -W to list of gcc specific options to + always enable. Made code clean for -W warnings. + [PW] Added Maxtor DiamondMax VL 30 family to knowndrives table. [DG] scsi: add warning (when '-l error' active) if Control mode page @@ -94,10 +98,12 @@ CURRENT DEVELOPMENT VERSION (see VERSION file in this directory): devicescan code to also use glob(3). Also verified clean compile on a 4.7 FreeBSD system. - [BA] smartd: Modified device scan code to use glob(3). Previously it - appeared to have trouble when - scanning devices on an XFS file system, and used non-public - interface to directory entries. + [BA] smartd: Modified device scan code to use glob(3). Previously + it appeared to have trouble when scanning devices on an XFS + file system, and used non-public interface to directory + entries. Problems were also reported when /dev/ was on an + ext2/3 file system, but there was a JFS partition on the same + disk. [BA] Clearer error messages when device scanning finds no suitable devices. diff --git a/sm5/configure.in b/sm5/configure.in index 69c682e1f4c1ffb06793470f5ceb813c35e8d9b7..a73b27e6cb7a42716f8a04385812e29f09c687da 100644 --- a/sm5/configure.in +++ b/sm5/configure.in @@ -1,5 +1,5 @@ # -# $Id: configure.in,v 1.33 2003/11/02 18:15:53 ballen4705 Exp $ +# $Id: configure.in,v 1.34 2003/11/17 03:10:40 ballen4705 Exp $ # dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) @@ -7,7 +7,7 @@ AC_INIT(smartmontools, 5.24, smartmontools-support@lists.sourceforge.net) AC_CONFIG_SRCDIR(smartctl.c) smartmontools_configure_date=`date -u +"%Y/%m/%d %T %Z"` -smartmontools_cvs_tag=`echo '$Id: configure.in,v 1.33 2003/11/02 18:15:53 ballen4705 Exp $'` +smartmontools_cvs_tag=`echo '$Id: configure.in,v 1.34 2003/11/17 03:10:40 ballen4705 Exp $'` AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_ARGS, "$ac_configure_args", [smartmontools Configure Arguments]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_DATE, "$smartmontools_configure_date", [smartmontools Configure Date]) @@ -84,11 +84,15 @@ case "${host}" in AC_SUBST([os_libs], ['']) ;; esac -# Add -Wall if using gcc and its not already there specified. +dnl Add -Wall and -W if using gcc and its not already specified. if test "x$GCC" = "xyes"; then if test -z "`echo "$CFLAGS" | grep "\-Wall" 2> /dev/null`" ; then CFLAGS="$CFLAGS -Wall" fi +# In the next line, do NOT delete the 2 spaces inside double quotes. + if test -z "`echo "$CFLAGS " | grep "\-W " 2> /dev/null`" ; then + CFLAGS="$CFLAGS -W" + fi else dnl We are NOT using gcc, so enable host-specific compiler flags case "${host}" in diff --git a/sm5/extern.h b/sm5/extern.h index 4ec14a7c735be240dc4cee29645f1d18cd8fc913..b13f335b702c11fca12b8c8e6e2da9868d9535fe 100644 --- a/sm5/extern.h +++ b/sm5/extern.h @@ -25,7 +25,7 @@ #ifndef EXTERN_H_ #define EXTERN_H_ -#define EXTERN_H_CVSID "$Id: extern.h,v 1.30 2003/10/12 09:10:03 ballen4705 Exp $\n" +#define EXTERN_H_CVSID "$Id: extern.h,v 1.31 2003/11/17 03:10:40 ballen4705 Exp $\n" // For development and testing of Selective self-test code #define DEVELOP_SELECTIVE_SELF_TEST 0 @@ -43,14 +43,17 @@ typedef struct smartmonctrl_s { unsigned char checksmart; unsigned char smartvendorattrib; unsigned char generalsmartvalues; + unsigned char smartlogdirectory; unsigned char smartselftestlog; unsigned char smarterrorlog; unsigned char smartdisable; + unsigned char smartenable; unsigned char smartstatus; unsigned char smartexeoffimmediate; unsigned char smartshortselftest; + unsigned char smartextendselftest; unsigned char smartconveyanceselftest; #if DEVELOP_SELECTIVE_SELF_TEST @@ -58,6 +61,7 @@ typedef struct smartmonctrl_s { #endif unsigned char smartshortcapselftest; unsigned char smartextendcapselftest; + unsigned char smartconveyancecapselftest; #if DEVELOP_SELECTIVE_SELF_TEST unsigned char smartselectivecapselftest; @@ -65,25 +69,30 @@ typedef struct smartmonctrl_s { unsigned char smartselftestabort; unsigned char smartautoofflineenable; unsigned char smartautoofflinedisable; + unsigned char smartautosaveenable; unsigned char smartautosavedisable; #if DEVELOP_SELECTIVE_SELF_TEST unsigned long long smartselectivespan[5][2]; int smartselectivenumspans; #endif - int testcase; unsigned char quietmode; unsigned char veryquietmode; + + int testcase; + unsigned char permissive; unsigned char conservative; unsigned char checksumfail; unsigned char checksumignore; + unsigned char reportataioctl; unsigned char reportscsiioctl; unsigned char fixfirmwarebug; // If nonzero, escalade is 1 plus the disk number behind an escalade // controller unsigned char escalade; + unsigned char ignorepresets; unsigned char showpresets; // The i'th entry in this array will modify the printed meaning of @@ -92,6 +101,10 @@ typedef struct smartmonctrl_s { // attributedefs[i] is nonzero, it means that the i'th attribute has // a non-default meaning. See the ataPrintSmartAttribName and // and parse_attribute_def functions. + + char notused1; // make structure pack cleanly without holes + char notused2; + unsigned char attributedefs[256]; } smartmonctrl; diff --git a/sm5/os_linux.c b/sm5/os_linux.c index 29b566541b48cd6b1f98670edddd472b2e5f9375..4352aef32dfe05a7c33dc533abe6ca429eb0e2da 100644 --- a/sm5/os_linux.c +++ b/sm5/os_linux.c @@ -60,7 +60,7 @@ #include "smartd.h" #include "utility.h" -const char *os_XXXX_c_cvsid="$Id: os_linux.c,v 1.27 2003/11/16 12:20:14 dpgilbert Exp $" \ +const char *os_XXXX_c_cvsid="$Id: os_linux.c,v 1.28 2003/11/17 03:10:40 ballen4705 Exp $" \ ATACMDS_H_CVSID CONFIG_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID UTILITY_H_CVSID; // to hold onto exit code for atexit routine @@ -96,8 +96,10 @@ int deviceclose(int fd){ int get_dev_names(char*** names, const char* pattern, const char* name, int max) { int n = 0, retglob, i, lim; char** mp; - glob_t globbuf={0}; + glob_t globbuf; + memset(&globbuf, 0, sizeof(globbuf)); + // in case of non-clean exit *names=NULL; diff --git a/sm5/os_linux.cpp b/sm5/os_linux.cpp index 7e5b207b28fcdeb99361224b1c34294c28a2a43f..61377e49155f655291fc08c9e915d6f8503e1d23 100644 --- a/sm5/os_linux.cpp +++ b/sm5/os_linux.cpp @@ -60,7 +60,7 @@ #include "smartd.h" #include "utility.h" -const char *os_XXXX_c_cvsid="$Id: os_linux.cpp,v 1.27 2003/11/16 12:20:14 dpgilbert Exp $" \ +const char *os_XXXX_c_cvsid="$Id: os_linux.cpp,v 1.28 2003/11/17 03:10:40 ballen4705 Exp $" \ ATACMDS_H_CVSID CONFIG_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID UTILITY_H_CVSID; // to hold onto exit code for atexit routine @@ -96,8 +96,10 @@ int deviceclose(int fd){ int get_dev_names(char*** names, const char* pattern, const char* name, int max) { int n = 0, retglob, i, lim; char** mp; - glob_t globbuf={0}; + glob_t globbuf; + memset(&globbuf, 0, sizeof(globbuf)); + // in case of non-clean exit *names=NULL; diff --git a/sm5/scsiprint.c b/sm5/scsiprint.c index bfe5e1bab2b8958eada7340011341b4393b1beed..84abb83454f04fa355cd3a559e2292be38bb645f 100644 --- a/sm5/scsiprint.c +++ b/sm5/scsiprint.c @@ -40,7 +40,7 @@ #define GBUF_SIZE 65535 -const char* scsiprint_c_cvsid="$Id: scsiprint.c,v 1.60 2003/11/16 16:59:23 ballen4705 Exp $" +const char* scsiprint_c_cvsid="$Id: scsiprint.c,v 1.61 2003/11/17 03:10:40 ballen4705 Exp $" EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; // control block which points to external global control variables @@ -608,6 +608,22 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) memset(revision, 0, sizeof(revision)); strncpy(revision, (char *)&gBuf[32], 4); pout("Device: %s %s Version: %s\n", manufacturer, product, revision); + + /* + Doug: for a bad USB device, the code hangs in the following + line within scsiInquiryVpd(): + + status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); + + and within do_scsi_cmnd_io() it hangs in the line: + + status = ioctl(dev_fd, SCSI_IOCTL_SEND_COMMAND , &wrk); + + which never returns. Would it be possible to put in a + sanity check to detect such devices and exit with an error + message, before calling scsiInquiryVpd()? + + */ if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) { /* should use VPD page 0x83 and fall back to this page (0x80) * if 0x83 not supported. NAA requires a lot of decoding code */ diff --git a/sm5/scsiprint.cpp b/sm5/scsiprint.cpp index 483cc90c493013b1bf42132d7ccf5b3c751ff22e..236d3efbc580d4a9498721de718f83dfe4f9853e 100644 --- a/sm5/scsiprint.cpp +++ b/sm5/scsiprint.cpp @@ -40,7 +40,7 @@ #define GBUF_SIZE 65535 -const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.60 2003/11/16 16:59:23 ballen4705 Exp $" +const char* scsiprint_c_cvsid="$Id: scsiprint.cpp,v 1.61 2003/11/17 03:10:40 ballen4705 Exp $" EXTERN_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID; // control block which points to external global control variables @@ -608,6 +608,22 @@ static int scsiGetDriveInfo(int device, UINT8 * peripheral_type, int all) memset(revision, 0, sizeof(revision)); strncpy(revision, (char *)&gBuf[32], 4); pout("Device: %s %s Version: %s\n", manufacturer, product, revision); + + /* + Doug: for a bad USB device, the code hangs in the following + line within scsiInquiryVpd(): + + status = do_scsi_cmnd_io(device, &io_hdr, con->reportscsiioctl); + + and within do_scsi_cmnd_io() it hangs in the line: + + status = ioctl(dev_fd, SCSI_IOCTL_SEND_COMMAND , &wrk); + + which never returns. Would it be possible to put in a + sanity check to detect such devices and exit with an error + message, before calling scsiInquiryVpd()? + + */ if (0 == (err = scsiInquiryVpd(device, 0x80, gBuf, 64))) { /* should use VPD page 0x83 and fall back to this page (0x80) * if 0x83 not supported. NAA requires a lot of decoding code */ diff --git a/sm5/smartd.c b/sm5/smartd.c index 29639b5e65877e276e4bfad77d2a0a30dc487bfe..04b8dcfa3b7fad56c4de106dec25a83c1f76cf70 100644 --- a/sm5/smartd.c +++ b/sm5/smartd.c @@ -65,7 +65,7 @@ extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid; -const char *smartd_c_cvsid="$Id: smartd.c,v 1.239 2003/11/16 16:53:02 ballen4705 Exp $" +const char *smartd_c_cvsid="$Id: smartd.c,v 1.240 2003/11/17 03:10:40 ballen4705 Exp $" ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID UTILITY_H_CVSID; @@ -771,7 +771,7 @@ int ATADeviceScan(cfgfile *cfg){ else PrintOut(LOG_INFO,"Device: %s, packet devices [this device %s] not SMART capable\n", name, packetdevicetype(retid-1)); - deviceclose(fd); + CloseDevice(fd, name); return 2; } @@ -817,7 +817,7 @@ int ATADeviceScan(cfgfile *cfg){ } else { PrintOut(LOG_INFO,"Device: %s, to proceed anyway, use '-T permissive' Directive.\n",name); - deviceclose(fd); + CloseDevice(fd, name); return 2; } } @@ -825,7 +825,7 @@ int ATADeviceScan(cfgfile *cfg){ if (ataEnableSmart(fd)){ // Enable SMART command has failed PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); - deviceclose(fd); + CloseDevice(fd, name); return 2; } @@ -958,7 +958,7 @@ int ATADeviceScan(cfgfile *cfg){ // If no tests available or selected, return if (!(cfg->errorlog || cfg->selftest || cfg->smartcheck || cfg->usagefailed || cfg->prefail || cfg->usage)) { - deviceclose(fd); + CloseDevice(fd, name); return 3; } @@ -983,144 +983,131 @@ int ATADeviceScan(cfgfile *cfg){ // on success, return 0. On failure, return >0. Never return <0, // please. -static int SCSIDeviceScan(cfgfile *cfg) -{ - int k, fd, err; - char *device = cfg->name; - struct scsi_iec_mode_page iec; - UINT8 tBuf[64]; - - // should we try to register this as a SCSI device? - if (! cfg->tryscsi) - return 1; - // open the device - if ((fd = OpenDevice(device, "SCSI")) < 0) { -#ifdef SCSIDEVELOPMENT - PrintOut(LOG_WARNING, "Device: %s, skip\n", device); - return 0; -#else - return 1; -#endif - } - PrintOut(LOG_INFO,"Device: %s, opened\n", device); - - // check that it's ready for commands. IE stores its stuff on the media. - if ((err = scsiTestUnitReady(fd))) { - if (1 == err) - PrintOut(LOG_WARNING, "Device: %s, NOT READY (media absent, spun " - "down); skip\n", device); - else - PrintOut(LOG_ERR, "Device: %s, failed Test Unit Ready [err=%d]\n", - device, err); - deviceclose(fd); -#ifdef SCSIDEVELOPMENT - return 0; -#else - return 2; -#endif - } +static int SCSIDeviceScan(cfgfile *cfg) { + int k, fd, err; + char *device = cfg->name; + struct scsi_iec_mode_page iec; + UINT8 tBuf[64]; + + // should we try to register this as a SCSI device? + if (!cfg->tryscsi) + return 1; - if ((err = scsiFetchIECmpage(fd, &iec, cfg->modese_len))) { - PrintOut(LOG_WARNING, "Device: %s, Fetch of IEC (SMART) mode page " - "failed, err=%d, skip device\n", device, err); - deviceclose(fd); -#ifdef SCSIDEVELOPMENT - return 0; -#else - return 3; -#endif - } + // open the device + if ((fd = OpenDevice(device, "SCSI")) < 0) + return 1; + PrintOut(LOG_INFO,"Device: %s, opened\n", device); + + // check that device is ready for commands. IE stores its stuff on + // the media. + if ((err = scsiTestUnitReady(fd))) { + if (1 == err) + PrintOut(LOG_INFO, "Device: %s, NOT READY (media absent, spun down); skip device\n", device); else - cfg->modese_len = iec.modese_len; - - if (! scsi_IsExceptionControlEnabled(&iec)) { - PrintOut(LOG_WARNING, "Device: %s, IE (SMART) not enabled, " - "skip device\n", device); - deviceclose(fd); -#ifdef SCSIDEVELOPMENT - return 0; -#else - return 3; -#endif - } + PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err); + CloseDevice(fd, device); + return 2; + } + + // Badly-confirming USB storage devices should fail this check. + // Doug, is it possible that a device will have functionality that + // we might want to monitor with smartd (such as the Temperature + // page or Self-test log) but DOESN'T support the IE mode page? If + // so, we might want to make the 'skip device' contingent on a + // problem like the wrong length, rather than simply on + // non-existence of the page. + if ((err = scsiFetchIECmpage(fd, &iec, cfg->modese_len))) { + PrintOut(LOG_INFO, + "Device: %s, Fetch of IEC (SMART) mode page failed, err=%d, skip device\n", device, err); + CloseDevice(fd, device); + return 3; + } + else + cfg->modese_len = iec.modese_len; - // Device exists, and does SMART. Add to list - if (numdevscsi >= MAXSCSIDEVICES) { - PrintOut(LOG_ERR, "smartd has found more than MAXSCSIDEVICES=%d " - "SCSI devices.\n" "Recompile code from " PROJECTHOME - " with larger MAXSCSIDEVICES\n", (int)numdevscsi); -#ifdef SCSIDEVELOPMENT - deviceclose(fd); - return 0; -#else - EXIT(EXIT_CCONST); -#endif - } + // Doug should we try to enable IE if it's not already enabled? + // This is what the ATA code does: enables SMART on devices. + if (!scsi_IsExceptionControlEnabled(&iec)) { + PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n", device); + CloseDevice(fd, device); + return 3; + } + + // Device exists, and does SMART. Add to list + if (numdevscsi >= MAXSCSIDEVICES) { + PrintOut(LOG_CRIT, + "smartd has found more than MAXSCSIDEVICES=%d SCSI devices.\n" + "Recompile code from " PROJECTHOME " with larger MAXSCSIDEVICES\n", + (int)numdevscsi); + EXIT(EXIT_CCONST); + } + + // Flag that certain log pages are supported (information may be + // available from other sources). + if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, tBuf, sizeof(tBuf), 0)) { + for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { + switch (tBuf[k]) { + case TEMPERATURE_LPAGE: + cfg->TempPageSupported = 1; + break; + case IE_LPAGE: + cfg->SmartPageSupported = 1; + break; + default: + break; + } + } + } + + // record type of device + cfg->tryata = 0; + cfg->tryscsi = 1; + + // get rid of allocated memory only needed for ATA devices. These + // might have been allocated if the user specified Ignore options or + // other ATA-only Attribute-specific options on the DEVICESCAN line. + cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,__FILE__); + cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,__FILE__); + cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,__FILE__); + cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds),__LINE__,__FILE__); + + // Check if scsiCheckIE() is going to work + { + UINT8 asc = 0; + UINT8 ascq = 0; + UINT8 currenttemp = 0; + UINT8 triptemp = 0; - // now we can proceed to register the device - PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding " - "to \"monitor\" list.\n",device); - - // Flag that certain log pages are supported (information may be - // available from other sources). - if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, tBuf, sizeof(tBuf), 0)) { - for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { - switch (tBuf[k]) { - case TEMPERATURE_LPAGE: - cfg->TempPageSupported = 1; - break; - case IE_LPAGE: - cfg->SmartPageSupported = 1; - break; - default: - break; - } - } + if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, + &asc, &ascq, ¤ttemp, &triptemp)) { + PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device); + cfg->SuppressReport = 1; } - - // record number of device, type of device, increment device count - cfg->tryata = 0; - cfg->tryscsi = 1; - - // get rid of allocated memory only needed for ATA devices - cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,__FILE__); - cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,__FILE__); - cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,__FILE__); - cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds),__LINE__,__FILE__); - - // Check if scsiCheckIE() is going to work - { - UINT8 asc = 0; - UINT8 ascq = 0; - UINT8 currenttemp = 0; - UINT8 triptemp = 0; - - if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, - &asc, &ascq, ¤ttemp, &triptemp)) { - PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART" - " values\n", device); - cfg->SuppressReport = 1; - } + } + + // capability check: self-test-log + if (cfg->selftest){ + int retval=scsiCountFailedSelfTests(fd, 0); + if (retval<0) { + // no self-test log, turn off monitoring + PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-test Log.\n", device); + cfg->selftest=0; + cfg->selflogcount=0; + cfg->selfloghour=0; } - - // capability check: self-test-log - if (cfg->selftest){ - int retval=scsiCountFailedSelfTests(fd, 0); - if (retval<0) { - PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-test Log.\n", device); - cfg->selftest=0; - cfg->selflogcount=0; - cfg->selfloghour=0; - } - else { - cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); - cfg->selfloghour =SELFTEST_ERRORHOURS(retval); - } + else { + // register starting values to watch for changes + cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); + cfg->selfloghour =SELFTEST_ERRORHOURS(retval); } - - // close file descriptor - CloseDevice(fd, device); - return 0; + } + + // tell user we are registering device + PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device); + + // close file descriptor + CloseDevice(fd, device); + return 0; } // We compare old and new values of the n'th attribute. Note that n diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp index fa0bd593f0914b624b171aa094ec6d4a486b3310..de5ff7ac70e74cdd2327defd3a2b739686f9a78c 100644 --- a/sm5/smartd.cpp +++ b/sm5/smartd.cpp @@ -65,7 +65,7 @@ extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid; -const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.239 2003/11/16 16:53:02 ballen4705 Exp $" +const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.240 2003/11/17 03:10:40 ballen4705 Exp $" ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID UTILITY_H_CVSID; @@ -771,7 +771,7 @@ int ATADeviceScan(cfgfile *cfg){ else PrintOut(LOG_INFO,"Device: %s, packet devices [this device %s] not SMART capable\n", name, packetdevicetype(retid-1)); - deviceclose(fd); + CloseDevice(fd, name); return 2; } @@ -817,7 +817,7 @@ int ATADeviceScan(cfgfile *cfg){ } else { PrintOut(LOG_INFO,"Device: %s, to proceed anyway, use '-T permissive' Directive.\n",name); - deviceclose(fd); + CloseDevice(fd, name); return 2; } } @@ -825,7 +825,7 @@ int ATADeviceScan(cfgfile *cfg){ if (ataEnableSmart(fd)){ // Enable SMART command has failed PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); - deviceclose(fd); + CloseDevice(fd, name); return 2; } @@ -958,7 +958,7 @@ int ATADeviceScan(cfgfile *cfg){ // If no tests available or selected, return if (!(cfg->errorlog || cfg->selftest || cfg->smartcheck || cfg->usagefailed || cfg->prefail || cfg->usage)) { - deviceclose(fd); + CloseDevice(fd, name); return 3; } @@ -983,144 +983,131 @@ int ATADeviceScan(cfgfile *cfg){ // on success, return 0. On failure, return >0. Never return <0, // please. -static int SCSIDeviceScan(cfgfile *cfg) -{ - int k, fd, err; - char *device = cfg->name; - struct scsi_iec_mode_page iec; - UINT8 tBuf[64]; - - // should we try to register this as a SCSI device? - if (! cfg->tryscsi) - return 1; - // open the device - if ((fd = OpenDevice(device, "SCSI")) < 0) { -#ifdef SCSIDEVELOPMENT - PrintOut(LOG_WARNING, "Device: %s, skip\n", device); - return 0; -#else - return 1; -#endif - } - PrintOut(LOG_INFO,"Device: %s, opened\n", device); - - // check that it's ready for commands. IE stores its stuff on the media. - if ((err = scsiTestUnitReady(fd))) { - if (1 == err) - PrintOut(LOG_WARNING, "Device: %s, NOT READY (media absent, spun " - "down); skip\n", device); - else - PrintOut(LOG_ERR, "Device: %s, failed Test Unit Ready [err=%d]\n", - device, err); - deviceclose(fd); -#ifdef SCSIDEVELOPMENT - return 0; -#else - return 2; -#endif - } +static int SCSIDeviceScan(cfgfile *cfg) { + int k, fd, err; + char *device = cfg->name; + struct scsi_iec_mode_page iec; + UINT8 tBuf[64]; + + // should we try to register this as a SCSI device? + if (!cfg->tryscsi) + return 1; - if ((err = scsiFetchIECmpage(fd, &iec, cfg->modese_len))) { - PrintOut(LOG_WARNING, "Device: %s, Fetch of IEC (SMART) mode page " - "failed, err=%d, skip device\n", device, err); - deviceclose(fd); -#ifdef SCSIDEVELOPMENT - return 0; -#else - return 3; -#endif - } + // open the device + if ((fd = OpenDevice(device, "SCSI")) < 0) + return 1; + PrintOut(LOG_INFO,"Device: %s, opened\n", device); + + // check that device is ready for commands. IE stores its stuff on + // the media. + if ((err = scsiTestUnitReady(fd))) { + if (1 == err) + PrintOut(LOG_INFO, "Device: %s, NOT READY (media absent, spun down); skip device\n", device); else - cfg->modese_len = iec.modese_len; - - if (! scsi_IsExceptionControlEnabled(&iec)) { - PrintOut(LOG_WARNING, "Device: %s, IE (SMART) not enabled, " - "skip device\n", device); - deviceclose(fd); -#ifdef SCSIDEVELOPMENT - return 0; -#else - return 3; -#endif - } + PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err); + CloseDevice(fd, device); + return 2; + } + + // Badly-confirming USB storage devices should fail this check. + // Doug, is it possible that a device will have functionality that + // we might want to monitor with smartd (such as the Temperature + // page or Self-test log) but DOESN'T support the IE mode page? If + // so, we might want to make the 'skip device' contingent on a + // problem like the wrong length, rather than simply on + // non-existence of the page. + if ((err = scsiFetchIECmpage(fd, &iec, cfg->modese_len))) { + PrintOut(LOG_INFO, + "Device: %s, Fetch of IEC (SMART) mode page failed, err=%d, skip device\n", device, err); + CloseDevice(fd, device); + return 3; + } + else + cfg->modese_len = iec.modese_len; - // Device exists, and does SMART. Add to list - if (numdevscsi >= MAXSCSIDEVICES) { - PrintOut(LOG_ERR, "smartd has found more than MAXSCSIDEVICES=%d " - "SCSI devices.\n" "Recompile code from " PROJECTHOME - " with larger MAXSCSIDEVICES\n", (int)numdevscsi); -#ifdef SCSIDEVELOPMENT - deviceclose(fd); - return 0; -#else - EXIT(EXIT_CCONST); -#endif - } + // Doug should we try to enable IE if it's not already enabled? + // This is what the ATA code does: enables SMART on devices. + if (!scsi_IsExceptionControlEnabled(&iec)) { + PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n", device); + CloseDevice(fd, device); + return 3; + } + + // Device exists, and does SMART. Add to list + if (numdevscsi >= MAXSCSIDEVICES) { + PrintOut(LOG_CRIT, + "smartd has found more than MAXSCSIDEVICES=%d SCSI devices.\n" + "Recompile code from " PROJECTHOME " with larger MAXSCSIDEVICES\n", + (int)numdevscsi); + EXIT(EXIT_CCONST); + } + + // Flag that certain log pages are supported (information may be + // available from other sources). + if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, tBuf, sizeof(tBuf), 0)) { + for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { + switch (tBuf[k]) { + case TEMPERATURE_LPAGE: + cfg->TempPageSupported = 1; + break; + case IE_LPAGE: + cfg->SmartPageSupported = 1; + break; + default: + break; + } + } + } + + // record type of device + cfg->tryata = 0; + cfg->tryscsi = 1; + + // get rid of allocated memory only needed for ATA devices. These + // might have been allocated if the user specified Ignore options or + // other ATA-only Attribute-specific options on the DEVICESCAN line. + cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,__FILE__); + cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,__FILE__); + cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,__FILE__); + cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds),__LINE__,__FILE__); + + // Check if scsiCheckIE() is going to work + { + UINT8 asc = 0; + UINT8 ascq = 0; + UINT8 currenttemp = 0; + UINT8 triptemp = 0; - // now we can proceed to register the device - PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding " - "to \"monitor\" list.\n",device); - - // Flag that certain log pages are supported (information may be - // available from other sources). - if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, tBuf, sizeof(tBuf), 0)) { - for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { - switch (tBuf[k]) { - case TEMPERATURE_LPAGE: - cfg->TempPageSupported = 1; - break; - case IE_LPAGE: - cfg->SmartPageSupported = 1; - break; - default: - break; - } - } + if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, + &asc, &ascq, ¤ttemp, &triptemp)) { + PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device); + cfg->SuppressReport = 1; } - - // record number of device, type of device, increment device count - cfg->tryata = 0; - cfg->tryscsi = 1; - - // get rid of allocated memory only needed for ATA devices - cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,__FILE__); - cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,__FILE__); - cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,__FILE__); - cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds),__LINE__,__FILE__); - - // Check if scsiCheckIE() is going to work - { - UINT8 asc = 0; - UINT8 ascq = 0; - UINT8 currenttemp = 0; - UINT8 triptemp = 0; - - if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, - &asc, &ascq, ¤ttemp, &triptemp)) { - PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART" - " values\n", device); - cfg->SuppressReport = 1; - } + } + + // capability check: self-test-log + if (cfg->selftest){ + int retval=scsiCountFailedSelfTests(fd, 0); + if (retval<0) { + // no self-test log, turn off monitoring + PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-test Log.\n", device); + cfg->selftest=0; + cfg->selflogcount=0; + cfg->selfloghour=0; } - - // capability check: self-test-log - if (cfg->selftest){ - int retval=scsiCountFailedSelfTests(fd, 0); - if (retval<0) { - PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-test Log.\n", device); - cfg->selftest=0; - cfg->selflogcount=0; - cfg->selfloghour=0; - } - else { - cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); - cfg->selfloghour =SELFTEST_ERRORHOURS(retval); - } + else { + // register starting values to watch for changes + cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); + cfg->selfloghour =SELFTEST_ERRORHOURS(retval); } - - // close file descriptor - CloseDevice(fd, device); - return 0; + } + + // tell user we are registering device + PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device); + + // close file descriptor + CloseDevice(fd, device); + return 0; } // We compare old and new values of the n'th attribute. Note that n diff --git a/sm5/smartd.h b/sm5/smartd.h index aa0f70ac45e31217c23d8a7c6b021e00e2bce509..e90e7a3e6091b8f98fca0b3695af9872c9de31d5 100644 --- a/sm5/smartd.h +++ b/sm5/smartd.h @@ -27,7 +27,7 @@ #ifndef SMARTD_H_CVSID -#define SMARTD_H_CVSID "$Id: smartd.h,v 1.57 2003/11/14 11:52:33 dpgilbert Exp $\n" +#define SMARTD_H_CVSID "$Id: smartd.h,v 1.58 2003/11/17 03:10:41 ballen4705 Exp $\n" #endif // Configuration file @@ -166,10 +166,13 @@ typedef struct configfile_s { char ignorepresets; // Ignore database of -v options char showpresets; // Show database entry for this device char removable; // Device may disappear (not be present) - char *emailcmdline; // Program for sending mail (or NULL) - char *address; // Email addresses (or NULL) unsigned char selflogcount; // total number of self-test errors + unsigned char notused1; // for packing alignment + unsigned char notused2; + unsigned char notused3; unsigned short selfloghour; // lifetime hours of last self-test error + char *emailcmdline; // Program for sending mail (or NULL) + char *address; // Email addresses (or NULL) // THE NEXT SET OF ENTRIES TRACK DEVICE STATE AND ARE DYNAMIC mailinfo maildata[10]; // Tracks type/date of email messages sent @@ -181,7 +184,10 @@ typedef struct configfile_s { unsigned char SuppressReport; // minimize nuisance reports unsigned char modese_len; // mode sense/select cmd len: 0 (don't // know yet) 6 or 10 - + unsigned char notused4; // for packing alignment + unsigned char notused5; + unsigned char notused6; + // ATA ONLY FROM HERE ON TO THE END int ataerrorcount; // Total number of ATA errors