smartmontools-6.2+svn3841.orig/0000755000000000000000000000000012212065524015060 5ustar rootrootsmartmontools-6.2+svn3841.orig/smartd_warning.sh.in0000644000000000000000000001321212134046164021041 0ustar rootroot#! /bin/sh # # smartd warning script # # Copyright (C) 2012-13 Christian Franke # # 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 Software Foundation; either version 2, or (at your option) # any later version. # # You should have received a copy of the GNU General Public License # (for example COPYING); If not, see . # # $Id: smartd_warning.sh.in 3809 2013-04-18 19:41:40Z chrfranke $ # set -e # Set by config.status PACKAGE="@PACKAGE@" VERSION="@VERSION@" prefix="@prefix@" sysconfdir="@sysconfdir@" # Default mailer os_mailer="@os_mailer@" # Plugin directory plugindir="$sysconfdir/smartd_warning.d" # Parse options dryrun= case $1 in --dryrun) dryrun=t; shift ;; esac if [ $# != 0 ]; then cat <&2 exit 1 fi # Get host and domain names for cmd in @os_hostname@ 'echo "[Unknown]"'; do hostname=`eval $cmd 2>/dev/null` || continue test -n "$hostname" || continue break done dnsdomain=${hostname#*.} if [ "$dnsdomain" != "$hostname" ]; then # hostname command printed FQDN hostname=${hostname%%.*} else for cmd in @os_dnsdomainname@ 'echo'; do dnsdomain=`eval $cmd 2>/dev/null` || continue break done test "$dnsdomain" != "(none)" || dnsdomain= fi for cmd in @os_nisdomainname@ 'echo'; do nisdomain=`eval $cmd 2>/dev/null` || continue break done test "$nisdomain" != "(none)" || nisdomain= # Format subject export SMARTD_SUBJECT="SMART error (${SMARTD_FAILTYPE-[SMARTD_FAILTYPE]}) detected on host: $hostname" # Format message fullmessage=` echo "This message was generated by the smartd daemon running on:" echo echo " host name: $hostname" echo " DNS domain: ${dnsdomain:-[Empty]}" test -z "$nisdomain" || echo " NIS domain: $nisdomain" @OS_WIN32_TRUE@test -z "$USERDOMAIN" || @OS_WIN32_TRUE@ echo " Win domain: $USERDOMAIN" echo echo "The following warning/error was logged by the smartd daemon:" echo echo "${SMARTD_MESSAGE-[SMARTD_MESSAGE]}" echo echo "Device info:" echo "${SMARTD_DEVICEINFO-[SMARTD_DEVICEINFO]}" echo echo "For details see host's SYSLOG." if [ "$SMARTD_FAILTYPE" != "EmailTest" ]; then echo echo "You can also use the smartctl utility for further investigation." test "$SMARTD_PREVCNT" = "0" || echo "The original message about this issue was sent at ${SMARTD_TFIRST-[SMARTD_TFIRST]}" case $SMARTD_NEXTDAYS in '') echo "No additional messages about this problem will be sent." ;; 1) echo "Another message will be sent in 24 hours if the problem persists." ;; *) echo "Another message will be sent in $SMARTD_NEXTDAYS days if the problem persists." ;; esac fi ` # Export message with trailing newline export SMARTD_FULLMESSAGE="$fullmessage " # Run plugin scripts if requested case " $SMARTD_ADDRESS" in *\ @*) if [ -n "$dryrun" ]; then echo "export SMARTD_SUBJECT='$SMARTD_SUBJECT'" echo "export SMARTD_FULLMESSAGE='$SMARTD_FULLMESSAGE'" fi # Run ALL scripts if requested case " $SMARTD_ADDRESS " in *\ @ALL\ *) for cmd in "$plugindir"/*; do if [ -f "$cmd" ] && [ -x "$cmd" ]; then if [ -n "$dryrun" ]; then echo "$cmd &2 fi ;; *) SMARTD_ADDRESS="${SMARTD_ADDRESS:+ }$ad" ;; esac done # Send email to remaining addresses test -n "$SMARTD_ADDRESS" || exit 0 ;; esac # Send mail or run command if [ -n "$SMARTD_ADDRESS" ]; then # Send mail, use platform mailer by default test -n "$SMARTD_MAILER" || SMARTD_MAILER=$os_mailer if [ -n "$dryrun" ]; then echo "exec '$SMARTD_MAILER' -s '$SMARTD_SUBJECT' $SMARTD_ADDRESS < Erik Inge Bolsø Stanislav Brabec Peter Cassidy Praveen Chidambaram Yuri Dario Casper Dik Christian Franke Guilhem Frézou Douglas Gilbert Guido Guenther Jordan Hargrave Joerg Hering Geoff Keating Dr. David Kirkby Kai Mäkisara Eduard Martinescu Frédéric L. W. Meunier Alex Samorukov Keiji Sawada Manfred Schwarb Tomas Smetana David Snyder Sergey Svishchev Phil Williams Shengfeng Zhou Richard Zybert smartmontools-6.2+svn3841.orig/int64.h0000644000000000000000000000447112062407372016207 0ustar rootroot/* * int64.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen * Copyright (C) 2004-11 Christian Franke * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef INT64_H_ #define INT64_H_ #define INT64_H_CVSID "$Id: int64.h 3727 2012-12-13 17:23:06Z samm2 $" // 64 bit integer typedefs and format strings #ifdef HAVE_INTTYPES_H // The ISO C99 standard specifies that in C++ implementations the PRI* macros // from should only be defined if explicitly requested #define __STDC_FORMAT_MACROS 1 #include // PRId64, PRIu64, PRIx64 (also includes ) #else #ifdef HAVE_STDINT_H #include // int64_t, uint64_t (usually included above) #else #ifdef HAVE_SYS_INTTYPES_H #include #else #ifdef HAVE_SYS_INT_TYPES_H #include #else #if defined(_WIN32) && defined(_MSC_VER) // for MSVC <= 9 (MSVC10 and MinGW provide ) typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #else // for systems with above includes missing (like ix86-pc-linux-gnulibc1), // default to GCC if types are undefined in types.h #include #ifndef HAVE_INT64_T typedef long long int64_t; #endif #ifndef HAVE_UINT64_T typedef unsigned long long uint64_t; #endif #endif // _WIN32 && _MSC_VER #endif // HAVE_SYS_INT_TYPES_H #endif // HAVE_SYS_INTTYPES_H #endif // HAVE_STDINT_H #endif // HAVE_INTTYPES_H #if defined(_WIN32) && !defined(PRId64) // for MSVC (MinGW provides ) #define PRId64 "I64d" #define PRIu64 "I64u" #define PRIx64 "I64x" #endif // _WIN32 && !PRId64 // If macros not defined in inttypes.h, fix here. Default is GCC // style #ifndef PRId64 #define PRId64 "lld" #endif // ndef PRId64 #ifndef PRIu64 #define PRIu64 "llu" #endif // ndef PRIu64 #ifndef PRIx64 #define PRIx64 "llx" #endif // ndef PRIx64 #endif // INT64_H smartmontools-6.2+svn3841.orig/README0000644000000000000000000000731412155132206015743 0ustar rootroot========================================================== smartmontools - S.M.A.R.T. utility toolset for Darwin/Mac OSX, FreeBSD, Linux, NetBSD, OpenBSD, Solaris, and Windows. ========================================================== $Id: README 3817 2013-06-09 16:59:50Z chrfranke $ == HOME == The home for smartmontools is located at: http://smartmontools.sourceforge.net/ Please see this web site for updates, documentation, and for submitting patches and bug reports. You will find a mailing list for support and other questions at: http://lists.sourceforge.net/lists/listinfo/smartmontools-support == COPYING == Copyright (C) 2002-9 Bruce Allen 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 Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License (for example COPYING); if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. == CREDITS == This code was originally developed as a Senior Thesis by Michael Cornwell 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/ == OVERVIEW == smartmontools contains utilities that control and monitor storage devices using the Self-Monitoring, Analysis and Reporting Technology (S.M.A.R.T.) system build into ATA and SCSI Hard Drives. This is used to check the reliability of the hard drive and to predict drive failures. smartmontools Version 5.x is designed to comply to the ATA/ATAPI-5 specification (Revision 1). Future releases of smartmontools (Versions 6.x and 7.x) will comply with the ATA/ATAPI-6 and ATA/ATAPI-7 specifications. This package is meant to be an up-to-date replacement for the ucsc-smartsuite and smartsuite packages, and is derived from that code. == CONTENTS == The suite contains two utilities: smartctl is a command line utility designed to perform S.M.A.R.T. tasks such as disk self-checks, and to report the S.M.A.R.T. status of the disk. smartd is a daemon that periodically monitors S.M.A.R.T. status and reports errors and changes in S.M.A.R.T. attributes to syslog. == OBTAINING SMARTMONTOOLS == Source tarballs --------------- http://sourceforge.net/projects/smartmontools/files/ SVN --- svn co http://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools smartmontools This will create a subdirectory called smartmontools containing the code. To instead get the 5.38 release: svn co http://svn.code.sf.net/p/smartmontools/code/tags/RELEASE_5_38/sm5 smartmontools You can see what the different tags are by looking at http://sourceforge.net/p/smartmontools/code/HEAD/tree/tags/ == BUILDING/INSTALLING SMARTMONTOOLS == Refer to the "INSTALL" file for detailed installation instructions. See the "WARNINGS" file for reports of hardware where these utilities might cause serious problems such as lockups. == GETTING STARTED == To examine SMART data from a disk, try: smartctl -a /dev/hda for ATA disks, or smartctl -a /dev/sda for SCSI disks. See the manual page 'man smartctl' for more information. To start automatic monitoring of your disks with the smartd daemon, try: smartd -d to start the daemon in foreground (debug) mode, or smartd to start the daemon in background mode. This will log messages to SYSLOG. If you would like to get email warning messages, please set up the configuration file smartd.conf with the '-m' mail warning Directive. See the manual page 'man smartd' for more information. smartmontools-6.2+svn3841.orig/atacmds.h0000644000000000000000000010641312166107121016650 0ustar rootroot/* * atacmds.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen * Copyright (C) 2008-12 Christian Franke * Copyright (C) 1999-2000 Michael Cornwell * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see . * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef ATACMDS_H_ #define ATACMDS_H_ #define ATACMDS_H_CVSID "$Id: atacmds.h 3825 2013-07-06 21:38:25Z samm2 $" #include "dev_interface.h" // ata_device // Macro to check expected size of struct at compile time using a // dummy typedef. On size mismatch, compiler reports a negative array // size. If you see an error message of this form, it means that the // #pragma pack(1) pragma below is not having the desired effect on // your compiler. #define ASSERT_SIZEOF_STRUCT(s, n) \ typedef char assert_sizeof_struct_##s[(sizeof(struct s) == (n)) ? 1 : -1] // Add __attribute__((packed)) if compiler supports it // because some gcc versions (at least ARM) lack support of #pragma pack() #ifdef HAVE_ATTR_PACKED #define ATTR_PACKED __attribute__((packed)) #else #define ATTR_PACKED #endif typedef enum { // returns no data, just succeeds or fails ENABLE, DISABLE, AUTOSAVE, IMMEDIATE_OFFLINE, AUTO_OFFLINE, STATUS, // just says if SMART is working or not STATUS_CHECK, // says if disk's SMART status is healthy, or failing // return 512 bytes of data: READ_VALUES, READ_THRESHOLDS, READ_LOG, IDENTIFY, PIDENTIFY, // returns 1 byte of data CHECK_POWER_MODE, // writes 512 bytes of data: WRITE_LOG } smart_command_set; // ATA Specification Command Register Values (Commands) #define ATA_CHECK_POWER_MODE 0xe5 #define ATA_IDENTIFY_DEVICE 0xec #define ATA_IDENTIFY_PACKET_DEVICE 0xa1 #define ATA_IDLE 0xe3 #define ATA_SMART_CMD 0xb0 #define ATA_SECURITY_FREEZE_LOCK 0xf5 #define ATA_SET_FEATURES 0xef #define ATA_STANDBY_IMMEDIATE 0xe0 // SET_FEATURES subcommands #define ATA_DISABLE_AAM 0xc2 #define ATA_DISABLE_APM 0x85 #define ATA_DISABLE_WRITE_CACHE 0x82 #define ATA_DISABLE_READ_LOOK_AHEAD 0x55 #define ATA_ENABLE_AAM 0x42 #define ATA_ENABLE_APM 0x05 #define ATA_ENABLE_WRITE_CACHE 0x02 #define ATA_ENABLE_READ_LOOK_AHEAD 0xaa // 48-bit commands #define ATA_READ_LOG_EXT 0x2F // ATA Specification Feature Register Values (SMART Subcommands). // Note that some are obsolete as of ATA-7. #define ATA_SMART_READ_VALUES 0xd0 #define ATA_SMART_READ_THRESHOLDS 0xd1 #define ATA_SMART_AUTOSAVE 0xd2 #define ATA_SMART_SAVE 0xd3 #define ATA_SMART_IMMEDIATE_OFFLINE 0xd4 #define ATA_SMART_READ_LOG_SECTOR 0xd5 #define ATA_SMART_WRITE_LOG_SECTOR 0xd6 #define ATA_SMART_WRITE_THRESHOLDS 0xd7 #define ATA_SMART_ENABLE 0xd8 #define ATA_SMART_DISABLE 0xd9 #define ATA_SMART_STATUS 0xda // SFF 8035i Revision 2 Specification Feature Register Value (SMART // Subcommand) #define ATA_SMART_AUTO_OFFLINE 0xdb // Sector Number values for ATA_SMART_IMMEDIATE_OFFLINE Subcommand #define OFFLINE_FULL_SCAN 0 #define SHORT_SELF_TEST 1 #define EXTEND_SELF_TEST 2 #define CONVEYANCE_SELF_TEST 3 #define SELECTIVE_SELF_TEST 4 #define ABORT_SELF_TEST 127 #define SHORT_CAPTIVE_SELF_TEST 129 #define EXTEND_CAPTIVE_SELF_TEST 130 #define CONVEYANCE_CAPTIVE_SELF_TEST 131 #define SELECTIVE_CAPTIVE_SELF_TEST 132 #define CAPTIVE_MASK (0x01<<7) // Maximum allowed number of SMART Attributes #define NUMBER_ATA_SMART_ATTRIBUTES 30 // Needed parts of the ATA DRIVE IDENTIFY Structure. Those labeled // word* are NOT used. #pragma pack(1) struct ata_identify_device { unsigned short words000_009[10]; unsigned char serial_no[20]; unsigned short words020_022[3]; unsigned char fw_rev[8]; unsigned char model[40]; unsigned short words047_079[33]; unsigned short major_rev_num; unsigned short minor_rev_num; unsigned short command_set_1; unsigned short command_set_2; unsigned short command_set_extension; unsigned short cfs_enable_1; unsigned short word086; unsigned short csf_default; unsigned short words088_255[168]; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_identify_device, 512); /* ata_smart_attribute is the vendor specific in SFF-8035 spec */ #pragma pack(1) struct ata_smart_attribute { unsigned char id; // meaning of flag bits: see MACROS just below // WARNING: MISALIGNED! unsigned short flags; unsigned char current; unsigned char worst; unsigned char raw[6]; unsigned char reserv; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_attribute, 12); // MACROS to interpret the flags bits in the previous structure. // These have not been implemented using bitflags and a union, to make // it portable across bit/little endian and different platforms. // 0: Prefailure bit // From SFF 8035i Revision 2 page 19: Bit 0 (pre-failure/advisory bit) // - If the value of this bit equals zero, an attribute value less // than or equal to its corresponding attribute threshold indicates an // advisory condition where the usage or age of the device has // exceeded its intended design life period. If the value of this bit // equals one, an attribute value less than or equal to its // corresponding attribute threshold indicates a prefailure condition // where imminent loss of data is being predicted. #define ATTRIBUTE_FLAGS_PREFAILURE(x) (x & 0x01) // 1: Online bit // From SFF 8035i Revision 2 page 19: Bit 1 (on-line data collection // bit) - If the value of this bit equals zero, then the attribute // value is updated only during off-line data collection // activities. If the value of this bit equals one, then the attribute // value is updated during normal operation of the device or during // both normal operation and off-line testing. #define ATTRIBUTE_FLAGS_ONLINE(x) (x & 0x02) // The following are (probably) IBM's, Maxtors and Quantum's definitions for the // vendor-specific bits: // 2: Performance type bit #define ATTRIBUTE_FLAGS_PERFORMANCE(x) (x & 0x04) // 3: Errorrate type bit #define ATTRIBUTE_FLAGS_ERRORRATE(x) (x & 0x08) // 4: Eventcount bit #define ATTRIBUTE_FLAGS_EVENTCOUNT(x) (x & 0x10) // 5: Selfpereserving bit #define ATTRIBUTE_FLAGS_SELFPRESERVING(x) (x & 0x20) // 6-15: Reserved for future use #define ATTRIBUTE_FLAGS_OTHER(x) ((x) & 0xffc0) // Format of data returned by SMART READ DATA // Table 62 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 #pragma pack(1) struct ata_smart_values { unsigned short int revnumber; struct ata_smart_attribute vendor_attributes [NUMBER_ATA_SMART_ATTRIBUTES]; unsigned char offline_data_collection_status; unsigned char self_test_exec_status; //IBM # segments for offline collection unsigned short int total_time_to_complete_off_line; // IBM different unsigned char vendor_specific_366; // Maxtor & IBM curent segment pointer unsigned char offline_data_collection_capability; unsigned short int smart_capability; unsigned char errorlog_capability; unsigned char vendor_specific_371; // Maxtor, IBM: self-test failure checkpoint see below! unsigned char short_test_completion_time; unsigned char extend_test_completion_time_b; // If 0xff, use 16-bit value below unsigned char conveyance_test_completion_time; unsigned short extend_test_completion_time_w; // e04130r2, added to T13/1699-D Revision 1c, April 2005 unsigned char reserved_377_385[9]; unsigned char vendor_specific_386_510[125]; // Maxtor bytes 508-509 Attribute/Threshold Revision # unsigned char chksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_values, 512); /* Maxtor, IBM: self-test failure checkpoint byte meaning: 00 - write test 01 - servo basic 02 - servo random 03 - G-list scan 04 - Handling damage 05 - Read scan */ /* Vendor attribute of SMART Threshold (compare to ata_smart_attribute above) */ #pragma pack(1) struct ata_smart_threshold_entry { unsigned char id; unsigned char threshold; unsigned char reserved[10]; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_threshold_entry, 12); /* Format of Read SMART THreshold Command */ /* Compare to ata_smart_values above */ #pragma pack(1) struct ata_smart_thresholds_pvt { unsigned short int revnumber; struct ata_smart_threshold_entry thres_entries[NUMBER_ATA_SMART_ATTRIBUTES]; unsigned char reserved[149]; unsigned char chksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_thresholds_pvt, 512); // Table 42 of T13/1321D Rev 1 spec (Error Data Structure) #pragma pack(1) struct ata_smart_errorlog_error_struct { unsigned char reserved; unsigned char error_register; unsigned char sector_count; unsigned char sector_number; unsigned char cylinder_low; unsigned char cylinder_high; unsigned char drive_head; unsigned char status; unsigned char extended_error[19]; unsigned char state; unsigned short timestamp; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_error_struct, 30); // Table 41 of T13/1321D Rev 1 spec (Command Data Structure) #pragma pack(1) struct ata_smart_errorlog_command_struct { unsigned char devicecontrolreg; unsigned char featuresreg; unsigned char sector_count; unsigned char sector_number; unsigned char cylinder_low; unsigned char cylinder_high; unsigned char drive_head; unsigned char commandreg; unsigned int timestamp; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_command_struct, 12); // Table 40 of T13/1321D Rev 1 spec (Error log data structure) #pragma pack(1) struct ata_smart_errorlog_struct { struct ata_smart_errorlog_command_struct commands[5]; struct ata_smart_errorlog_error_struct error_struct; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_errorlog_struct, 90); // Table 39 of T13/1321D Rev 1 spec (SMART error log sector) #pragma pack(1) struct ata_smart_errorlog { unsigned char revnumber; unsigned char error_log_pointer; struct ata_smart_errorlog_struct errorlog_struct[5]; unsigned short int ata_error_count; unsigned char reserved[57]; unsigned char checksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_errorlog, 512); // Extended Comprehensive SMART Error Log data structures // See Section A.7 of // AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) // T13/1699-D Revision 6a (Working Draft), September 6, 2008. // Command data structure // Table A.9 of T13/1699-D Revision 6a #pragma pack(1) struct ata_smart_exterrlog_command { unsigned char device_control_register; unsigned char features_register; unsigned char features_register_hi; unsigned char count_register; unsigned char count_register_hi; unsigned char lba_low_register; unsigned char lba_low_register_hi; unsigned char lba_mid_register; unsigned char lba_mid_register_hi; unsigned char lba_high_register; unsigned char lba_high_register_hi; unsigned char device_register; unsigned char command_register; unsigned char reserved; unsigned int timestamp; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog_command, 18); // Error data structure // Table A.10 T13/1699-D Revision 6a #pragma pack(1) struct ata_smart_exterrlog_error { unsigned char device_control_register; unsigned char error_register; unsigned char count_register; unsigned char count_register_hi; unsigned char lba_low_register; unsigned char lba_low_register_hi; unsigned char lba_mid_register; unsigned char lba_mid_register_hi; unsigned char lba_high_register; unsigned char lba_high_register_hi; unsigned char device_register; unsigned char status_register; unsigned char extended_error[19]; unsigned char state; unsigned short timestamp; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog_error, 34); // Error log data structure // Table A.8 of T13/1699-D Revision 6a #pragma pack(1) struct ata_smart_exterrlog_error_log { ata_smart_exterrlog_command commands[5]; ata_smart_exterrlog_error error; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog_error_log, 124); // Ext. Comprehensive SMART error log // Table A.7 of T13/1699-D Revision 6a #pragma pack(1) struct ata_smart_exterrlog { unsigned char version; unsigned char reserved1; unsigned short error_log_index; ata_smart_exterrlog_error_log error_logs[4]; unsigned short device_error_count; unsigned char reserved2[9]; unsigned char checksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_exterrlog, 512); // Table 45 of T13/1321D Rev 1 spec (Self-test log descriptor entry) #pragma pack(1) struct ata_smart_selftestlog_struct { unsigned char selftestnumber; // Sector number register unsigned char selfteststatus; unsigned short int timestamp; unsigned char selftestfailurecheckpoint; unsigned int lbafirstfailure; unsigned char vendorspecific[15]; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_selftestlog_struct, 24); // Table 44 of T13/1321D Rev 1 spec (Self-test log data structure) #pragma pack(1) struct ata_smart_selftestlog { unsigned short int revnumber; struct ata_smart_selftestlog_struct selftest_struct[21]; unsigned char vendorspecific[2]; unsigned char mostrecenttest; unsigned char reserved[2]; unsigned char chksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_selftestlog, 512); // Extended SMART Self-test log data structures // See Section A.8 of // AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) // T13/1699-D Revision 6a (Working Draft), September 6, 2008. // Extended Self-test log descriptor entry // Table A.13 of T13/1699-D Revision 6a #pragma pack(1) struct ata_smart_extselftestlog_desc { unsigned char self_test_type; unsigned char self_test_status; unsigned short timestamp; unsigned char checkpoint; unsigned char failing_lba[6]; unsigned char vendorspecific[15]; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_extselftestlog_desc, 26); // Extended Self-test log data structure // Table A.12 of T13/1699-D Revision 6a #pragma pack(1) struct ata_smart_extselftestlog { unsigned char version; unsigned char reserved1; unsigned short log_desc_index; struct ata_smart_extselftestlog_desc log_descs[19]; unsigned char vendor_specifc[2]; unsigned char reserved2[11]; unsigned char chksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_extselftestlog, 512); // SMART LOG DIRECTORY Table 52 of T13/1532D Vol 1 Rev 1a #pragma pack(1) struct ata_smart_log_entry { unsigned char numsectors; unsigned char reserved; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_log_entry, 2); #pragma pack(1) struct ata_smart_log_directory { unsigned short int logversion; struct ata_smart_log_entry entry[255]; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_smart_log_directory, 512); // SMART SELECTIVE SELF-TEST LOG Table 61 of T13/1532D Volume 1 // Revision 3 #pragma pack(1) struct test_span { uint64_t start; uint64_t end; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(test_span, 16); #pragma pack(1) struct ata_selective_self_test_log { unsigned short logversion; struct test_span span[5]; unsigned char reserved1[337-82+1]; unsigned char vendor_specific1[491-338+1]; uint64_t currentlba; unsigned short currentspan; unsigned short flags; unsigned char vendor_specific2[507-504+1]; unsigned short pendingtime; unsigned char reserved2; unsigned char checksum; } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_selective_self_test_log, 512); #define SELECTIVE_FLAG_DOSCAN (0x0002) #define SELECTIVE_FLAG_PENDING (0x0008) #define SELECTIVE_FLAG_ACTIVE (0x0010) // SCT (SMART Command Transport) data structures // See Sections 8.2 and 8.3 of: // AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) // T13/1699-D Revision 3f (Working Draft), December 11, 2006. // SCT Status response (read with SMART_READ_LOG page 0xe0) // Table 60 of T13/1699-D Revision 3f #pragma pack(1) struct ata_sct_status_response { unsigned short format_version; // 0-1: Status response format version number (2, 3) unsigned short sct_version; // 2-3: Vendor specific version number unsigned short sct_spec; // 4-5: SCT level supported (1) unsigned int status_flags; // 6-9: Status flags (Bit 0: Segment initialized, Bits 1-31: reserved) unsigned char device_state; // 10: Device State (0-5) unsigned char bytes011_013[3]; // 11-13: reserved unsigned short ext_status_code; // 14-15: Status of last SCT command (0xffff if executing) unsigned short action_code; // 16-17: Action code of last SCT command unsigned short function_code; // 18-19: Function code of last SCT command unsigned char bytes020_039[20]; // 20-39: reserved uint64_t lba_current; // 40-47: LBA of SCT command executing in background unsigned char bytes048_199[152]; // 48-199: reserved signed char hda_temp; // 200: Current temperature in Celsius (0x80 = invalid) signed char min_temp; // 201: Minimum temperature this power cycle signed char max_temp; // 202: Maximum temperature this power cycle signed char life_min_temp; // 203: Minimum lifetime temperature signed char life_max_temp; // 204: Maximum lifetime temperature unsigned char byte205; // 205: reserved (T13/e06152r0-2: Average lifetime temperature) unsigned int over_limit_count; // 206-209: # intervals since last reset with temperature > Max Op Limit unsigned int under_limit_count; // 210-213: # intervals since last reset with temperature < Min Op Limit unsigned char bytes214_479[266]; // 214-479: reserved unsigned char vendor_specific[32];// 480-511: vendor specific } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_sct_status_response, 512); // SCT Error Recovery Control command (send with SMART_WRITE_LOG page 0xe0) // Table 88 of T13/1699-D Revision 6a #pragma pack(1) struct ata_sct_error_recovery_control_command { unsigned short action_code; // 3 = Error Recovery Control unsigned short function_code; // 1 = Set, 2 = Return unsigned short selection_code; // 1 = Read Timer, 2 = Write Timer unsigned short time_limit; // If set: Recovery time limit in 100ms units unsigned short words004_255[252]; // reserved } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_sct_error_recovery_control_command, 512); // SCT Feature Control command (send with SMART_WRITE_LOG page 0xe0) // Table 72 of T13/1699-D Revision 3f #pragma pack(1) struct ata_sct_feature_control_command { unsigned short action_code; // 4 = Feature Control unsigned short function_code; // 1 = Set, 2 = Return, 3 = Return options unsigned short feature_code; // 3 = Temperature logging interval unsigned short state; // Interval unsigned short option_flags; // Bit 0: persistent, Bits 1-15: reserved unsigned short words005_255[251]; // reserved } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_sct_feature_control_command, 512); // SCT Data Table command (send with SMART_WRITE_LOG page 0xe0) // Table 73 of T13/1699-D Revision 3f #pragma pack(1) struct ata_sct_data_table_command { unsigned short action_code; // 5 = Data Table unsigned short function_code; // 1 = Read Table unsigned short table_id; // 2 = Temperature History unsigned short words003_255[253]; // reserved } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_sct_data_table_command, 512); // SCT Temperature History Table (read with SMART_READ_LOG page 0xe1) // Table 75 of T13/1699-D Revision 3f #pragma pack(1) struct ata_sct_temperature_history_table { unsigned short format_version; // 0-1: Data table format version number (2) unsigned short sampling_period; // 2-3: Temperature sampling period in minutes unsigned short interval; // 4-5: Timer interval between history entries signed char max_op_limit; // 6: Maximum recommended continuous operating temperature signed char over_limit; // 7: Maximum temperature limit signed char min_op_limit; // 8: Minimum recommended continuous operating limit signed char under_limit; // 9: Minimum temperature limit unsigned char bytes010_029[20]; // 10-29: reserved unsigned short cb_size; // 30-31: Number of history entries (range 128-478) unsigned short cb_index; // 32-33: Index of last updated entry (zero-based) signed char cb[478]; // 34-(34+cb_size-1): Circular buffer of temperature values } ATTR_PACKED; #pragma pack() ASSERT_SIZEOF_STRUCT(ata_sct_temperature_history_table, 512); // Possible values for span_args.mode enum { SEL_RANGE, // MIN-MAX SEL_REDO, // redo this SEL_NEXT, // do next range SEL_CONT // redo or next depending of last test status }; // Arguments for selective self-test struct ata_selective_selftest_args { // Arguments for each span struct span_args { uint64_t start; // First block uint64_t end; // Last block int mode; // SEL_*, see above span_args() : start(0), end(0), mode(SEL_RANGE) { } }; span_args span[5]; // Range and mode for 5 spans int num_spans; // Number of spans int pending_time; // One plus time in minutes to wait after powerup before restarting // interrupted offline scan after selective self-test. int scan_after_select; // Run offline scan after selective self-test: // 0: don't change, // 1: turn off scan after selective self-test, // 2: turn on scan after selective self-test. ata_selective_selftest_args() : num_spans(0), pending_time(0), scan_after_select(0) { } }; // Priority for vendor attribute defs enum ata_vendor_def_prior { PRIOR_DEFAULT, PRIOR_DATABASE, PRIOR_USER }; // Raw attribute value print formats enum ata_attr_raw_format { RAWFMT_DEFAULT, RAWFMT_RAW8, RAWFMT_RAW16, RAWFMT_RAW48, RAWFMT_HEX48, RAWFMT_RAW56, RAWFMT_HEX56, RAWFMT_RAW64, RAWFMT_HEX64, RAWFMT_RAW16_OPT_RAW16, RAWFMT_RAW16_OPT_AVG16, RAWFMT_RAW24_OPT_RAW8, RAWFMT_RAW24_DIV_RAW24, RAWFMT_RAW24_DIV_RAW32, RAWFMT_SEC2HOUR, RAWFMT_MIN2HOUR, RAWFMT_HALFMIN2HOUR, RAWFMT_MSEC24_HOUR32, RAWFMT_TEMPMINMAX, RAWFMT_TEMP10X, }; // Attribute flags enum { ATTRFLAG_INCREASING = 0x01, // Value not reset (for reallocated/pending counts) ATTRFLAG_NO_NORMVAL = 0x02, // Normalized value not valid ATTRFLAG_NO_WORSTVAL = 0x04 // Worst value not valid }; // Vendor attribute display defs for all attribute ids class ata_vendor_attr_defs { public: struct entry { std::string name; // Attribute name, empty for default ata_attr_raw_format raw_format; // Raw value print format ata_vendor_def_prior priority; // Setting priority unsigned flags; // ATTRFLAG_* char byteorder[8+1]; // String [012345rvwz] to define byte order entry() : raw_format(RAWFMT_DEFAULT), priority(PRIOR_DEFAULT), flags(0) { byteorder[0] = 0; } }; entry & operator[](unsigned char id) { return m_defs[id]; } const entry & operator[](unsigned char id) const { return m_defs[id]; } private: entry m_defs[256]; }; // Possible values for firmwarebugs enum firmwarebug_t { BUG_NONE = 0, BUG_NOLOGDIR, BUG_SAMSUNG, BUG_SAMSUNG2, BUG_SAMSUNG3, BUG_XERRORLBA }; // Set of firmware bugs class firmwarebug_defs { public: firmwarebug_defs() : m_bugs(0) { } bool is_set(firmwarebug_t bug) const { return !!(m_bugs & (1 << bug)); } void set(firmwarebug_t bug) { m_bugs |= (1 << bug); } void set(firmwarebug_defs bugs) { m_bugs |= bugs.m_bugs; } private: unsigned m_bugs; }; // Print ATA debug messages? extern unsigned char ata_debugmode; // Suppress serial number? extern bool dont_print_serial_number; // Get information from drive int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_swapped_id, unsigned char * raw_buf = 0); int ataCheckPowerMode(ata_device * device); // Issue a no-data ATA command with optional sector count register value bool ata_nodata_command(ata_device * device, unsigned char command, int sector_count = -1); // Issue SET FEATURES command with optional sector count register value bool ata_set_features(ata_device * device, unsigned char features, int sector_count = -1); /* Read S.M.A.R.T information from drive */ int ataReadSmartValues(ata_device * device,struct ata_smart_values *); int ataReadSmartThresholds(ata_device * device, struct ata_smart_thresholds_pvt *); int ataReadErrorLog (ata_device * device, ata_smart_errorlog *data, firmwarebug_defs firmwarebugs); int ataReadSelfTestLog(ata_device * device, ata_smart_selftestlog * data, firmwarebug_defs firmwarebugs); int ataReadSelectiveSelfTestLog(ata_device * device, struct ata_selective_self_test_log *data); int ataReadLogDirectory(ata_device * device, ata_smart_log_directory *, bool gpl); // Read GP Log page(s) bool ataReadLogExt(ata_device * device, unsigned char logaddr, unsigned char features, unsigned page, void * data, unsigned nsectors); // Read SMART Log page(s) bool ataReadSmartLog(ata_device * device, unsigned char logaddr, void * data, unsigned nsectors); // Read SMART Extended Comprehensive Error Log bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log, unsigned nsectors, firmwarebug_defs firwarebugs); // Read SMART Extended Self-test Log bool ataReadExtSelfTestLog(ata_device * device, ata_smart_extselftestlog * log, unsigned nsectors); // Read SCT information int ataReadSCTStatus(ata_device * device, ata_sct_status_response * sts); int ataReadSCTTempHist(ata_device * device, ata_sct_temperature_history_table * tmh, ata_sct_status_response * sts); // Set SCT temperature logging interval int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persistent); // Get/Set SCT Error Recovery Control int ataGetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short & time_limit); int ataSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short time_limit); /* Enable/Disable SMART on device */ int ataEnableSmart (ata_device * device); int ataDisableSmart (ata_device * device); int ataEnableAutoSave(ata_device * device); int ataDisableAutoSave(ata_device * device); /* Automatic Offline Testing */ int ataEnableAutoOffline (ata_device * device); int ataDisableAutoOffline (ata_device * device); /* S.M.A.R.T. test commands */ int ataSmartTest(ata_device * device, int testtype, bool force, const ata_selective_selftest_args & args, const ata_smart_values * sv, uint64_t num_sectors); int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_args & args, const ata_smart_values * sv, uint64_t num_sectors, const ata_selective_selftest_args * prev_spans = 0); // Get World Wide Name (WWN) fields. // Return NAA field or -1 if WWN is unsupported. int ata_get_wwn(const ata_identify_device * id, unsigned & oui, uint64_t & unique_id); // Get nominal media rotation rate. // Returns: 0 = not reported, 1 = SSD, >1 = HDD rpm, < 0 = -(Unknown value) int ata_get_rotation_rate(const ata_identify_device * id); // If SMART supported, this is guaranteed to return 1 if SMART is enabled, else 0. int ataDoesSmartWork(ata_device * device); // returns 1 if SMART supported, 0 if not supported or can't tell int ataSmartSupport(const ata_identify_device * drive); // Return values: // 1: Write Cache Reordering enabled // 2: Write Cache Reordering disabled // -1: error int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool persistent, bool set); // Return values: // 1: SMART enabled // 0: SMART disabled // -1: can't tell if SMART is enabled -- try issuing ataDoesSmartWork command to see int ataIsSmartEnabled(const ata_identify_device * drive); int ataSmartStatus2(ata_device * device); int isSmartErrorLogCapable(const ata_smart_values * data, const ata_identify_device * identity); int isSmartTestLogCapable(const ata_smart_values * data, const ata_identify_device * identity); int isGeneralPurposeLoggingCapable(const ata_identify_device * identity); int isSupportExecuteOfflineImmediate(const ata_smart_values * data); int isSupportAutomaticTimer(const ata_smart_values * data); int isSupportOfflineAbort(const ata_smart_values * data); int isSupportOfflineSurfaceScan(const ata_smart_values * data); int isSupportSelfTest(const ata_smart_values * data); int isSupportConveyanceSelfTest(const ata_smart_values * data); int isSupportSelectiveSelfTest(const ata_smart_values * data); inline bool isSCTCapable(const ata_identify_device *drive) { return !!(drive->words088_255[206-88] & 0x01); } // 0x01 = SCT support inline bool isSCTErrorRecoveryControlCapable(const ata_identify_device *drive) { return ((drive->words088_255[206-88] & 0x09) == 0x09); } // 0x08 = SCT Error Recovery Control support inline bool isSCTFeatureControlCapable(const ata_identify_device *drive) { return ((drive->words088_255[206-88] & 0x11) == 0x11); } // 0x10 = SCT Feature Control support inline bool isSCTDataTableCapable(const ata_identify_device *drive) { return ((drive->words088_255[206-88] & 0x21) == 0x21); } // 0x20 = SCT Data Table support int TestTime(const ata_smart_values * data, int testtype); // Attribute state enum ata_attr_state { ATTRSTATE_NON_EXISTING, // No such Attribute ATTRSTATE_NO_NORMVAL, // Normalized value not valid ATTRSTATE_NO_THRESHOLD, // Unknown or no threshold ATTRSTATE_OK, // Never failed ATTRSTATE_FAILED_PAST, // Failed in the past ATTRSTATE_FAILED_NOW // Failed now }; // Get attribute state ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr, int attridx, const ata_smart_threshold_entry * thresholds, const ata_vendor_attr_defs & defs, unsigned char * threshval = 0); // Get attribute raw value. uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr, const ata_vendor_attr_defs & defs); // Format attribute raw value. std::string ata_format_attr_raw_value(const ata_smart_attribute & attr, const ata_vendor_attr_defs & defs); // Get attribute name std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs, int rpm = 0); // External handler function, for when a checksum is not correct. Can // simply return if no action is desired, or can print error messages // as needed, or exit. Is passed a string with the name of the Data // Structure with the incorrect checksum. void checksumwarning(const char *string); // Find attribute index for attribute id, -1 if not found. int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval); // Return Temperature Attribute raw value selected according to possible // non-default interpretations. If the Attribute does not exist, return 0 unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs); #define MAX_ATTRIBUTE_NUM 256 // Parse vendor attribute display def (-v option). // Return false on error. bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs, ata_vendor_def_prior priority); // Get ID and increase flag of current pending or offline // uncorrectable attribute. unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs, bool & increase); // Return a multiline string containing a list of valid arguments for // parse_attribute_def(). std::string create_vendor_attribute_arg_list(); // Parse firmwarebug def (-F option). // Return false on error. bool parse_firmwarebug_def(const char * opt, firmwarebug_defs & firmwarebugs); // Return a string of valid argument words for parse_firmwarebug_def() const char * get_valid_firmwarebug_args(); // These are two of the functions that are defined in os_*.c and need // to be ported to get smartmontools onto another OS. // Moved to C++ interface //int ata_command_interface(int device, smart_command_set command, int select, char *data); //int escalade_command_interface(int fd, int escalade_port, int escalade_type, smart_command_set command, int select, char *data); //int marvell_command_interface(int device, smart_command_set command, int select, char *data); //int highpoint_command_interface(int device, smart_command_set command, int select, char *data); //int areca_command_interface(int fd, int disknum, smart_command_set command, int select, char *data); // This function is exported to give low-level capability int smartcommandhandler(ata_device * device, smart_command_set command, int select, char *data); // Print one self-test log entry. // Returns: // -1: failed self-test // 1: extended self-test completed without error // 0: otherwise int ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type, unsigned char test_status, unsigned short timestamp, uint64_t failing_lba, bool print_error_only, bool & print_header); // Print Smart self-test log, used by smartctl and smartd. int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries, firmwarebug_defs firmwarebugs); // Get capacity and sector sizes from IDENTIFY data struct ata_size_info { uint64_t sectors; uint64_t capacity; unsigned log_sector_size; unsigned phy_sector_size; unsigned log_sector_offset; }; void ata_get_size_info(const ata_identify_device * id, ata_size_info & sizes); // Convenience function for formatting strings from ata_identify_device. void ata_format_id_string(char * out, const unsigned char * in, int n); // Utility routines. unsigned char checksum(const void * data); void swap2(char *location); void swap4(char *location); void swap8(char *location); // Typesafe variants using overloading inline void swapx(unsigned short * p) { swap2((char*)p); } inline void swapx(unsigned int * p) { swap4((char*)p); } inline void swapx(uint64_t * p) { swap8((char*)p); } // Return pseudo-device to parse "smartctl -r ataioctl,2 ..." output // and simulate an ATA device with same behaviour ata_device * get_parsed_ata_device(smart_interface * intf, const char * dev_name); #endif /* ATACMDS_H_ */ smartmontools-6.2+svn3841.orig/os_linux.h0000644000000000000000000002644712062413436017110 0ustar rootroot/* * os_linux.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 Bruce Allen * * Derived from code that was * * Written By: Adam Radford * Modifications By: Joel Jacobson * Arnaldo Carvalho de Melo * Brad Strand * * Copyright (C) 1999-2003 3ware Inc. * * Kernel compatablity By: Andre Hedrick * Non-Copyright (C) 2000 Andre Hedrick * * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef OS_LINUX_H_ #define OS_LINUX_H_ #define OS_LINUX_H_CVSID "$Id: os_linux.h 3728 2012-12-13 17:57:50Z chrfranke $\n" /* The following definitions/macros/prototypes are used for three different interfaces, referred to as "the three cases" below. CONTROLLER_3WARE_678K -- 6000, 7000, and 8000 controllers via /dev/sd? CONTROLLER_3WARE_678K_CHAR -- 6000, 7000, and 8000 controllers via /dev/twe? CONTROLLER_3WARE_9000_CHAR -- 9000 controllers via /dev/twa? */ // USED FOR ALL THREE CASES #define u32 unsigned int #define TW_OP_ATA_PASSTHRU 0x11 #define MAX(x,y) ( (x)>(y)?(x):(y) ) #pragma pack(1) /* Scatter gather list entry */ typedef struct TAG_TW_SG_Entry { unsigned int address; unsigned int length; } TW_SG_Entry; /* Command header for ATA pass-thru. Note that for different drivers/interfaces the length of sg_list (here TW_ATA_PASS_SGL_MAX) is different. But it can be taken as same for all three cases because it's never used to define any other structures, and we never use anything in the sg_list or beyond! */ #define TW_ATA_PASS_SGL_MAX 60 typedef struct TAG_TW_Passthru { struct { unsigned char opcode:5; unsigned char sgloff:3; } byte0; unsigned char size; unsigned char request_id; unsigned char unit; unsigned char status; // On return, contains 3ware STATUS register unsigned char flags; unsigned short param; unsigned short features; // On return, contains ATA ERROR register unsigned short sector_count; unsigned short sector_num; unsigned short cylinder_lo; unsigned short cylinder_hi; unsigned char drive_head; unsigned char command; // On return, contains ATA STATUS register TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX]; unsigned char padding[12]; } TW_Passthru; // the following are for the SCSI interface only // Ioctl buffer: Note that this defn has changed in kernel tree... // Total size is 1041 bytes -- this is really weird #define TW_IOCTL 0x80 #define TW_ATA_PASSTHRU 0x1e // Adam -- should this be #pramga packed? Otherwise table_id gets // moved for byte alignment. Without packing, input passthru for SCSI // ioctl is 31 bytes in. With packing it is 30 bytes in. typedef struct TAG_TW_Ioctl { int input_length; int output_length; unsigned char cdb[16]; unsigned char opcode; // This one byte of padding is missing from the typedefs in the // kernel code, but it is indeed present. We put it explicitly // here, so that the structure can be packed. Adam agrees with // this. unsigned char packing; unsigned short table_id; unsigned char parameter_id; unsigned char parameter_size_bytes; unsigned char unit_index; // Size up to here is 30 bytes + 1 padding! unsigned char input_data[499]; // Reserve lots of extra space for commands that set Sector Count // register to large values unsigned char output_data[512]; // starts 530 bytes in! // two more padding bytes here if structure NOT packed. } TW_Ioctl; /* Ioctl buffer output -- SCSI interface only! */ typedef struct TAG_TW_Output { int padding[2]; char output_data[512]; } TW_Output; // What follows is needed for 9000 char interface only #define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 #define TW_MAX_SGL_LENGTH_9000 61 typedef struct TAG_TW_Ioctl_Driver_Command_9000 { unsigned int control_code; unsigned int status; unsigned int unique_id; unsigned int sequence_id; unsigned int os_specific; unsigned int buffer_length; } TW_Ioctl_Driver_Command_9000; /* Command Packet */ typedef struct TW_Command_9000 { /* First DWORD */ struct { unsigned char opcode:5; unsigned char sgl_offset:3; } byte0; unsigned char size; unsigned char request_id; struct { unsigned char unit:4; unsigned char host_id:4; } byte3; /* Second DWORD */ unsigned char status; unsigned char flags; union { unsigned short block_count; unsigned short parameter_count; unsigned short message_credits; } byte6; union { struct { u32 lba; TW_SG_Entry sgl[TW_MAX_SGL_LENGTH_9000]; u32 padding; } io; struct { TW_SG_Entry sgl[TW_MAX_SGL_LENGTH_9000]; u32 padding[2]; } param; struct { u32 response_queue_pointer; u32 padding[125]; /* pad entire structure to 512 bytes */ } init_connection; struct { char version[504]; } ioctl_miniport_version; } byte8; } TW_Command_9000; /* Command Packet for 9000+ controllers */ typedef struct TAG_TW_Command_Apache { struct { unsigned char opcode:5; unsigned char reserved:3; } command; unsigned char unit; unsigned short request_id; unsigned char sense_length; unsigned char sgl_offset; unsigned short sgl_entries; unsigned char cdb[16]; TW_SG_Entry sg_list[TW_MAX_SGL_LENGTH_9000]; } TW_Command_Apache; /* New command packet header */ typedef struct TAG_TW_Command_Apache_Header { unsigned char sense_data[18]; struct { char reserved[4]; unsigned short error; unsigned char status; struct { unsigned char severity:3; unsigned char reserved:5; } substatus_block; } status_block; unsigned char err_specific_desc[102]; } TW_Command_Apache_Header; /* This struct is a union of the 2 command packets */ typedef struct TAG_TW_Command_Full_9000 { TW_Command_Apache_Header header; union { TW_Command_9000 oldcommand; TW_Command_Apache newcommand; } command; unsigned char padding[384]; /* Pad to 1024 bytes */ } TW_Command_Full_9000; typedef struct TAG_TW_Ioctl_Apache { TW_Ioctl_Driver_Command_9000 driver_command; char padding[488]; TW_Command_Full_9000 firmware_command; char data_buffer[1]; // three bytes of padding here if structure not packed! } TW_Ioctl_Buf_Apache; // START OF DEFINITIONS FOR THE CHARACTER INTERFACE TO THE // 6000/7000/8000 drivers #define TW_MAX_SGL_LENGTH 62 #define TW_CMD_PACKET_WITH_DATA 0x1f /* Command Packet */ typedef struct TW_Command { /* First DWORD */ struct { unsigned char opcode:5; unsigned char sgl_offset:3; } byte0; unsigned char size; unsigned char request_id; struct { unsigned char unit:4; unsigned char host_id:4; } byte3; /* Second DWORD */ unsigned char status; unsigned char flags; union { unsigned short block_count; unsigned short parameter_count; unsigned short message_credits; } byte6; union { struct { u32 lba; TW_SG_Entry sgl[TW_MAX_SGL_LENGTH]; u32 padding; /* pad to 512 bytes */ } io; struct { TW_SG_Entry sgl[TW_MAX_SGL_LENGTH]; u32 padding[2]; } param; struct { u32 response_queue_pointer; u32 padding[125]; } init_connection; struct { char version[504]; } ioctl_miniport_version; } byte8; } TW_Command; typedef struct TAG_TW_New_Ioctl { unsigned int data_buffer_length; unsigned char padding [508]; TW_Command firmware_command; char data_buffer[1]; // three bytes of padding here } TW_New_Ioctl; #pragma pack() #if 0 // Useful for checking/understanding packing of 3ware data structures // above. void my(int x, char *y){ printf("The size of %30s is: %5d\n",y, x); return; } int main() { TW_Ioctl tmp; my(sizeof(TW_SG_Entry),"TW_SG_Entry"); my(sizeof(TW_Passthru),"TW_Passthru"); my(sizeof(TW_Ioctl),"TW_Ioctl"); my(sizeof(TW_Output),"TW_Output"); my(sizeof(TW_Ioctl_Driver_Command_9000),"TW_Ioctl_Driver_Command_9000"); my(sizeof(TW_Command_9000),"TW_Command_9000"); my(sizeof(TW_Command_Apache),"TW_Command_Apache"); my(sizeof(TW_Command_Apache_Header),"TW_Command_Apache_Header"); my(sizeof(TW_Command_Full_9000),"TW_Command_Full_9000"); my(sizeof(TW_Ioctl_Buf_Apache),"TW_Ioctl_Buf_Apache"); my(sizeof(TW_Command),"TW_Command"); my(sizeof(TW_New_Ioctl),"TW_New_Ioctl"); printf("TW_Ioctl.table_id - start = %d (irrelevant)\n", (void *)&tmp.table_id - (void *)&tmp); printf("TW_Ioctl.input_data - start = %d (input passthru location)\n", (void *)&tmp.input_data - (void *)&tmp); printf("TW_Ioctl.output_data - start = %d (irrelevant)\n", (void *)&tmp.output_data - (void *)&tmp); return 0; } #endif // The following definitions are from hdreg.h in the kernel source // tree. They don't carry any Copyright statements, but I think they // are primarily from Mark Lord and Andre Hedrick. typedef unsigned char task_ioreg_t; typedef struct hd_drive_task_hdr { task_ioreg_t data; task_ioreg_t feature; task_ioreg_t sector_count; task_ioreg_t sector_number; task_ioreg_t low_cylinder; task_ioreg_t high_cylinder; task_ioreg_t device_head; task_ioreg_t command; } task_struct_t; typedef union ide_reg_valid_s { unsigned all : 16; struct { unsigned data : 1; unsigned error_feature : 1; unsigned sector : 1; unsigned nsector : 1; unsigned lcyl : 1; unsigned hcyl : 1; unsigned select : 1; unsigned status_command : 1; unsigned data_hob : 1; unsigned error_feature_hob : 1; unsigned sector_hob : 1; unsigned nsector_hob : 1; unsigned lcyl_hob : 1; unsigned hcyl_hob : 1; unsigned select_hob : 1; unsigned control_hob : 1; } b; } ide_reg_valid_t; typedef struct ide_task_request_s { task_ioreg_t io_ports[8]; task_ioreg_t hob_ports[8]; ide_reg_valid_t out_flags; ide_reg_valid_t in_flags; int data_phase; int req_cmd; unsigned long out_size; unsigned long in_size; } ide_task_request_t; #define TASKFILE_NO_DATA 0x0000 #define TASKFILE_IN 0x0001 #define TASKFILE_OUT 0x0004 #define HDIO_DRIVE_TASK_HDR_SIZE 8*sizeof(task_ioreg_t) #define IDE_DRIVE_TASK_NO_DATA 0 #define IDE_DRIVE_TASK_IN 2 #define IDE_DRIVE_TASK_OUT 3 #define HDIO_DRIVE_CMD 0x031f #define HDIO_DRIVE_TASK 0x031e #define HDIO_DRIVE_TASKFILE 0x031d #define HDIO_GET_IDENTITY 0x030d #define HPTIO_CTL 0x03ff // ioctl interface for HighPoint raid device #endif /* OS_LINUX_H_ */ smartmontools-6.2+svn3841.orig/dev_ata_cmd_set.h0000644000000000000000000000264211227432427020343 0ustar rootroot/* * dev_ata_cmd_set.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2008 Christian Franke * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see . * */ #ifndef DEV_ATA_CMD_SET_H #define DEV_ATA_CMD_SET_H #define DEV_ATA_CMD_SET_H_CVSID "$Id: dev_ata_cmd_set.h,v 1.3 2008/08/23 21:32:12 chrfranke Exp $\n" #include "atacmds.h" // smart_command_set #include "dev_interface.h" ///////////////////////////////////////////////////////////////////////////// // ata_device_with_command_set /// Adapter class to implement new ATA pass through old interface. class ata_device_with_command_set : public /*implements*/ ata_device { public: /// ATA pass through mapped to ata_command_interface(). virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); protected: /// Old ATA interface called by ata_pass_through() virtual int ata_command_interface(smart_command_set command, int select, char * data) = 0; ata_device_with_command_set() : smart_device(never_called) { } }; #endif // DEV_ATA_CMD_SET_H smartmontools-6.2+svn3841.orig/dev_interface.cpp0000644000000000000000000002450612071064456020377 0ustar rootroot/* * dev_interface.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2008-13 Christian Franke * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see . * */ #include "config.h" #include "int64.h" #include "dev_interface.h" #include "dev_tunnelled.h" #include "atacmds.h" // ATA_SMART_CMD/STATUS #include "utility.h" #include #include #include #if defined(HAVE_GETTIMEOFDAY) #include #elif defined(HAVE_FTIME) #include #endif const char * dev_interface_cpp_cvsid = "$Id: dev_interface.cpp 3741 2013-01-02 17:06:54Z chrfranke $" DEV_INTERFACE_H_CVSID; ///////////////////////////////////////////////////////////////////////////// // smart_device smart_device::smart_device(smart_interface * intf, const char * dev_name, const char * dev_type, const char * req_type) : m_intf(intf), m_info(dev_name, dev_type, req_type), m_ata_ptr(0), m_scsi_ptr(0) { } smart_device::smart_device(do_not_use_in_implementation_classes) : m_intf(0), m_ata_ptr(0), m_scsi_ptr(0) { throw std::logic_error("smart_device: wrong constructor called in implementation class"); } smart_device::~smart_device() throw() { } bool smart_device::is_syscall_unsup() const { if (get_errno() == ENOSYS) return true; #ifdef ENOTSUP if (get_errno() == ENOTSUP) return true; #endif return false; } bool smart_device::set_err(int no, const char * msg, ...) { if (!msg) return set_err(no); m_err.no = no; va_list ap; va_start(ap, msg); m_err.msg = vstrprintf(msg, ap); va_end(ap); return false; } bool smart_device::set_err(int no) { return smi()->set_err_var(&m_err, no); } smart_device * smart_device::autodetect_open() { open(); return this; } bool smart_device::owns(const smart_device * /*dev*/) const { return false; } void smart_device::release(const smart_device * /*dev*/) { } ///////////////////////////////////////////////////////////////////////////// // ata_device ata_in_regs_48bit::ata_in_regs_48bit() : features_16(features, prev.features), sector_count_16(sector_count, prev.sector_count), lba_low_16(lba_low, prev.lba_low), lba_mid_16(lba_mid, prev.lba_mid), lba_high_16(lba_high, prev.lba_high), lba_48( lba_low, lba_mid, lba_high, prev.lba_low, prev.lba_mid, prev.lba_high) { } ata_out_regs_48bit::ata_out_regs_48bit() : sector_count_16(sector_count, prev.sector_count), lba_low_16(lba_low, prev.lba_low), lba_mid_16(lba_mid, prev.lba_mid), lba_high_16(lba_high, prev.lba_high), lba_48( lba_low, lba_mid, lba_high, prev.lba_low, prev.lba_mid, prev.lba_high) { } ata_cmd_in::ata_cmd_in() : direction(no_data), buffer(0), size(0) { } ata_cmd_out::ata_cmd_out() { } bool ata_device::ata_pass_through(const ata_cmd_in & in) { ata_cmd_out dummy; return ata_pass_through(in, dummy); } bool ata_device::ata_cmd_is_supported(const ata_cmd_in & in, unsigned flags, const char * type /* = 0 */) { // Check DATA IN/OUT switch (in.direction) { case ata_cmd_in::no_data: break; case ata_cmd_in::data_in: break; case ata_cmd_in::data_out: break; default: return set_err(EINVAL, "Invalid data direction %d", (int)in.direction); } // Check buffer size if (in.direction == ata_cmd_in::no_data) { if (in.size) return set_err(EINVAL, "Buffer size %u > 0 for NO DATA command", in.size); } else { if (!in.buffer) return set_err(EINVAL, "Buffer not set for DATA IN/OUT command"); unsigned count = (in.in_regs.prev.sector_count<<16)|in.in_regs.sector_count; // TODO: Add check for sector count == 0 if (count * 512 != in.size) return set_err(EINVAL, "Sector count %u does not match buffer size %u", count, in.size); } // Check features const char * errmsg = 0; if (in.direction == ata_cmd_in::data_out && !(flags & supports_data_out)) errmsg = "DATA OUT ATA commands not implemented"; else if ( in.out_needed.is_set() && !(flags & supports_output_regs) && !( in.in_regs.command == ATA_SMART_CMD && in.in_regs.features == ATA_SMART_STATUS && (flags & supports_smart_status))) errmsg = "Read of ATA output registers not implemented"; else if (!(in.size == 0 || in.size == 512) && !(flags & supports_multi_sector)) errmsg = "Multi-sector ATA commands not implemented"; else if (in.in_regs.is_48bit_cmd() && !(flags & (supports_48bit_hi_null|supports_48bit))) errmsg = "48-bit ATA commands not implemented"; else if (in.in_regs.is_real_48bit_cmd() && !(flags & supports_48bit)) errmsg = "48-bit ATA commands not fully implemented"; if (errmsg) return set_err(ENOSYS, "%s%s%s%s", errmsg, (type ? " [" : ""), (type ? type : ""), (type ? "]" : "")); return true; } bool ata_device::ata_identify_is_cached() const { return false; } ///////////////////////////////////////////////////////////////////////////// // tunnelled_device_base tunnelled_device_base::tunnelled_device_base(smart_device * tunnel_dev) : smart_device(never_called), m_tunnel_base_dev(tunnel_dev) { } tunnelled_device_base::~tunnelled_device_base() throw() { delete m_tunnel_base_dev; } bool tunnelled_device_base::is_open() const { return (m_tunnel_base_dev && m_tunnel_base_dev->is_open()); } bool tunnelled_device_base::open() { if (!m_tunnel_base_dev) return set_err(ENOSYS); if (!m_tunnel_base_dev->open()) return set_err(m_tunnel_base_dev->get_err()); return true; } bool tunnelled_device_base::close() { if (!m_tunnel_base_dev) return true; if (!m_tunnel_base_dev->close()) return set_err(m_tunnel_base_dev->get_err()); return true; } bool tunnelled_device_base::owns(const smart_device * dev) const { return (m_tunnel_base_dev && (m_tunnel_base_dev == dev)); } void tunnelled_device_base::release(const smart_device * dev) { if (m_tunnel_base_dev == dev) m_tunnel_base_dev = 0; } ///////////////////////////////////////////////////////////////////////////// // smart_interface // Pointer to (usually singleton) interface object returned by ::smi() smart_interface * smart_interface::s_instance; std::string smart_interface::get_os_version_str() { return SMARTMONTOOLS_BUILD_HOST; } std::string smart_interface::get_valid_dev_types_str() { // default std::string s = "ata, scsi, sat[,auto][,N][+TYPE], usbcypress[,X], usbjmicron[,p][,x][,N], usbsunplus"; // append custom std::string s2 = get_valid_custom_dev_types_str(); if (!s2.empty()) { s += ", "; s += s2; } return s; } std::string smart_interface::get_app_examples(const char * /*appname*/) { return ""; } int64_t smart_interface::get_timer_usec() { #if defined(HAVE_GETTIMEOFDAY) #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) { static bool have_clock_monotonic = true; if (have_clock_monotonic) { struct timespec ts; if (!clock_gettime(CLOCK_MONOTONIC, &ts)) return ts.tv_sec * 1000000LL + ts.tv_nsec/1000; have_clock_monotonic = false; } } #endif { struct timeval tv; gettimeofday(&tv, 0); return tv.tv_sec * 1000000LL + tv.tv_usec; } #elif defined(HAVE_FTIME) { struct timeb tb; ftime(&tb); return tb.time * 1000000LL + tb.millitm * 1000; } #else return -1; #endif } bool smart_interface::disable_system_auto_standby(bool /*disable*/) { return set_err(ENOSYS); } bool smart_interface::set_err(int no, const char * msg, ...) { if (!msg) return set_err(no); m_err.no = no; va_list ap; va_start(ap, msg); m_err.msg = vstrprintf(msg, ap); va_end(ap); return false; } bool smart_interface::set_err(int no) { return set_err_var(&m_err, no); } bool smart_interface::set_err_var(smart_device::error_info * err, int no) { err->no = no; err->msg = get_msg_for_errno(no); if (err->msg.empty() && no != 0) err->msg = strprintf("Unknown error %d", no); return false; } const char * smart_interface::get_msg_for_errno(int no) { return strerror(no); } ///////////////////////////////////////////////////////////////////////////// // Default device factory smart_device * smart_interface::get_smart_device(const char * name, const char * type) { clear_err(); // Call platform specific autodetection if no device type specified smart_device * dev; if (!type || !*type) { dev = autodetect_smart_device(name); if (!dev && !get_errno()) set_err(EINVAL, "Unable to detect device type"); return dev; } // First check for platform specific device types dev = get_custom_smart_device(name, type); if (dev || get_errno()) return dev; if (!strcmp(type, "ata")) dev = get_ata_device(name, type); else if (!strcmp(type, "scsi")) dev = get_scsi_device(name, type); else if ( ((!strncmp(type, "sat", 3) && (!type[3] || strchr(",+", type[3]))) || (!strncmp(type, "usb", 3)))) { // Split "sat...+base..." -> ("sat...", "base...") unsigned satlen = strcspn(type, "+"); std::string sattype(type, satlen); const char * basetype = (type[satlen] ? type+satlen+1 : ""); // Recurse to allocate base device, default is standard SCSI if (!*basetype) basetype = "scsi"; smart_device_auto_ptr basedev( get_smart_device(name, basetype) ); if (!basedev) { set_err(EINVAL, "Type '%s+...': %s", sattype.c_str(), get_errmsg()); return 0; } // Result must be SCSI if (!basedev->is_scsi()) { set_err(EINVAL, "Type '%s+...': Device type '%s' is not SCSI", sattype.c_str(), basetype); return 0; } // Attach SAT tunnel ata_device * satdev = get_sat_device(sattype.c_str(), basedev->to_scsi()); if (!satdev) return 0; basedev.release(); return satdev; } else { set_err(EINVAL, "Unknown device type '%s'", type); return 0; } if (!dev && !get_errno()) set_err(EINVAL, "Not a device of type '%s'", type); return dev; } smart_device * smart_interface::get_custom_smart_device(const char * /*name*/, const char * /*type*/) { return 0; } std::string smart_interface::get_valid_custom_dev_types_str() { return ""; } smartmontools-6.2+svn3841.orig/ataprint.cpp0000644000000000000000000035307112172516764017433 0ustar rootroot/* * ataprint.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen * Copyright (C) 2008-13 Christian Franke * Copyright (C) 1999-2000 Michael Cornwell * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see . * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #include "config.h" #include #include #include #include #include #include "int64.h" #include "atacmdnames.h" #include "atacmds.h" #include "ataidentify.h" #include "dev_interface.h" #include "ataprint.h" #include "smartctl.h" #include "utility.h" #include "knowndrives.h" const char * ataprint_cpp_cvsid = "$Id: ataprint.cpp 3831 2013-07-20 14:25:56Z chrfranke $" ATAPRINT_H_CVSID; static const char * infofound(const char *output) { return (*output ? output : "[No Information Found]"); } // Return true if '-T permissive' is specified, // used to ignore missing capabilities static bool is_permissive() { if (!failuretest_permissive) return false; failuretest_permissive--; return true; } /* For the given Command Register (CR) and Features Register (FR), attempts * to construct a string that describes the contents of the Status * Register (ST) and Error Register (ER). If the meanings of the flags of * the error register are not known for the given command then it returns an * empty string. * * The meanings of the flags of the error register for all commands are * described in the ATA spec and could all be supported here in theory. * Currently, only a few commands are supported (those that have been seen * to produce errors). If many more are to be added then this function * should probably be redesigned. */ static std::string format_st_er_desc( unsigned char CR, unsigned char FR, unsigned char ST, unsigned char ER, unsigned short SC, const ata_smart_errorlog_error_struct * lba28_regs, const ata_smart_exterrlog_error * lba48_regs ) { const char *error_flag[8]; int i, print_lba=0, print_sector=0; // Set of character strings corresponding to different error codes. // Please keep in alphabetic order if you add more. const char *abrt = "ABRT"; // ABORTED const char *amnf = "AMNF"; // ADDRESS MARK NOT FOUND const char *ccto = "CCTO"; // COMMAND COMPLETION TIMED OUT const char *eom = "EOM"; // END OF MEDIA const char *icrc = "ICRC"; // INTERFACE CRC ERROR const char *idnf = "IDNF"; // ID NOT FOUND const char *ili = "ILI"; // MEANING OF THIS BIT IS COMMAND-SET SPECIFIC const char *mc = "MC"; // MEDIA CHANGED const char *mcr = "MCR"; // MEDIA CHANGE REQUEST const char *nm = "NM"; // NO MEDIA const char *obs = "obs"; // OBSOLETE const char *tk0nf = "TK0NF"; // TRACK 0 NOT FOUND const char *unc = "UNC"; // UNCORRECTABLE const char *wp = "WP"; // WRITE PROTECTED /* If for any command the Device Fault flag of the status register is * not used then used_device_fault should be set to 0 (in the CR switch * below) */ int uses_device_fault = 1; /* A value of NULL means that the error flag isn't used */ for (i = 0; i < 8; i++) error_flag[i] = NULL; std::string str; switch (CR) { case 0x10: // RECALIBRATE error_flag[2] = abrt; error_flag[1] = tk0nf; break; case 0x20: /* READ SECTOR(S) */ case 0x21: // READ SECTOR(S) case 0x24: // READ SECTOR(S) EXT case 0xC4: /* READ MULTIPLE */ case 0x29: // READ MULTIPLE EXT error_flag[6] = unc; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; error_flag[0] = amnf; print_lba=1; break; case 0x22: // READ LONG (with retries) case 0x23: // READ LONG (without retries) error_flag[4] = idnf; error_flag[2] = abrt; error_flag[0] = amnf; print_lba=1; break; case 0x2a: // READ STREAM DMA case 0x2b: // READ STREAM PIO if (CR==0x2a) error_flag[7] = icrc; error_flag[6] = unc; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; error_flag[0] = ccto; print_lba=1; print_sector=SC; break; case 0x3A: // WRITE STREAM DMA case 0x3B: // WRITE STREAM PIO if (CR==0x3A) error_flag[7] = icrc; error_flag[6] = wp; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; error_flag[0] = ccto; print_lba=1; print_sector=SC; break; case 0x25: // READ DMA EXT case 0x26: // READ DMA QUEUED EXT case 0xC7: // READ DMA QUEUED case 0xC8: // READ DMA (with retries) case 0xC9: // READ DMA (without retries, obsolete since ATA-5) case 0x60: // READ FPDMA QUEUED (NCQ) error_flag[7] = icrc; error_flag[6] = unc; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; error_flag[0] = amnf; print_lba=1; if (CR==0x25 || CR==0xC8) print_sector=SC; break; case 0x30: /* WRITE SECTOR(S) */ case 0x31: // WRITE SECTOR(S) case 0x34: // WRITE SECTOR(S) EXT case 0xC5: /* WRITE MULTIPLE */ case 0x39: // WRITE MULTIPLE EXT case 0xCE: // WRITE MULTIPLE FUA EXT error_flag[6] = wp; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; print_lba=1; break; case 0x32: // WRITE LONG (with retries) case 0x33: // WRITE LONG (without retries) error_flag[4] = idnf; error_flag[2] = abrt; print_lba=1; break; case 0x3C: // WRITE VERIFY error_flag[6] = unc; error_flag[4] = idnf; error_flag[2] = abrt; error_flag[0] = amnf; print_lba=1; break; case 0x40: // READ VERIFY SECTOR(S) with retries case 0x41: // READ VERIFY SECTOR(S) without retries case 0x42: // READ VERIFY SECTOR(S) EXT error_flag[6] = unc; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; error_flag[0] = amnf; print_lba=1; break; case 0xA0: /* PACKET */ /* Bits 4-7 are all used for sense key (a 'command packet set specific error * indication' according to the ATA/ATAPI-7 standard), so "Sense key" will * be repeated in the error description string if more than one of those * bits is set. */ error_flag[7] = "Sense key (bit 3)", error_flag[6] = "Sense key (bit 2)", error_flag[5] = "Sense key (bit 1)", error_flag[4] = "Sense key (bit 0)", error_flag[2] = abrt; error_flag[1] = eom; error_flag[0] = ili; break; case 0xA1: /* IDENTIFY PACKET DEVICE */ case 0xEF: /* SET FEATURES */ case 0x00: /* NOP */ case 0xC6: /* SET MULTIPLE MODE */ error_flag[2] = abrt; break; case 0x2F: // READ LOG EXT error_flag[6] = unc; error_flag[4] = idnf; error_flag[2] = abrt; error_flag[0] = obs; break; case 0x3F: // WRITE LOG EXT error_flag[4] = idnf; error_flag[2] = abrt; error_flag[0] = obs; break; case 0xB0: /* SMART */ switch(FR) { case 0xD0: // SMART READ DATA case 0xD1: // SMART READ ATTRIBUTE THRESHOLDS case 0xD5: /* SMART READ LOG */ error_flag[6] = unc; error_flag[4] = idnf; error_flag[2] = abrt; error_flag[0] = obs; break; case 0xD6: /* SMART WRITE LOG */ error_flag[4] = idnf; error_flag[2] = abrt; error_flag[0] = obs; break; case 0xD2: // Enable/Disable Attribute Autosave case 0xD3: // SMART SAVE ATTRIBUTE VALUES (ATA-3) case 0xD8: // SMART ENABLE OPERATIONS case 0xD9: /* SMART DISABLE OPERATIONS */ case 0xDA: /* SMART RETURN STATUS */ case 0xDB: // Enable/Disable Auto Offline (SFF) error_flag[2] = abrt; break; case 0xD4: // SMART EXECUTE IMMEDIATE OFFLINE error_flag[4] = idnf; error_flag[2] = abrt; break; default: return str; // "" break; } break; case 0xB1: /* DEVICE CONFIGURATION */ switch (FR) { case 0xC0: /* DEVICE CONFIGURATION RESTORE */ error_flag[2] = abrt; break; default: return str; // "" break; } break; case 0xCA: // WRITE DMA (with retries) case 0xCB: // WRITE DMA (without retries, obsolete since ATA-5) case 0x35: // WRITE DMA EXT case 0x3D: // WRITE DMA FUA EXT case 0xCC: // WRITE DMA QUEUED case 0x36: // WRITE DMA QUEUED EXT case 0x3E: // WRITE DMA QUEUED FUA EXT case 0x61: // WRITE FPDMA QUEUED (NCQ) error_flag[7] = icrc; error_flag[6] = wp; error_flag[5] = mc; error_flag[4] = idnf; error_flag[3] = mcr; error_flag[2] = abrt; error_flag[1] = nm; error_flag[0] = amnf; print_lba=1; if (CR==0x35) print_sector=SC; break; case 0xE4: // READ BUFFER case 0xE8: // WRITE BUFFER error_flag[2] = abrt; break; default: return str; // "" } /* We ignore any status flags other than Device Fault and Error */ if (uses_device_fault && (ST & (1 << 5))) { str = "Device Fault"; if (ST & 1) // Error flag str += "; "; } if (ST & 1) { // Error flag int count = 0; str += "Error: "; for (i = 7; i >= 0; i--) if ((ER & (1 << i)) && (error_flag[i])) { if (count++ > 0) str += ", "; str += error_flag[i]; } } // If the error was a READ or WRITE error, print the Logical Block // Address (LBA) at which the read or write failed. if (print_lba) { // print number of sectors, if known, and append to print string if (print_sector) str += strprintf(" %d sectors", print_sector); if (lba28_regs) { unsigned lba; // bits 24-27: bits 0-3 of DH lba = 0xf & lba28_regs->drive_head; lba <<= 8; // bits 16-23: CH lba |= lba28_regs->cylinder_high; lba <<= 8; // bits 8-15: CL lba |= lba28_regs->cylinder_low; lba <<= 8; // bits 0-7: SN lba |= lba28_regs->sector_number; str += strprintf(" at LBA = 0x%08x = %u", lba, lba); } else if (lba48_regs) { // This assumes that upper LBA registers are 0 for 28-bit commands // (TODO: detect 48-bit commands above) uint64_t lba48; lba48 = lba48_regs->lba_high_register_hi; lba48 <<= 8; lba48 |= lba48_regs->lba_mid_register_hi; lba48 <<= 8; lba48 |= lba48_regs->lba_low_register_hi; lba48 |= lba48_regs->device_register & 0xf; lba48 <<= 8; lba48 |= lba48_regs->lba_high_register; lba48 <<= 8; lba48 |= lba48_regs->lba_mid_register; lba48 <<= 8; lba48 |= lba48_regs->lba_low_register; str += strprintf(" at LBA = 0x%08"PRIx64" = %"PRIu64, lba48, lba48); } } return str; } static inline std::string format_st_er_desc( const ata_smart_errorlog_struct * data) { return format_st_er_desc( data->commands[4].commandreg, data->commands[4].featuresreg, data->error_struct.status, data->error_struct.error_register, data->error_struct.sector_count, &data->error_struct, (const ata_smart_exterrlog_error *)0); } static inline std::string format_st_er_desc( const ata_smart_exterrlog_error_log * data) { return format_st_er_desc( data->commands[4].command_register, data->commands[4].features_register, data->error.status_register, data->error.error_register, data->error.count_register_hi << 8 | data->error.count_register, (const ata_smart_errorlog_error_struct *)0, &data->error); } static int find_msb(unsigned short word) { for (int bit = 15; bit >= 0; bit--) if (word & (1 << bit)) return bit; return -1; } static const char * get_ata_major_version(const ata_identify_device * drive) { switch (find_msb(drive->major_rev_num)) { case 10: return "ACS-3"; case 9: return "ACS-2"; case 8: return "ATA8-ACS"; case 7: return "ATA/ATAPI-7"; case 6: return "ATA/ATAPI-6"; case 5: return "ATA/ATAPI-5"; case 4: return "ATA/ATAPI-4"; case 3: return "ATA-3"; case 2: return "ATA-2"; case 1: return "ATA-1"; default: return 0; } } static const char * get_ata_minor_version(const ata_identify_device * drive) { switch (drive->minor_rev_num) { case 0x0001: return "ATA-1 X3T9.2/781D prior to revision 4"; case 0x0002: return "ATA-1 published, ANSI X3.221-1994"; case 0x0003: return "ATA-1 X3T9.2/781D revision 4"; case 0x0004: return "ATA-2 published, ANSI X3.279-1996"; case 0x0005: return "ATA-2 X3T10/948D prior to revision 2k"; case 0x0006: return "ATA-3 X3T10/2008D revision 1"; case 0x0007: return "ATA-2 X3T10/948D revision 2k"; case 0x0008: return "ATA-3 X3T10/2008D revision 0"; case 0x0009: return "ATA-2 X3T10/948D revision 3"; case 0x000a: return "ATA-3 published, ANSI X3.298-1997"; case 0x000b: return "ATA-3 X3T10/2008D revision 6"; // 1st ATA-3 revision with SMART case 0x000c: return "ATA-3 X3T13/2008D revision 7 and 7a"; case 0x000d: return "ATA/ATAPI-4 X3T13/1153D revision 6"; case 0x000e: return "ATA/ATAPI-4 T13/1153D revision 13"; case 0x000f: return "ATA/ATAPI-4 X3T13/1153D revision 7"; case 0x0010: return "ATA/ATAPI-4 T13/1153D revision 18"; case 0x0011: return "ATA/ATAPI-4 T13/1153D revision 15"; case 0x0012: return "ATA/ATAPI-4 published, ANSI NCITS 317-1998"; case 0x0013: return "ATA/ATAPI-5 T13/1321D revision 3"; case 0x0014: return "ATA/ATAPI-4 T13/1153D revision 14"; case 0x0015: return "ATA/ATAPI-5 T13/1321D revision 1"; case 0x0016: return "ATA/ATAPI-5 published, ANSI NCITS 340-2000"; case 0x0017: return "ATA/ATAPI-4 T13/1153D revision 17"; case 0x0018: return "ATA/ATAPI-6 T13/1410D revision 0"; case 0x0019: return "ATA/ATAPI-6 T13/1410D revision 3a"; case 0x001a: return "ATA/ATAPI-7 T13/1532D revision 1"; case 0x001b: return "ATA/ATAPI-6 T13/1410D revision 2"; case 0x001c: return "ATA/ATAPI-6 T13/1410D revision 1"; case 0x001d: return "ATA/ATAPI-7 published, ANSI INCITS 397-2005"; case 0x001e: return "ATA/ATAPI-7 T13/1532D revision 0"; case 0x001f: return "ACS-3 T13/2161-D revision 3b"; case 0x0021: return "ATA/ATAPI-7 T13/1532D revision 4a"; case 0x0022: return "ATA/ATAPI-6 published, ANSI INCITS 361-2002"; case 0x0027: return "ATA8-ACS T13/1699-D revision 3c"; case 0x0028: return "ATA8-ACS T13/1699-D revision 6"; case 0x0029: return "ATA8-ACS T13/1699-D revision 4"; case 0x0031: return "ACS-2 T13/2015-D revision 2"; case 0x0033: return "ATA8-ACS T13/1699-D revision 3e"; case 0x0039: return "ATA8-ACS T13/1699-D revision 4c"; case 0x0042: return "ATA8-ACS T13/1699-D revision 3f"; case 0x0052: return "ATA8-ACS T13/1699-D revision 3b"; case 0x0107: return "ATA8-ACS T13/1699-D revision 2d"; case 0x0110: return "ACS-2 T13/2015-D revision 3"; default: return 0; } } static const char * get_sata_version(const ata_identify_device * drive) { unsigned short word222 = drive->words088_255[222-88]; if ((word222 & 0xf000) != 0x1000) return 0; switch (find_msb(word222 & 0x0fff)) { default: return "SATA >3.1"; case 6: return "SATA 3.1"; case 5: return "SATA 3.0"; case 4: return "SATA 2.6"; case 3: return "SATA 2.5"; case 2: return "SATA II Ext"; case 1: return "SATA 1.0a"; case 0: return "ATA8-AST"; case -1: return 0; } } static const char * get_sata_speed(int level) { if (level <= 0) return 0; switch (level) { default: return ">6.0 Gb/s"; case 3: return "6.0 Gb/s"; case 2: return "3.0 Gb/s"; case 1: return "1.5 Gb/s"; } } static const char * get_sata_maxspeed(const ata_identify_device * drive) { unsigned short word076 = drive->words047_079[76-47]; if (word076 & 0x0001) return 0; return get_sata_speed(find_msb(word076 & 0x00fe)); } static const char * get_sata_curspeed(const ata_identify_device * drive) { unsigned short word077 = drive->words047_079[77-47]; if (word077 & 0x0001) return 0; return get_sata_speed((word077 >> 1) & 0x7); } static void print_drive_info(const ata_identify_device * drive, const ata_size_info & sizes, int rpm, const drive_settings * dbentry) { // format drive information (with byte swapping as needed) char model[40+1], serial[20+1], firmware[8+1]; ata_format_id_string(model, drive->model, sizeof(model)-1); ata_format_id_string(serial, drive->serial_no, sizeof(serial)-1); ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1); // Print model family if known if (dbentry && *dbentry->modelfamily) pout("Model Family: %s\n", dbentry->modelfamily); pout("Device Model: %s\n", infofound(model)); if (!dont_print_serial_number) { pout("Serial Number: %s\n", infofound(serial)); unsigned oui = 0; uint64_t unique_id = 0; int naa = ata_get_wwn(drive, oui, unique_id); if (naa >= 0) pout("LU WWN Device Id: %x %06x %09"PRIx64"\n", naa, oui, unique_id); // Additional Product Identifier (OEM Id) string in words 170-173 // (e08130r1, added in ACS-2 Revision 1, December 17, 2008) if (0x2020 <= drive->words088_255[170-88] && drive->words088_255[170-88] <= 0x7e7e) { char add[8+1]; ata_format_id_string(add, (const unsigned char *)(drive->words088_255+170-88), sizeof(add)-1); if (add[0]) pout("Add. Product Id: %s\n", add); } } pout("Firmware Version: %s\n", infofound(firmware)); if (sizes.capacity) { // Print capacity char num[64], cap[32]; pout("User Capacity: %s bytes [%s]\n", format_with_thousands_sep(num, sizeof(num), sizes.capacity), format_capacity(cap, sizeof(cap), sizes.capacity)); // Print sector sizes. if (sizes.phy_sector_size == sizes.log_sector_size) pout("Sector Size: %u bytes logical/physical\n", sizes.log_sector_size); else { pout("Sector Sizes: %u bytes logical, %u bytes physical", sizes.log_sector_size, sizes.phy_sector_size); if (sizes.log_sector_offset) pout(" (offset %u bytes)", sizes.log_sector_offset); pout("\n"); } } // Print nominal media rotation rate if reported if (rpm) { if (rpm == 1) pout("Rotation Rate: Solid State Device\n"); else if (rpm > 1) pout("Rotation Rate: %d rpm\n", rpm); else pout("Rotation Rate: Unknown (0x%04x)\n", -rpm); } // See if drive is recognized pout("Device is: %s\n", !dbentry ? "Not in smartctl database [for details use: -P showall]": "In smartctl database [for details use: -P show]"); // Print ATA version std::string ataver; if ( (drive->major_rev_num != 0x0000 && drive->major_rev_num != 0xffff) || (drive->minor_rev_num != 0x0000 && drive->minor_rev_num != 0xffff)) { const char * majorver = get_ata_major_version(drive); const char * minorver = get_ata_minor_version(drive); if (majorver && minorver && str_starts_with(minorver, majorver)) { // Major and minor strings match, print minor string only ataver = minorver; } else { if (majorver) ataver = majorver; else ataver = strprintf("Unknown(0x%04x)", drive->major_rev_num); if (minorver) ataver += strprintf(", %s", minorver); else if (drive->minor_rev_num != 0x0000 && drive->minor_rev_num != 0xffff) ataver += strprintf(" (unknown minor revision code: 0x%04x)", drive->minor_rev_num); else ataver += " (minor revision not indicated)"; } } pout("ATA Version is: %s\n", infofound(ataver.c_str())); // If SATA drive print SATA version and speed const char * sataver = get_sata_version(drive); if (sataver) { const char * maxspeed = get_sata_maxspeed(drive); const char * curspeed = get_sata_curspeed(drive); pout("SATA Version is: %s%s%s%s%s%s\n", sataver, (maxspeed ? ", " : ""), (maxspeed ? maxspeed : ""), (curspeed ? " (current: " : ""), (curspeed ? curspeed : ""), (curspeed ? ")" : "")); } // print current time and date and timezone char timedatetz[DATEANDEPOCHLEN]; dateandtimezone(timedatetz); pout("Local Time is: %s\n", timedatetz); // Print warning message, if there is one if (dbentry && *dbentry->warningmsg) pout("\n==> WARNING: %s\n\n", dbentry->warningmsg); } static const char *OfflineDataCollectionStatus(unsigned char status_byte) { unsigned char stat=status_byte & 0x7f; switch(stat){ case 0x00: return "was never started"; case 0x02: return "was completed without error"; case 0x03: if (status_byte == 0x03) return "is in progress"; else return "is in a Reserved state"; case 0x04: return "was suspended by an interrupting command from host"; case 0x05: return "was aborted by an interrupting command from host"; case 0x06: return "was aborted by the device with a fatal error"; default: if (stat >= 0x40) return "is in a Vendor Specific state"; else return "is in a Reserved state"; } } // prints verbose value Off-line data collection status byte static void PrintSmartOfflineStatus(const ata_smart_values * data) { pout("Offline data collection status: (0x%02x)\t", (int)data->offline_data_collection_status); // Off-line data collection status byte is not a reserved // or vendor specific value pout("Offline data collection activity\n" "\t\t\t\t\t%s.\n", OfflineDataCollectionStatus(data->offline_data_collection_status)); // Report on Automatic Data Collection Status. Only IBM documents // this bit. See SFF 8035i Revision 2 for details. if (data->offline_data_collection_status & 0x80) pout("\t\t\t\t\tAuto Offline Data Collection: Enabled.\n"); else pout("\t\t\t\t\tAuto Offline Data Collection: Disabled.\n"); return; } static void PrintSmartSelfExecStatus(const ata_smart_values * data, firmwarebug_defs firmwarebugs) { pout("Self-test execution status: "); switch (data->self_test_exec_status >> 4) { case 0: pout("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("without error or no self-test has ever \n\t\t\t\t\tbeen run.\n"); break; case 1: pout("(%4d)\tThe self-test routine was aborted by\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("the host.\n"); break; case 2: pout("(%4d)\tThe self-test routine was interrupted\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("by the host with a hard or soft reset.\n"); break; case 3: pout("(%4d)\tA fatal error or unknown test error\n\t\t\t\t\t", (int)data->self_test_exec_status); 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: pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", (int)data->self_test_exec_status); 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: pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("the electrical element of the test\n\t\t\t\t\t"); pout("failed.\n"); break; case 6: pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("the servo (and/or seek) element of the \n\t\t\t\t\t"); pout("test failed.\n"); break; case 7: pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("the read element of the test failed.\n"); break; case 8: pout("(%4d)\tThe previous self-test completed having\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("a test element that failed and the\n\t\t\t\t\t"); pout("device is suspected of having handling\n\t\t\t\t\t"); pout("damage.\n"); break; case 15: if (firmwarebugs.is_set(BUG_SAMSUNG3) && data->self_test_exec_status == 0xf0) { pout("(%4d)\tThe previous self-test routine completed\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("with unknown result or self-test in\n\t\t\t\t\t"); pout("progress with less than 10%% remaining.\n"); } else { pout("(%4d)\tSelf-test routine in progress...\n\t\t\t\t\t", (int)data->self_test_exec_status); pout("%1d0%% of test remaining.\n", (int)(data->self_test_exec_status & 0x0f)); } break; default: pout("(%4d)\tReserved.\n", (int)data->self_test_exec_status); break; } } static void PrintSmartTotalTimeCompleteOffline (const ata_smart_values * data) { pout("Total time to complete Offline \n"); pout("data collection: \t\t(%5d) seconds.\n", (int)data->total_time_to_complete_off_line); } static void PrintSmartOfflineCollectCap(const ata_smart_values *data) { pout("Offline data collection\n"); pout("capabilities: \t\t\t (0x%02x) ", (int)data->offline_data_collection_capability); if (data->offline_data_collection_capability == 0x00){ pout("\tOffline data collection not supported.\n"); } else { pout( "%s\n", isSupportExecuteOfflineImmediate(data)? "SMART execute Offline immediate." : "No SMART execute Offline immediate."); pout( "\t\t\t\t\t%s\n", isSupportAutomaticTimer(data)? "Auto Offline data collection on/off support.": "No Auto Offline data collection support."); 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."); pout( "\t\t\t\t\t%s\n", isSupportOfflineSurfaceScan(data)? "Offline surface scan supported.": "No Offline surface scan supported."); pout( "\t\t\t\t\t%s\n", isSupportSelfTest(data)? "Self-test supported.": "No Self-test supported."); pout( "\t\t\t\t\t%s\n", isSupportConveyanceSelfTest(data)? "Conveyance Self-test supported.": "No Conveyance Self-test supported."); pout( "\t\t\t\t\t%s\n", isSupportSelectiveSelfTest(data)? "Selective Self-test supported.": "No Selective Self-test supported."); } } static void PrintSmartCapability(const ata_smart_values *data) { pout("SMART capabilities: "); pout("(0x%04x)\t", (int)data->smart_capability); if (data->smart_capability == 0x00) { pout("Automatic saving of SMART data\t\t\t\t\tis not implemented.\n"); } else { 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 ) { pout("\t\t\t\t\tSupports SMART auto save timer.\n"); } } } static void PrintSmartErrorLogCapability(const ata_smart_values * data, const ata_identify_device * identity) { pout("Error logging capability: "); if ( isSmartErrorLogCapable(data, identity) ) { pout(" (0x%02x)\tError logging supported.\n", (int)data->errorlog_capability); } else { pout(" (0x%02x)\tError logging NOT supported.\n", (int)data->errorlog_capability); } } static void PrintSmartShortSelfTestPollingTime(const ata_smart_values * data) { pout("Short self-test routine \n"); if (isSupportSelfTest(data)) pout("recommended polling time: \t (%4d) minutes.\n", (int)data->short_test_completion_time); else pout("recommended polling time: \t Not Supported.\n"); } static void PrintSmartExtendedSelfTestPollingTime(const ata_smart_values * data) { pout("Extended self-test routine\n"); if (isSupportSelfTest(data)) pout("recommended polling time: \t (%4d) minutes.\n", TestTime(data, EXTEND_SELF_TEST)); else pout("recommended polling time: \t Not Supported.\n"); } static void PrintSmartConveyanceSelfTestPollingTime(const ata_smart_values * data) { pout("Conveyance self-test routine\n"); if (isSupportConveyanceSelfTest(data)) pout("recommended polling time: \t (%4d) minutes.\n", (int)data->conveyance_test_completion_time); else pout("recommended polling time: \t Not Supported.\n"); } // Check SMART attribute table for Threshold failure // onlyfailed=0: are or were any age or prefailure attributes <= threshold // onlyfailed=1: are any prefailure attributes <= threshold now static int find_failed_attr(const ata_smart_values * data, const ata_smart_thresholds_pvt * thresholds, const ata_vendor_attr_defs & defs, int onlyfailed) { for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const ata_smart_attribute & attr = data->vendor_attributes[i]; ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs); if (!onlyfailed) { if (state >= ATTRSTATE_FAILED_PAST) return attr.id; } else { if (state == ATTRSTATE_FAILED_NOW && ATTRIBUTE_FLAGS_PREFAILURE(attr.flags)) return attr.id; } } return 0; } // onlyfailed=0 : print all attribute values // onlyfailed=1: just ones that are currently failed and have prefailure bit set // onlyfailed=2: ones that are failed, or have failed with or without prefailure bit set static void PrintSmartAttribWithThres(const ata_smart_values * data, const ata_smart_thresholds_pvt * thresholds, const ata_vendor_attr_defs & defs, int rpm, int onlyfailed, unsigned char format) { bool brief = !!(format & ata_print_options::FMT_BRIEF); bool hexid = !!(format & ata_print_options::FMT_HEX_ID); bool hexval = !!(format & ata_print_options::FMT_HEX_VAL); bool needheader = true; // step through all vendor attributes for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const ata_smart_attribute & attr = data->vendor_attributes[i]; // Check attribute and threshold unsigned char threshold = 0; ata_attr_state state = ata_get_attr_state(attr, i, thresholds->thres_entries, defs, &threshold); if (state == ATTRSTATE_NON_EXISTING) continue; // These break out of the loop if we are only printing certain entries... if (onlyfailed == 1 && !(ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) && state == ATTRSTATE_FAILED_NOW)) continue; if (onlyfailed == 2 && state < ATTRSTATE_FAILED_PAST) continue; // print header only if needed if (needheader) { if (!onlyfailed) { pout("SMART Attributes Data Structure revision number: %d\n",(int)data->revnumber); pout("Vendor Specific SMART Attributes with Thresholds:\n"); } if (!brief) pout("ID#%s ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE\n", (!hexid ? "" : " ")); else pout("ID#%s ATTRIBUTE_NAME FLAGS VALUE WORST THRESH FAIL RAW_VALUE\n", (!hexid ? "" : " ")); needheader = false; } // Format value, worst, threshold std::string valstr, worstr, threstr; if (state > ATTRSTATE_NO_NORMVAL) valstr = (!hexval ? strprintf("%.3d", attr.current) : strprintf("0x%02x", attr.current)); else valstr = (!hexval ? "---" : "----"); if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL)) worstr = (!hexval ? strprintf("%.3d", attr.worst) : strprintf("0x%02x", attr.worst)); else worstr = (!hexval ? "---" : "----"); if (state > ATTRSTATE_NO_THRESHOLD) threstr = (!hexval ? strprintf("%.3d", threshold) : strprintf("0x%02x", threshold)); else threstr = (!hexval ? "---" : "----"); // Print line for each valid attribute std::string idstr = (!hexid ? strprintf("%3d", attr.id) : strprintf("0x%02x", attr.id)); std::string attrname = ata_get_smart_attr_name(attr.id, defs, rpm); std::string rawstr = ata_format_attr_raw_value(attr, defs); if (!brief) pout("%s %-24s0x%04x %-4s %-4s %-4s %-10s%-9s%-12s%s\n", idstr.c_str(), attrname.c_str(), attr.flags, valstr.c_str(), worstr.c_str(), threstr.c_str(), (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) ? "Pre-fail" : "Old_age"), (ATTRIBUTE_FLAGS_ONLINE(attr.flags) ? "Always" : "Offline"), (state == ATTRSTATE_FAILED_NOW ? "FAILING_NOW" : state == ATTRSTATE_FAILED_PAST ? "In_the_past" : " -" ) , rawstr.c_str()); else pout("%s %-24s%c%c%c%c%c%c%c %-4s %-4s %-4s %-5s%s\n", idstr.c_str(), attrname.c_str(), (ATTRIBUTE_FLAGS_PREFAILURE(attr.flags) ? 'P' : '-'), (ATTRIBUTE_FLAGS_ONLINE(attr.flags) ? 'O' : '-'), (ATTRIBUTE_FLAGS_PERFORMANCE(attr.flags) ? 'S' : '-'), (ATTRIBUTE_FLAGS_ERRORRATE(attr.flags) ? 'R' : '-'), (ATTRIBUTE_FLAGS_EVENTCOUNT(attr.flags) ? 'C' : '-'), (ATTRIBUTE_FLAGS_SELFPRESERVING(attr.flags) ? 'K' : '-'), (ATTRIBUTE_FLAGS_OTHER(attr.flags) ? '+' : ' '), valstr.c_str(), worstr.c_str(), threstr.c_str(), (state == ATTRSTATE_FAILED_NOW ? "NOW" : state == ATTRSTATE_FAILED_PAST ? "Past" : "-" ), rawstr.c_str()); } if (!needheader) { if (!onlyfailed && brief) { int n = (!hexid ? 28 : 29); pout("%*s||||||_ K auto-keep\n" "%*s|||||__ C event count\n" "%*s||||___ R error rate\n" "%*s|||____ S speed/performance\n" "%*s||_____ O updated online\n" "%*s|______ P prefailure warning\n", n, "", n, "", n, "", n, "", n, "", n, ""); } pout("\n"); } } // Print SMART related SCT capabilities static void ataPrintSCTCapability(const ata_identify_device *drive) { unsigned short sctcaps = drive->words088_255[206-88]; if (!(sctcaps & 0x01)) return; pout("SCT capabilities: \t (0x%04x)\tSCT Status supported.\n", sctcaps); if (sctcaps & 0x08) pout("\t\t\t\t\tSCT Error Recovery Control supported.\n"); if (sctcaps & 0x10) pout("\t\t\t\t\tSCT Feature Control supported.\n"); if (sctcaps & 0x20) pout("\t\t\t\t\tSCT Data Table supported.\n"); } static void PrintGeneralSmartValues(const ata_smart_values *data, const ata_identify_device *drive, firmwarebug_defs firmwarebugs) { pout("General SMART Values:\n"); PrintSmartOfflineStatus(data); if (isSupportSelfTest(data)){ PrintSmartSelfExecStatus(data, firmwarebugs); } PrintSmartTotalTimeCompleteOffline(data); PrintSmartOfflineCollectCap(data); PrintSmartCapability(data); PrintSmartErrorLogCapability(data, drive); pout( "\t\t\t\t\t%s\n", isGeneralPurposeLoggingCapable(drive)? "General Purpose Logging supported.": "No General Purpose Logging support."); if (isSupportSelfTest(data)){ PrintSmartShortSelfTestPollingTime (data); PrintSmartExtendedSelfTestPollingTime (data); } if (isSupportConveyanceSelfTest(data)) PrintSmartConveyanceSelfTestPollingTime (data); ataPrintSCTCapability(drive); pout("\n"); } // Get # sectors of a log addr, 0 if log does not exist. static unsigned GetNumLogSectors(const ata_smart_log_directory * logdir, unsigned logaddr, bool gpl) { if (!logdir) return 0; if (logaddr > 0xff) return 0; if (logaddr == 0) return 1; unsigned n = logdir->entry[logaddr-1].numsectors; if (gpl) // GP logs may have >255 sectors n |= logdir->entry[logaddr-1].reserved << 8; return n; } // Get name of log. // Table A.2 of T13/2161-D (ACS-3) Revision 4, September 4, 2012 static const char * GetLogName(unsigned logaddr) { switch (logaddr) { case 0x00: return "Log Directory"; case 0x01: return "Summary SMART error log"; case 0x02: return "Comprehensive SMART error log"; case 0x03: return "Ext. Comprehensive SMART error log"; case 0x04: return "Device Statistics log"; case 0x05: return "Reserved for CFA"; // ACS-2 case 0x06: return "SMART self-test log"; case 0x07: return "Extended self-test log"; case 0x08: return "Power Conditions log"; // ACS-2 case 0x09: return "Selective self-test log"; case 0x0a: return "Device Statistics Notification"; // ACS-3 case 0x0b: return "Reserved for CFA"; // ACS-3 case 0x0d: return "LPS Mis-alignment log"; // ACS-2 case 0x10: return "NCQ Command Error log"; case 0x11: return "SATA Phy Event Counters"; case 0x12: return "SATA NCQ Queue Management log"; // ACS-3 case 0x13: return "SATA NCQ Send and Receive log"; // ACS-3 case 0x14: case 0x15: case 0x16: return "Reserved for Serial ATA"; case 0x19: return "LBA Status log"; // ACS-3 case 0x20: return "Streaming performance log [OBS-8]"; case 0x21: return "Write stream error log"; case 0x22: return "Read stream error log"; case 0x23: return "Delayed sector log [OBS-8]"; case 0x24: return "Current Device Internal Status Data log"; // ACS-3 case 0x25: return "Saved Device Internal Status Data log"; // ACS-3 case 0x30: return "IDENTIFY DEVICE data log"; // ACS-3 case 0xe0: return "SCT Command/Status"; case 0xe1: return "SCT Data Transfer"; default: if (0xa0 <= logaddr && logaddr <= 0xdf) return "Device vendor specific log"; if (0x80 <= logaddr && logaddr <= 0x9f) return "Host vendor specific log"; return "Reserved"; } /*NOTREACHED*/ } // Get log access permissions static const char * get_log_rw(unsigned logaddr) { if ( ( logaddr <= 0x08) || (0x0d == logaddr) || (0x10 <= logaddr && logaddr <= 0x13) || (0x19 == logaddr) || (0x20 <= logaddr && logaddr <= 0x25) || (0x30 == logaddr)) return "R/O"; if ( (0x09 <= logaddr && logaddr <= 0x0a) || (0x80 <= logaddr && logaddr <= 0x9f) || (0xe0 <= logaddr && logaddr <= 0xe1)) return "R/W"; if (0xa0 <= logaddr && logaddr <= 0xdf) return "VS"; // Vendor specific return "-"; // Unknown/Reserved } // Init a fake log directory, assume that standard logs are supported const ata_smart_log_directory * fake_logdir(ata_smart_log_directory * logdir, const ata_print_options & options) { memset(logdir, 0, sizeof(*logdir)); logdir->logversion = 255; logdir->entry[0x01-1].numsectors = 1; logdir->entry[0x03-1].numsectors = (options.smart_ext_error_log + (4-1)) / 4; logdir->entry[0x04-1].numsectors = 8; logdir->entry[0x06-1].numsectors = 1; logdir->entry[0x07-1].numsectors = (options.smart_ext_selftest_log + (19-1)) / 19; logdir->entry[0x09-1].numsectors = 1; logdir->entry[0x11-1].numsectors = 1; return logdir; } // Print SMART and/or GP Log Directory static void PrintLogDirectories(const ata_smart_log_directory * gplogdir, const ata_smart_log_directory * smartlogdir) { if (gplogdir) pout("General Purpose Log Directory Version %u\n", gplogdir->logversion); if (smartlogdir) pout("SMART %sLog Directory Version %u%s\n", (gplogdir ? " " : ""), smartlogdir->logversion, (smartlogdir->logversion==1 ? " [multi-sector log support]" : "")); pout("Address Access R/W Size Description\n"); for (unsigned i = 0; i <= 0xff; i++) { // Get number of sectors unsigned smart_numsect = GetNumLogSectors(smartlogdir, i, false); unsigned gp_numsect = GetNumLogSectors(gplogdir , i, true ); if (!(smart_numsect || gp_numsect)) continue; // Log does not exist const char * acc; unsigned size; if (smart_numsect == gp_numsect) { acc = "GPL,SL"; size = gp_numsect; } else if (!smart_numsect) { acc = "GPL"; size = gp_numsect; } else if (!gp_numsect) { acc = " SL"; size = smart_numsect; } else { acc = 0; size = 0; } unsigned i2 = i; if (acc && ((0x80 <= i && i < 0x9f) || (0xa0 <= i && i < 0xdf))) { // Find range of Host/Device vendor specific logs with same size unsigned imax = (i < 0x9f ? 0x9f : 0xdf); for (unsigned j = i+1; j <= imax; j++) { unsigned sn = GetNumLogSectors(smartlogdir, j, false); unsigned gn = GetNumLogSectors(gplogdir , j, true ); if (!(sn == smart_numsect && gn == gp_numsect)) break; i2 = j; } } const char * name = GetLogName(i); const char * rw = get_log_rw(i); if (i2 > i) { pout("0x%02x-0x%02x %-6s %-3s %5u %s\n", i, i2, acc, rw, size, name); i = i2; } else if (acc) pout( "0x%02x %-6s %-3s %5u %s\n", i, acc, rw, size, name); else { // GPL and SL support different sizes pout( "0x%02x %-6s %-3s %5u %s\n", i, "GPL", rw, gp_numsect, name); pout( "0x%02x %-6s %-3s %5u %s\n", i, "SL", rw, smart_numsect, name); } } pout("\n"); } // Print hexdump of log pages. // Format is compatible with 'xxd -r'. static void PrintLogPages(const char * type, const unsigned char * data, unsigned char logaddr, unsigned page, unsigned num_pages, unsigned max_pages) { pout("%s Log 0x%02x [%s], Page %u-%u (of %u)\n", type, logaddr, GetLogName(logaddr), page, page+num_pages-1, max_pages); for (unsigned i = 0; i < num_pages * 512; i += 16) { const unsigned char * p = data+i; pout("%07x: %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x ", (page * 512) + i, p[ 0], p[ 1], p[ 2], p[ 3], p[ 4], p[ 5], p[ 6], p[ 7], p[ 8], p[ 9], p[10], p[11], p[12], p[13], p[14], p[15]); #define P(n) (' ' <= p[n] && p[n] <= '~' ? (int)p[n] : '.') pout("|%c%c%c%c%c%c%c%c" "%c%c%c%c%c%c%c%c|\n", P( 0), P( 1), P( 2), P( 3), P( 4), P( 5), P( 6), P( 7), P( 8), P( 9), P(10), P(11), P(12), P(13), P(14), P(15)); #undef P if ((i & 0x1ff) == 0x1f0) pout("\n"); } } /////////////////////////////////////////////////////////////////////// // Device statistics (Log 0x04) // See Section A.5 of // ATA/ATAPI Command Set - 3 (ACS-3) // T13/2161-D Revision 2, February 21, 2012. struct devstat_entry_info { short size; // #bytes of value, -1 for signed char const char * name; }; const devstat_entry_info devstat_info_0x00[] = { { 2, "List of supported log pages" }, { 0, 0 } }; const devstat_entry_info devstat_info_0x01[] = { { 2, "General Statistics" }, { 4, "Lifetime Power-On Resets" }, { 4, "Power-on Hours" }, // spec says no flags(?) { 6, "Logical Sectors Written" }, { 6, "Number of Write Commands" }, { 6, "Logical Sectors Read" }, { 6, "Number of Read Commands" }, { 6, "Date and Time TimeStamp" }, // ACS-3 { 0, 0 } }; const devstat_entry_info devstat_info_0x02[] = { { 2, "Free-Fall Statistics" }, { 4, "Number of Free-Fall Events Detected" }, { 4, "Overlimit Shock Events" }, { 0, 0 } }; const devstat_entry_info devstat_info_0x03[] = { { 2, "Rotating Media Statistics" }, { 4, "Spindle Motor Power-on Hours" }, { 4, "Head Flying Hours" }, { 4, "Head Load Events" }, { 4, "Number of Reallocated Logical Sectors" }, { 4, "Read Recovery Attempts" }, { 4, "Number of Mechanical Start Failures" }, { 4, "Number of Realloc. Candidate Logical Sectors" }, // ACS-3 { 0, 0 } }; const devstat_entry_info devstat_info_0x04[] = { { 2, "General Errors Statistics" }, { 4, "Number of Reported Uncorrectable Errors" }, //{ 4, "Number of Resets Between Command Acceptance and Command Completion" }, { 4, "Resets Between Cmd Acceptance and Completion" }, { 0, 0 } }; const devstat_entry_info devstat_info_0x05[] = { { 2, "Temperature Statistics" }, { -1, "Current Temperature" }, { -1, "Average Short Term Temperature" }, { -1, "Average Long Term Temperature" }, { -1, "Highest Temperature" }, { -1, "Lowest Temperature" }, { -1, "Highest Average Short Term Temperature" }, { -1, "Lowest Average Short Term Temperature" }, { -1, "Highest Average Long Term Temperature" }, { -1, "Lowest Average Long Term Temperature" }, { 4, "Time in Over-Temperature" }, { -1, "Specified Maximum Operating Temperature" }, { 4, "Time in Under-Temperature" }, { -1, "Specified Minimum Operating Temperature" }, { 0, 0 } }; const devstat_entry_info devstat_info_0x06[] = { { 2, "Transport Statistics" }, { 4, "Number of Hardware Resets" }, { 4, "Number of ASR Events" }, { 4, "Number of Interface CRC Errors" }, { 0, 0 } }; const devstat_entry_info devstat_info_0x07[] = { { 2, "Solid State Device Statistics" }, { 1, "Percentage Used Endurance Indicator" }, { 0, 0 } }; const devstat_entry_info * devstat_infos[] = { devstat_info_0x00, devstat_info_0x01, devstat_info_0x02, devstat_info_0x03, devstat_info_0x04, devstat_info_0x05, devstat_info_0x06, devstat_info_0x07 }; const int num_devstat_infos = sizeof(devstat_infos)/sizeof(devstat_infos[0]); static void print_device_statistics_page(const unsigned char * data, int page, bool & need_trailer) { const devstat_entry_info * info = (page < num_devstat_infos ? devstat_infos[page] : 0); const char * name = (info ? info[0].name : "Unknown Statistics"); // Check page number in header static const char line[] = " ===== = = == "; if (!data[2]) { pout("%3d%s%s (empty) ==\n", page, line, name); return; } if (data[2] != page) { pout("%3d%s%s (invalid page %d in header) ==\n", page, line, name, data[2]); return; } pout("%3d%s%s (rev %d) ==\n", page, line, name, data[0]); // Print entries for (int i = 1, offset = 8; offset < 512-7; i++, offset+=8) { // Check for last known entry if (info && !info[i].size) info = 0; // Skip unsupported entries unsigned char flags = data[offset+7]; if (!(flags & 0x80)) continue; // Get value size, default to max if unknown int size = (info ? info[i].size : 7); // Format value char valstr[32]; if (flags & 0x40) { // valid flag // Get value int64_t val; if (size < 0) { val = (signed char)data[offset]; } else { val = 0; for (int j = 0; j < size; j++) val |= (int64_t)data[offset+j] << (j*8); } snprintf(valstr, sizeof(valstr), "%"PRId64, val); } else { // Value not known (yet) valstr[0] = '-'; valstr[1] = 0; } pout("%3d 0x%03x %d%c %15s%c %s\n", page, offset, abs(size), (flags & 0x1f ? '+' : ' '), // unknown flags valstr, (flags & 0x20 ? '~' : ' '), // normalized flag (info ? info[i].name : "Unknown")); if (flags & 0x20) need_trailer = true; } } static bool print_device_statistics(ata_device * device, unsigned nsectors, const std::vector & single_pages, bool all_pages, bool ssd_page) { // Read list of supported pages from page 0 unsigned char page_0[512] = {0, }; if (!ataReadLogExt(device, 0x04, 0, 0, page_0, 1)) { pout("Read Device Statistics page 0 failed\n\n"); return false; } unsigned char nentries = page_0[8]; if (!(page_0[2] == 0 && nentries > 0)) { pout("Device Statistics page 0 is invalid (page=%d, nentries=%d)\n\n", page_0[2], nentries); return false; } // Prepare list of pages to print std::vector pages; unsigned i; if (all_pages) { // Add all supported pages for (i = 0; i < nentries; i++) { int page = page_0[8+1+i]; if (page) pages.push_back(page); } ssd_page = false; } // Add manually specified pages bool print_page_0 = false; for (i = 0; i < single_pages.size() || ssd_page; i++) { int page = (i < single_pages.size() ? single_pages[i] : 7); if (!page) print_page_0 = true; else if (page >= (int)nsectors) pout("Device Statistics Log has only %u pages\n", nsectors); else pages.push_back(page); if (page == 7) ssd_page = false; } // Print list of supported pages if requested if (print_page_0) { pout("Device Statistics (GP Log 0x04) supported pages\n"); pout("Page Description\n"); for (i = 0; i < nentries; i++) { int page = page_0[8+1+i]; pout("%3d %s\n", page, (page < num_devstat_infos ? devstat_infos[page][0].name : "Unknown Statistics")); } pout("\n"); } // Read & print pages if (!pages.empty()) { pout("Device Statistics (GP Log 0x04)\n"); pout("Page Offset Size Value Description\n"); bool need_trailer = false; for (i = 0; i < pages.size(); i++) { int page = pages[i]; unsigned char page_n[512] = {0, }; if (!ataReadLogExt(device, 0x04, 0, page, page_n, 1)) { pout("Read Device Statistics page %d failed\n\n", page); return false; } print_device_statistics_page(page_n, page, need_trailer); } if (need_trailer) pout("%30s|_ ~ normalized value\n", ""); pout("\n"); } return true; } /////////////////////////////////////////////////////////////////////// // Print log 0x11 static void PrintSataPhyEventCounters(const unsigned char * data, bool reset) { if (checksum(data)) checksumwarning("SATA Phy Event Counters"); pout("SATA Phy Event Counters (GP Log 0x11)\n"); if (data[0] || data[1] || data[2] || data[3]) pout("[Reserved: 0x%02x 0x%02x 0x%02x 0x%02x]\n", data[0], data[1], data[2], data[3]); pout("ID Size Value Description\n"); for (unsigned i = 4; ; ) { // Get counter id and size (bits 14:12) unsigned id = data[i] | (data[i+1] << 8); unsigned size = ((id >> 12) & 0x7) << 1; id &= 0x8fff; // End of counter table ? if (!id) break; i += 2; if (!(2 <= size && size <= 8 && i + size < 512)) { pout("0x%04x %u: Invalid entry\n", id, size); break; } // Get value uint64_t val = 0, max_val = 0; for (unsigned j = 0; j < size; j+=2) { val |= (uint64_t)(data[i+j] | (data[i+j+1] << 8)) << (j*8); max_val |= (uint64_t)0xffffU << (j*8); } i += size; // Get name const char * name; switch (id) { case 0x001: name = "Command failed due to ICRC error"; break; // Mandatory case 0x002: name = "R_ERR response for data FIS"; break; case 0x003: name = "R_ERR response for device-to-host data FIS"; break; case 0x004: name = "R_ERR response for host-to-device data FIS"; break; case 0x005: name = "R_ERR response for non-data FIS"; break; case 0x006: name = "R_ERR response for device-to-host non-data FIS"; break; case 0x007: name = "R_ERR response for host-to-device non-data FIS"; break; case 0x008: name = "Device-to-host non-data FIS retries"; break; case 0x009: name = "Transition from drive PhyRdy to drive PhyNRdy"; break; case 0x00A: name = "Device-to-host register FISes sent due to a COMRESET"; break; // Mandatory case 0x00B: name = "CRC errors within host-to-device FIS"; break; case 0x00D: name = "Non-CRC errors within host-to-device FIS"; break; case 0x00F: name = "R_ERR response for host-to-device data FIS, CRC"; break; case 0x010: name = "R_ERR response for host-to-device data FIS, non-CRC"; break; case 0x012: name = "R_ERR response for host-to-device non-data FIS, CRC"; break; case 0x013: name = "R_ERR response for host-to-device non-data FIS, non-CRC"; break; default: name = (id & 0x8000 ? "Vendor specific" : "Unknown"); break; } // Counters stop at max value, add '+' in this case pout("0x%04x %u %12"PRIu64"%c %s\n", id, size, val, (val == max_val ? '+' : ' '), name); } if (reset) pout("All counters reset\n"); pout("\n"); } // Format milliseconds from error log entry as "DAYS+H:M:S.MSEC" static std::string format_milliseconds(unsigned msec) { unsigned days = msec / 86400000U; msec -= days * 86400000U; unsigned hours = msec / 3600000U; msec -= hours * 3600000U; unsigned min = msec / 60000U; msec -= min * 60000U; unsigned sec = msec / 1000U; msec -= sec * 1000U; std::string str; if (days) str = strprintf("%2ud+", days); str += strprintf("%02u:%02u:%02u.%03u", hours, min, sec, msec); return str; } // Get description for 'state' value from SMART Error Logs static const char * get_error_log_state_desc(unsigned state) { state &= 0x0f; switch (state){ case 0x0: return "in an unknown state"; case 0x1: return "sleeping"; case 0x2: return "in standby mode"; case 0x3: return "active or idle"; case 0x4: return "doing SMART Offline or Self-test"; default: return (state < 0xb ? "in a reserved state" : "in a vendor specific state"); } } // returns number of errors static int PrintSmartErrorlog(const ata_smart_errorlog *data, firmwarebug_defs firmwarebugs) { pout("SMART Error Log Version: %d\n", (int)data->revnumber); // if no errors logged, return if (!data->error_log_pointer){ pout("No Errors Logged\n\n"); return 0; } print_on(); // If log pointer out of range, return if (data->error_log_pointer>5){ pout("Invalid Error Log index = 0x%02x (T13/1321D rev 1c " "Section 8.41.6.8.2.2 gives valid range from 1 to 5)\n\n", (int)data->error_log_pointer); return 0; } // Some internal consistency checking of the data structures if ((data->ata_error_count-data->error_log_pointer) % 5 && !firmwarebugs.is_set(BUG_SAMSUNG2)) { pout("Warning: ATA error count %d inconsistent with error log pointer %d\n\n", data->ata_error_count,data->error_log_pointer); } // starting printing error log info if (data->ata_error_count<=5) pout( "ATA Error Count: %d\n", (int)data->ata_error_count); else pout( "ATA Error Count: %d (device log contains only the most recent five errors)\n", (int)data->ata_error_count); print_off(); pout("\tCR = Command Register [HEX]\n" "\tFR = Features Register [HEX]\n" "\tSC = Sector Count Register [HEX]\n" "\tSN = Sector Number Register [HEX]\n" "\tCL = Cylinder Low Register [HEX]\n" "\tCH = Cylinder High Register [HEX]\n" "\tDH = Device/Head Register [HEX]\n" "\tDC = Device Command Register [HEX]\n" "\tER = Error register [HEX]\n" "\tST = Status register [HEX]\n" "Powered_Up_Time is measured from power on, and printed as\n" "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n" "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n"); // now step through the five error log data structures (table 39 of spec) for (int k = 4; k >= 0; k-- ) { // The error log data structure entries are a circular buffer int j, i=(data->error_log_pointer+k)%5; const ata_smart_errorlog_struct * elog = data->errorlog_struct+i; const ata_smart_errorlog_error_struct * summary = &(elog->error_struct); // Spec says: unused error log structures shall be zero filled if (nonempty(elog, sizeof(*elog))){ // Table 57 of T13/1532D Volume 1 Revision 3 const char *msgstate = get_error_log_state_desc(summary->state); int days = (int)summary->timestamp/24; // See table 42 of ATA5 spec print_on(); pout("Error %d occurred at disk power-on lifetime: %d hours (%d days + %d hours)\n", (int)(data->ata_error_count+k-4), (int)summary->timestamp, days, (int)(summary->timestamp-24*days)); print_off(); pout(" When the command that caused the error occurred, the device was %s.\n\n",msgstate); pout(" After command completion occurred, registers were:\n" " ER ST SC SN CL CH DH\n" " -- -- -- -- -- -- --\n" " %02x %02x %02x %02x %02x %02x %02x", (int)summary->error_register, (int)summary->status, (int)summary->sector_count, (int)summary->sector_number, (int)summary->cylinder_low, (int)summary->cylinder_high, (int)summary->drive_head); // Add a description of the contents of the status and error registers // if possible std::string st_er_desc = format_st_er_desc(elog); if (!st_er_desc.empty()) pout(" %s", st_er_desc.c_str()); pout("\n\n"); pout(" Commands leading to the command that caused the error were:\n" " CR FR SC SN CL CH DH DC Powered_Up_Time Command/Feature_Name\n" " -- -- -- -- -- -- -- -- ---------------- --------------------\n"); for ( j = 4; j >= 0; j--){ const ata_smart_errorlog_command_struct * thiscommand = elog->commands+j; // Spec says: unused data command structures shall be zero filled if (nonempty(thiscommand, sizeof(*thiscommand))) { pout(" %02x %02x %02x %02x %02x %02x %02x %02x %16s %s\n", (int)thiscommand->commandreg, (int)thiscommand->featuresreg, (int)thiscommand->sector_count, (int)thiscommand->sector_number, (int)thiscommand->cylinder_low, (int)thiscommand->cylinder_high, (int)thiscommand->drive_head, (int)thiscommand->devicecontrolreg, format_milliseconds(thiscommand->timestamp).c_str(), look_up_ata_command(thiscommand->commandreg, thiscommand->featuresreg)); } } pout("\n"); } } print_on(); if (printing_is_switchable) pout("\n"); print_off(); return data->ata_error_count; } // Print SMART Extended Comprehensive Error Log (GP Log 0x03) static int PrintSmartExtErrorLog(const ata_smart_exterrlog * log, unsigned nsectors, unsigned max_errors) { pout("SMART Extended Comprehensive Error Log Version: %u (%u sectors)\n", log->version, nsectors); if (!log->device_error_count) { pout("No Errors Logged\n\n"); return 0; } print_on(); // Check index unsigned nentries = nsectors * 4; unsigned erridx = log->error_log_index; if (!(1 <= erridx && erridx <= nentries)){ // Some Samsung disks (at least SP1614C/SW100-25, HD300LJ/ZT100-12) use the // former index from Summary Error Log (byte 1, now reserved) and set byte 2-3 // to 0. if (!(erridx == 0 && 1 <= log->reserved1 && log->reserved1 <= nentries)) { pout("Invalid Error Log index = 0x%04x (reserved = 0x%02x)\n", erridx, log->reserved1); return 0; } pout("Invalid Error Log index = 0x%04x, trying reserved byte (0x%02x) instead\n", erridx, log->reserved1); erridx = log->reserved1; } // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a), // it is 1-based in practice. erridx--; // Calculate #errors to print unsigned errcnt = log->device_error_count; if (errcnt <= nentries) pout("Device Error Count: %u\n", log->device_error_count); else { errcnt = nentries; pout("Device Error Count: %u (device log contains only the most recent %u errors)\n", log->device_error_count, errcnt); } if (max_errors < errcnt) errcnt = max_errors; print_off(); pout("\tCR = Command Register\n" "\tFEATR = Features Register\n" "\tCOUNT = Count (was: Sector Count) Register\n" "\tLBA_48 = Upper bytes of LBA High/Mid/Low Registers ] ATA-8\n" "\tLH = LBA High (was: Cylinder High) Register ] LBA\n" "\tLM = LBA Mid (was: Cylinder Low) Register ] Register\n" "\tLL = LBA Low (was: Sector Number) Register ]\n" "\tDV = Device (was: Device/Head) Register\n" "\tDC = Device Control Register\n" "\tER = Error register\n" "\tST = Status register\n" "Powered_Up_Time is measured from power on, and printed as\n" "DDd+hh:mm:SS.sss where DD=days, hh=hours, mm=minutes,\n" "SS=sec, and sss=millisec. It \"wraps\" after 49.710 days.\n\n"); // Iterate through circular buffer in reverse direction for (unsigned i = 0, errnum = log->device_error_count; i < errcnt; i++, errnum--, erridx = (erridx > 0 ? erridx - 1 : nentries - 1)) { const ata_smart_exterrlog_error_log & entry = log[erridx / 4].error_logs[erridx % 4]; // Skip unused entries if (!nonempty(&entry, sizeof(entry))) { pout("Error %u [%u] log entry is empty\n", errnum, erridx); continue; } // Print error information print_on(); const ata_smart_exterrlog_error & err = entry.error; pout("Error %u [%u] occurred at disk power-on lifetime: %u hours (%u days + %u hours)\n", errnum, erridx, err.timestamp, err.timestamp / 24, err.timestamp % 24); print_off(); pout(" When the command that caused the error occurred, the device was %s.\n\n", get_error_log_state_desc(err.state)); // Print registers pout(" After command completion occurred, registers were:\n" " ER -- ST COUNT LBA_48 LH LM LL DV DC\n" " -- -- -- == -- == == == -- -- -- -- --\n" " %02x -- %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", err.error_register, err.status_register, err.count_register_hi, err.count_register, err.lba_high_register_hi, err.lba_mid_register_hi, err.lba_low_register_hi, err.lba_high_register, err.lba_mid_register, err.lba_low_register, err.device_register, err.device_control_register); // Add a description of the contents of the status and error registers // if possible std::string st_er_desc = format_st_er_desc(&entry); if (!st_er_desc.empty()) pout(" %s", st_er_desc.c_str()); pout("\n\n"); // Print command history pout(" Commands leading to the command that caused the error were:\n" " CR FEATR COUNT LBA_48 LH LM LL DV DC Powered_Up_Time Command/Feature_Name\n" " -- == -- == -- == == == -- -- -- -- -- --------------- --------------------\n"); for (int ci = 4; ci >= 0; ci--) { const ata_smart_exterrlog_command & cmd = entry.commands[ci]; // Skip unused entries if (!nonempty(&cmd, sizeof(cmd))) continue; // Print registers, timestamp and ATA command name pout(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %16s %s\n", cmd.command_register, cmd.features_register_hi, cmd.features_register, cmd.count_register_hi, cmd.count_register, cmd.lba_high_register_hi, cmd.lba_mid_register_hi, cmd.lba_low_register_hi, cmd.lba_high_register, cmd.lba_mid_register, cmd.lba_low_register, cmd.device_register, cmd.device_control_register, format_milliseconds(cmd.timestamp).c_str(), look_up_ata_command(cmd.command_register, cmd.features_register)); } pout("\n"); } print_on(); if (printing_is_switchable) pout("\n"); print_off(); return log->device_error_count; } // Print SMART Extended Self-test Log (GP Log 0x07) static int PrintSmartExtSelfTestLog(const ata_smart_extselftestlog * log, unsigned nsectors, unsigned max_entries) { pout("SMART Extended Self-test Log Version: %u (%u sectors)\n", log->version, nsectors); if (!log->log_desc_index){ pout("No self-tests have been logged. [To run self-tests, use: smartctl -t]\n\n"); return 0; } // Check index unsigned nentries = nsectors * 19; unsigned logidx = log->log_desc_index; if (logidx > nentries) { pout("Invalid Self-test Log index = 0x%04x (reserved = 0x%02x)\n", logidx, log->reserved1); return 0; } // Index base is not clearly specified by ATA8-ACS (T13/1699-D Revision 6a), // it is 1-based in practice. logidx--; bool print_header = true; int errcnt = 0, igncnt = 0; int ext_ok_testnum = -1; // Iterate through circular buffer in reverse direction for (unsigned i = 0, testnum = 1; i < nentries && testnum <= max_entries; i++, logidx = (logidx > 0 ? logidx - 1 : nentries - 1)) { const ata_smart_extselftestlog_desc & entry = log[logidx / 19].log_descs[logidx % 19]; // Skip unused entries if (!nonempty(&entry, sizeof(entry))) continue; // Get LBA const unsigned char * b = entry.failing_lba; uint64_t lba48 = b[0] | ( b[1] << 8) | ( b[2] << 16) | ((uint64_t)b[3] << 24) | ((uint64_t)b[4] << 32) | ((uint64_t)b[5] << 40); // Print entry int state = ataPrintSmartSelfTestEntry(testnum, entry.self_test_type, entry.self_test_status, entry.timestamp, lba48, false /*!print_error_only*/, print_header); if (state < 0) { // Self-test showed an error if (ext_ok_testnum < 0) errcnt++; else // Newer successful extended self-test exits igncnt++; } else if (state > 0 && ext_ok_testnum < 0) { // Latest successful extended self-test ext_ok_testnum = testnum; } testnum++; } if (igncnt) pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n", igncnt, igncnt+errcnt, ext_ok_testnum); pout("\n"); return errcnt; } static void ataPrintSelectiveSelfTestLog(const ata_selective_self_test_log * log, const ata_smart_values * sv) { int i,field1,field2; const char *msg; char tmp[64]; uint64_t maxl=0,maxr=0; uint64_t current=log->currentlba; uint64_t currentend=current+65535; // print data structure revision number pout("SMART Selective self-test log data structure revision number %d\n",(int)log->logversion); if (1 != log->logversion) pout("Note: revision number not 1 implies that no selective self-test has ever been run\n"); switch((sv->self_test_exec_status)>>4){ case 0:msg="Completed"; break; case 1:msg="Aborted_by_host"; break; case 2:msg="Interrupted"; break; case 3:msg="Fatal_error"; break; case 4:msg="Completed_unknown_failure"; break; case 5:msg="Completed_electrical_failure"; break; case 6:msg="Completed_servo/seek_failure"; break; case 7:msg="Completed_read_failure"; break; case 8:msg="Completed_handling_damage??"; break; case 15:msg="Self_test_in_progress"; break; default:msg="Unknown_status "; break; } // find the number of columns needed for printing. If in use, the // start/end of span being read-scanned... if (log->currentspan>5) { maxl=current; maxr=currentend; } for (i=0; i<5; i++) { uint64_t start=log->span[i].start; uint64_t end =log->span[i].end; // ... plus max start/end of each of the five test spans. if (start>maxl) maxl=start; if (end > maxr) maxr=end; } // we need at least 7 characters wide fields to accomodate the // labels if ((field1=snprintf(tmp,64, "%"PRIu64, maxl))<7) field1=7; if ((field2=snprintf(tmp,64, "%"PRIu64, maxr))<7) field2=7; // now print the five test spans pout(" SPAN %*s %*s CURRENT_TEST_STATUS\n", field1, "MIN_LBA", field2, "MAX_LBA"); for (i=0; i<5; i++) { uint64_t start=log->span[i].start; uint64_t end=log->span[i].end; if ((i+1)==(int)log->currentspan) // this span is currently under test pout(" %d %*"PRIu64" %*"PRIu64" %s [%01d0%% left] (%"PRIu64"-%"PRIu64")\n", i+1, field1, start, field2, end, msg, (int)(sv->self_test_exec_status & 0xf), current, currentend); else // this span is not currently under test pout(" %d %*"PRIu64" %*"PRIu64" Not_testing\n", i+1, field1, start, field2, end); } // if we are currently read-scanning, print LBAs and the status of // the read scan if (log->currentspan>5) pout("%5d %*"PRIu64" %*"PRIu64" Read_scanning %s\n", (int)log->currentspan, field1, current, field2, currentend, OfflineDataCollectionStatus(sv->offline_data_collection_status)); /* Print selective self-test flags. Possible flag combinations are (numbering bits from 0-15): Bit-1 Bit-3 Bit-4 Scan Pending Active 0 * * Don't scan 1 0 0 Will carry out scan after selective test 1 1 0 Waiting to carry out scan after powerup 1 0 1 Currently scanning 1 1 1 Currently scanning */ pout("Selective self-test flags (0x%x):\n", (unsigned int)log->flags); if (log->flags & SELECTIVE_FLAG_DOSCAN) { if (log->flags & SELECTIVE_FLAG_ACTIVE) pout(" Currently read-scanning the remainder of the disk.\n"); else if (log->flags & SELECTIVE_FLAG_PENDING) pout(" Read-scan of remainder of disk interrupted; will resume %d min after power-up.\n", (int)log->pendingtime); else pout(" After scanning selected spans, read-scan remainder of disk.\n"); } else pout(" After scanning selected spans, do NOT read-scan remainder of disk.\n"); // print pending time pout("If Selective self-test is pending on power-up, resume after %d minute delay.\n", (int)log->pendingtime); return; } // Format SCT Temperature value static const char * sct_ptemp(signed char x, char (& buf)[20]) { if (x == -128 /*0x80 = unknown*/) return " ?"; snprintf(buf, sizeof(buf), "%2d", x); return buf; } static const char * sct_pbar(int x, char (& buf)[64]) { if (x <= 19) x = 0; else x -= 19; bool ov = false; if (x > 40) { x = 40; ov = true; } if (x > 0) { memset(buf, '*', x); if (ov) buf[x-1] = '+'; buf[x] = 0; } else { buf[0] = '-'; buf[1] = 0; } return buf; } static const char * sct_device_state_msg(unsigned char state) { switch (state) { case 0: return "Active"; case 1: return "Stand-by"; case 2: return "Sleep"; case 3: return "DST executing in background"; case 4: return "SMART Off-line Data Collection executing in background"; case 5: return "SCT command executing in background"; default:return "Unknown"; } } // Print SCT Status static int ataPrintSCTStatus(const ata_sct_status_response * sts) { pout("SCT Status Version: %u\n", sts->format_version); pout("SCT Version (vendor specific): %u (0x%04x)\n", sts->sct_version, sts->sct_version); pout("SCT Support Level: %u\n", sts->sct_spec); pout("Device State: %s (%u)\n", sct_device_state_msg(sts->device_state), sts->device_state); char buf1[20], buf2[20]; if ( !sts->min_temp && !sts->life_min_temp && !sts->under_limit_count && !sts->over_limit_count) { // "Reserved" fields not set, assume "old" format version 2 // Table 11 of T13/1701DT-N (SMART Command Transport) Revision 5, February 2005 // Table 54 of T13/1699-D (ATA8-ACS) Revision 3e, July 2006 pout("Current Temperature: %s Celsius\n", sct_ptemp(sts->hda_temp, buf1)); pout("Power Cycle Max Temperature: %s Celsius\n", sct_ptemp(sts->max_temp, buf2)); pout("Lifetime Max Temperature: %s Celsius\n", sct_ptemp(sts->life_max_temp, buf2)); } else { // Assume "new" format version 2 or version 3 // T13/e06152r0-3 (Additional SCT Temperature Statistics), August - October 2006 // Table 60 of T13/1699-D (ATA8-ACS) Revision 3f, December 2006 (format version 2) // Table 80 of T13/1699-D (ATA8-ACS) Revision 6a, September 2008 (format version 3) pout("Current Temperature: %s Celsius\n", sct_ptemp(sts->hda_temp, buf1)); pout("Power Cycle Min/Max Temperature: %s/%s Celsius\n", sct_ptemp(sts->min_temp, buf1), sct_ptemp(sts->max_temp, buf2)); pout("Lifetime Min/Max Temperature: %s/%s Celsius\n", sct_ptemp(sts->life_min_temp, buf1), sct_ptemp(sts->life_max_temp, buf2)); signed char avg = sts->byte205; // Average Temperature from e06152r0-2, removed in e06152r3 if (0 < avg && sts->life_min_temp <= avg && avg <= sts->life_max_temp) pout("Lifetime Average Temperature: %2d Celsius\n", avg); pout("Under/Over Temperature Limit Count: %2u/%u\n", sts->under_limit_count, sts->over_limit_count); } return 0; } // Print SCT Temperature History Table static int ataPrintSCTTempHist(const ata_sct_temperature_history_table * tmh) { char buf1[20], buf2[20], buf3[64]; pout("SCT Temperature History Version: %u%s\n", tmh->format_version, (tmh->format_version != 2 ? " (Unknown, should be 2)" : "")); pout("Temperature Sampling Period: %u minute%s\n", tmh->sampling_period, (tmh->sampling_period==1?"":"s")); pout("Temperature Logging Interval: %u minute%s\n", tmh->interval, (tmh->interval==1?"":"s")); pout("Min/Max recommended Temperature: %s/%s Celsius\n", sct_ptemp(tmh->min_op_limit, buf1), sct_ptemp(tmh->max_op_limit, buf2)); pout("Min/Max Temperature Limit: %s/%s Celsius\n", sct_ptemp(tmh->under_limit, buf1), sct_ptemp(tmh->over_limit, buf2)); pout("Temperature History Size (Index): %u (%u)\n", tmh->cb_size, tmh->cb_index); if (!(0 < tmh->cb_size && tmh->cb_size <= sizeof(tmh->cb) && tmh->cb_index < tmh->cb_size)) { if (!tmh->cb_size) pout("Temperature History is empty\n"); else pout("Invalid Temperature History Size or Index\n"); return 0; } // Print table pout("\nIndex Estimated Time Temperature Celsius\n"); unsigned n = 0, i = (tmh->cb_index+1) % tmh->cb_size; unsigned interval = (tmh->interval > 0 ? tmh->interval : 1); time_t t = time(0) - (tmh->cb_size-1) * interval * 60; t -= t % (interval * 60); while (n < tmh->cb_size) { // Find range of identical temperatures unsigned n1 = n, n2 = n+1, i2 = (i+1) % tmh->cb_size; while (n2 < tmh->cb_size && tmh->cb[i2] == tmh->cb[i]) { n2++; i2 = (i2+1) % tmh->cb_size; } // Print range while (n < n2) { if (n == n1 || n == n2-1 || n2 <= n1+3) { char date[30]; // TODO: Don't print times < boot time strftime(date, sizeof(date), "%Y-%m-%d %H:%M", localtime(&t)); pout(" %3u %s %s %s\n", i, date, sct_ptemp(tmh->cb[i], buf1), sct_pbar(tmh->cb[i], buf3)); } else if (n == n1+1) { pout(" ... ..(%3u skipped). .. %s\n", n2-n1-2, sct_pbar(tmh->cb[i], buf3)); } t += interval * 60; i = (i+1) % tmh->cb_size; n++; } } //assert(n == tmh->cb_size && i == (tmh->cb_index+1) % tmh->cb_size); return 0; } // Print SCT Error Recovery Control timers static void ataPrintSCTErrorRecoveryControl(bool set, unsigned short read_timer, unsigned short write_timer) { pout("SCT Error Recovery Control%s:\n", (set ? " set to" : "")); if (!read_timer) pout(" Read: Disabled\n"); else pout(" Read: %6d (%0.1f seconds)\n", read_timer, read_timer/10.0); if (!write_timer) pout(" Write: Disabled\n"); else pout(" Write: %6d (%0.1f seconds)\n", write_timer, write_timer/10.0); } static void print_aam_level(const char * msg, int level, int recommended = -1) { // Table 56 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008 // Obsolete since T13/2015-D (ACS-2) Revision 4a, December 9, 2010 const char * s; if (level == 0) s = "vendor specific"; else if (level < 128) s = "unknown/retired"; else if (level == 128) s = "quiet"; else if (level < 254) s = "intermediate"; else if (level == 254) s = "maximum performance"; else s = "reserved"; if (recommended >= 0) pout("%s%d (%s), recommended: %d\n", msg, level, s, recommended); else pout("%s%d (%s)\n", msg, level, s); } static void print_apm_level(const char * msg, int level) { // Table 120 of T13/2015-D (ACS-2) Revision 7, June 22, 2011 const char * s; if (!(1 <= level && level <= 254)) s = "reserved"; else if (level == 1) s = "minimum power consumption with standby"; else if (level < 128) s = "intermediate level with standby"; else if (level == 128) s = "minimum power consumption without standby"; else if (level < 254) s = "intermediate level without standby"; else s = "maximum performance"; pout("%s%d (%s)\n", msg, level, s); } static void print_ata_security_status(const char * msg, unsigned short state) { const char * s1, * s2 = "", * s3 = "", * s4 = ""; // Table 6 of T13/2015-D (ACS-2) Revision 7, June 22, 2011 if (!(state & 0x0001)) s1 = "Unavailable"; else if (!(state & 0x0002)) { s1 = "Disabled, "; if (!(state & 0x0008)) s2 = "NOT FROZEN [SEC1]"; else s2 = "frozen [SEC2]"; } else { s1 = "ENABLED, PW level "; if (!(state & 0x0020)) s2 = "HIGH"; else s2 = "MAX"; if (!(state & 0x0004)) { s3 = ", not locked, "; if (!(state & 0x0008)) s4 = "not frozen [SEC5]"; else s4 = "frozen [SEC6]"; } else { s3 = ", **LOCKED** [SEC4]"; if (state & 0x0010) s4 = ", PW ATTEMPTS EXCEEDED"; } } pout("%s%s%s%s%s\n", msg, s1, s2, s3, s4); } static void print_standby_timer(const char * msg, int timer, const ata_identify_device & drive) { const char * s1 = 0; int hours = 0, minutes = 0 , seconds = 0; // Table 63 of T13/2015-D (ACS-2) Revision 7, June 22, 2011 if (timer == 0) s1 = "disabled"; else if (timer <= 240) seconds = timer * 5, minutes = seconds / 60, seconds %= 60; else if (timer <= 251) minutes = (timer - 240) * 30, hours = minutes / 60, minutes %= 60; else if (timer == 252) minutes = 21; else if (timer == 253) s1 = "between 8 hours and 12 hours"; else if (timer == 255) minutes = 21, seconds = 15; else s1 = "reserved"; const char * s2 = "", * s3 = ""; if (!(drive.words047_079[49-47] & 0x2000)) s2 = " or vendor-specific"; if (timer > 0 && (drive.words047_079[50-47] & 0xc001) == 0x4001) s3 = ", a vendor-specific minimum applies"; if (s1) pout("%s%d (%s%s%s)\n", msg, timer, s1, s2, s3); else pout("%s%d (%02d:%02d:%02d%s%s)\n", msg, timer, hours, minutes, seconds, s2, s3); } int ataPrintMain (ata_device * device, const ata_print_options & options) { // If requested, check power mode first const char * powername = 0; bool powerchg = false; if (options.powermode) { unsigned char powerlimit = 0xff; int powermode = ataCheckPowerMode(device); switch (powermode) { case -1: if (device->is_syscall_unsup()) { pout("CHECK POWER MODE not implemented, ignoring -n option\n"); break; } powername = "SLEEP"; powerlimit = 2; break; case 0: powername = "STANDBY"; powerlimit = 3; break; case 0x80: powername = "IDLE"; powerlimit = 4; break; case 0xff: powername = "ACTIVE or IDLE"; break; default: pout("CHECK POWER MODE returned unknown value 0x%02x, ignoring -n option\n", powermode); break; } if (powername) { if (options.powermode >= powerlimit) { pout("Device is in %s mode, exit(%d)\n", powername, FAILPOWER); return FAILPOWER; } powerchg = (powermode != 0xff); // SMART tests will spin up drives } } // SMART values needed ? bool need_smart_val = ( options.smart_check_status || options.smart_general_values || options.smart_vendor_attrib || options.smart_error_log || options.smart_selftest_log || options.smart_selective_selftest_log || options.smart_ext_error_log || options.smart_ext_selftest_log || options.smart_auto_offl_enable || options.smart_auto_offl_disable || options.smart_selftest_type != -1 ); // SMART must be enabled ? bool need_smart_enabled = ( need_smart_val || options.smart_auto_save_enable || options.smart_auto_save_disable ); // SMART feature set needed ? bool need_smart_support = ( need_smart_enabled || options.smart_enable || options.smart_disable ); // SMART and GP log directories needed ? bool need_smart_logdir = options.smart_logdir; bool need_gp_logdir = ( options.gp_logdir || options.smart_ext_error_log || options.smart_ext_selftest_log || options.devstat_all_pages || options.devstat_ssd_page || !options.devstat_pages.empty() ); unsigned i; for (i = 0; i < options.log_requests.size(); i++) { if (options.log_requests[i].gpl) need_gp_logdir = true; else need_smart_logdir = true; } // SCT commands needed ? bool need_sct_support = ( options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int || options.sct_erc_get || options.sct_erc_set || options.sct_wcache_reorder_get || options.sct_wcache_reorder_set ); // Exit if no further options specified if (!( options.drive_info || options.show_presets || need_smart_support || need_smart_logdir || need_gp_logdir || need_sct_support || options.sataphy || options.identify_word_level >= 0 || options.get_set_used )) { if (powername) pout("Device is in %s mode\n", powername); else pout("ATA device successfully opened\n\n" "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n"); return 0; } // Start by getting Drive ID information. We need this, to know if SMART is supported. int returnval = 0; ata_identify_device drive; memset(&drive, 0, sizeof(drive)); unsigned char raw_drive[sizeof(drive)]; memset(&raw_drive, 0, sizeof(raw_drive)); device->clear_err(); int retid = ata_read_identity(device, &drive, options.fix_swapped_id, raw_drive); if (retid < 0) { pout("Read Device Identity failed: %s\n\n", (device->get_errno() ? device->get_errmsg() : "Unknown error")); failuretest(MANDATORY_CMD, returnval|=FAILID); } else if (!nonempty(&drive, sizeof(drive))) { pout("Read Device Identity failed: empty IDENTIFY data\n\n"); failuretest(MANDATORY_CMD, returnval|=FAILID); } // If requested, show which presets would be used for this drive and exit. if (options.show_presets) { show_presets(&drive); return 0; } // Use preset vendor attribute options unless user has requested otherwise. ata_vendor_attr_defs attribute_defs = options.attribute_defs; firmwarebug_defs firmwarebugs = options.firmwarebugs; const drive_settings * dbentry = 0; if (!options.ignore_presets) dbentry = lookup_drive_apply_presets(&drive, attribute_defs, firmwarebugs); // Get capacity, sector sizes and rotation rate ata_size_info sizes; ata_get_size_info(&drive, sizes); int rpm = ata_get_rotation_rate(&drive); // Print ATA IDENTIFY info if requested if (options.identify_word_level >= 0) { pout("=== ATA IDENTIFY DATA ===\n"); // Pass raw data without endianness adjustments ata_print_identify_data(raw_drive, (options.identify_word_level > 0), options.identify_bit_level); } // Print most drive identity information if requested if (options.drive_info) { pout("=== START OF INFORMATION SECTION ===\n"); print_drive_info(&drive, sizes, rpm, dbentry); } // Check and print SMART support and state int smart_supported = -1, smart_enabled = -1; if (need_smart_support || options.drive_info) { // Packet device ? if (retid > 0) { pout("SMART support is: Unavailable - Packet Interface Devices [this device: %s] don't support ATA SMART\n", packetdevicetype(retid-1)); } else { // Disk device: SMART supported and enabled ? smart_supported = ataSmartSupport(&drive); smart_enabled = ataIsSmartEnabled(&drive); if (smart_supported < 0) pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 82-83 don't show if SMART supported.\n"); if (smart_supported && smart_enabled < 0) { pout("SMART support is: Ambiguous - ATA IDENTIFY DEVICE words 85-87 don't show if SMART is enabled.\n"); if (need_smart_support) { failuretest(MANDATORY_CMD, returnval|=FAILSMART); // check SMART support by trying a command pout(" Checking to be sure by trying SMART RETURN STATUS command.\n"); if (ataDoesSmartWork(device)) smart_supported = smart_enabled = 1; } } else if (smart_supported < 0 && (smart_enabled > 0 || dbentry)) // Assume supported if enabled or in drive database smart_supported = 1; if (smart_supported < 0) pout("SMART support is: Unknown - Try option -s with argument 'on' to enable it."); else if (!smart_supported) pout("SMART support is: Unavailable - device lacks SMART capability.\n"); else { if (options.drive_info) pout("SMART support is: Available - device has SMART capability.\n"); if (smart_enabled >= 0) { if (device->ata_identify_is_cached()) { if (options.drive_info) pout(" %sabled status cached by OS, trying SMART RETURN STATUS cmd.\n", (smart_enabled?"En":"Dis")); smart_enabled = ataDoesSmartWork(device); } if (options.drive_info) pout("SMART support is: %s\n", (smart_enabled ? "Enabled" : "Disabled")); } } } } // Print AAM status if (options.get_aam) { if ((drive.command_set_2 & 0xc200) != 0x4200) // word083 pout("AAM feature is: Unavailable\n"); else if (!(drive.word086 & 0x0200)) pout("AAM feature is: Disabled\n"); else print_aam_level("AAM level is: ", drive.words088_255[94-88] & 0xff, drive.words088_255[94-88] >> 8); } // Print APM status if (options.get_apm) { if ((drive.command_set_2 & 0xc008) != 0x4008) // word083 pout("APM feature is: Unavailable\n"); else if (!(drive.word086 & 0x0008)) pout("APM feature is: Disabled\n"); else print_apm_level("APM level is: ", drive.words088_255[91-88] & 0xff); } // Print read look-ahead status if (options.get_lookahead) { pout("Rd look-ahead is: %s\n", ( (drive.command_set_2 & 0xc000) != 0x4000 // word083 || !(drive.command_set_1 & 0x0040)) ? "Unavailable" : // word082 !(drive.cfs_enable_1 & 0x0040) ? "Disabled" : "Enabled"); // word085 } // Print write cache status if (options.get_wcache) { pout("Write cache is: %s\n", ( (drive.command_set_2 & 0xc000) != 0x4000 // word083 || !(drive.command_set_1 & 0x0020)) ? "Unavailable" : // word082 !(drive.cfs_enable_1 & 0x0020) ? "Disabled" : "Enabled"); // word085 } // Print ATA security status if (options.get_security) print_ata_security_status("ATA Security is: ", drive.words088_255[128-88]); // Check if SCT commands available bool sct_ok = false; if (need_sct_support) { if (!isSCTCapable(&drive)) { failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else sct_ok = true; } // Print write cache reordering status if (sct_ok && options.sct_wcache_reorder_get) { int wcache_reorder=ataGetSetSCTWriteCacheReordering(device, false /* enable */, false /* persistent */, false /*set*/); pout("Wt Cache Reorder: "); switch(wcache_reorder) { case 0: /* not defined in standard but returned on some drives if not set */ pout("Unknown"); break; case 1: pout("Enabled"); break; case 2: pout("Disabled"); break; default: /* error? */ pout("N/A"); break; } pout("\n"); } if (!sct_ok && options.sct_wcache_reorder_get) { pout("Wt Cache Reorder: Unavailable\n"); } // Print remaining drive info if (options.drive_info) { // Print the (now possibly changed) power mode if available if (powername) pout("Power mode %s %s\n", (powerchg?"was:":"is: "), powername); pout("\n"); } // Exit if SMART is not supported but must be available to proceed if (smart_supported <= 0 && need_smart_support) failuretest(MANDATORY_CMD, returnval|=FAILSMART); // START OF THE ENABLE/DISABLE SECTION OF THE CODE if ( options.smart_disable || options.smart_enable || options.smart_auto_save_disable || options.smart_auto_save_enable || options.smart_auto_offl_disable || options.smart_auto_offl_enable || options.set_aam || options.set_apm || options.set_lookahead || options.set_wcache || options.set_security_freeze || options.set_standby || options.sct_wcache_reorder_set) pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); // Enable/Disable AAM if (options.set_aam) { if (options.set_aam > 0) { if (!ata_set_features(device, ATA_ENABLE_AAM, options.set_aam-1)) { pout("AAM enable failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else print_aam_level("AAM set to level ", options.set_aam-1); } else { if (!ata_set_features(device, ATA_DISABLE_AAM)) { pout("AAM disable failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else pout("AAM disabled\n"); } } // Enable/Disable APM if (options.set_apm) { if (options.set_apm > 0) { if (!ata_set_features(device, ATA_ENABLE_APM, options.set_apm-1)) { pout("APM enable failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else print_apm_level("APM set to level ", options.set_apm-1); } else { if (!ata_set_features(device, ATA_DISABLE_APM)) { pout("APM disable failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else pout("APM disabled\n"); } } // Enable/Disable read look-ahead if (options.set_lookahead) { bool enable = (options.set_lookahead > 0); if (!ata_set_features(device, (enable ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD))) { pout("Read look-ahead %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg()); returnval |= FAILSMART; } else pout("Read look-ahead %sabled\n", (enable ? "en" : "dis")); } // Enable/Disable write cache if (options.set_wcache) { bool enable = (options.set_wcache > 0); if (!ata_set_features(device, (enable ? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE))) { pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg()); returnval |= FAILSMART; } else pout("Write cache %sabled\n", (enable ? "en" : "dis")); } // Enable/Disable write cache reordering if (sct_ok && options.sct_wcache_reorder_set) { bool enable = (options.sct_wcache_reorder_set > 0); int wcache_reorder=ataGetSetSCTWriteCacheReordering(device, enable, false /* persistent */, true /*set*/); if (wcache_reorder < 0) { pout("Write cache reordering %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg()); returnval |= FAILSMART; } else pout("Write cache reordering %sabled\n", (enable ? "en" : "dis")); } // Freeze ATA security if (options.set_security_freeze) { if (!ata_nodata_command(device, ATA_SECURITY_FREEZE_LOCK)) { pout("ATA SECURITY FREEZE LOCK failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else pout("ATA Security set to frozen mode\n"); } // Set standby timer if (options.set_standby) { if (!ata_nodata_command(device, ATA_IDLE, options.set_standby-1)) { pout("ATA IDLE command failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else print_standby_timer("Standby timer set to ", options.set_standby-1, drive); } // Enable/Disable SMART commands if (options.smart_enable) { if (ataEnableSmart(device)) { pout("SMART Enable failed: %s\n\n", device->get_errmsg()); failuretest(MANDATORY_CMD, returnval|=FAILSMART); } else { pout("SMART Enabled.\n"); smart_enabled = 1; } } // Turn off SMART on device if (options.smart_disable) { if (ataDisableSmart(device)) { pout("SMART Disable failed: %s\n\n", device->get_errmsg()); failuretest(MANDATORY_CMD,returnval|=FAILSMART); } } // Exit if SMART is disabled but must be enabled to proceed if (options.smart_disable || (smart_enabled <= 0 && need_smart_enabled && !is_permissive())) { pout("SMART Disabled. Use option -s with argument 'on' to enable it.\n"); if (!options.smart_disable) pout("(override with '-T permissive' option)\n"); return returnval; } // Enable/Disable Auto-save attributes if (options.smart_auto_save_enable) { if (ataEnableAutoSave(device)){ pout("SMART Enable Attribute Autosave failed: %s\n\n", device->get_errmsg()); failuretest(MANDATORY_CMD, returnval|=FAILSMART); } else pout("SMART Attribute Autosave Enabled.\n"); } if (options.smart_auto_save_disable) { if (ataDisableAutoSave(device)){ pout("SMART Disable Attribute Autosave failed: %s\n\n", device->get_errmsg()); failuretest(MANDATORY_CMD, returnval|=FAILSMART); } else pout("SMART Attribute Autosave Disabled.\n"); } // Read SMART values and thresholds if necessary ata_smart_values smartval; memset(&smartval, 0, sizeof(smartval)); ata_smart_thresholds_pvt smartthres; memset(&smartthres, 0, sizeof(smartthres)); bool smart_val_ok = false, smart_thres_ok = false; if (need_smart_val) { if (ataReadSmartValues(device, &smartval)) { pout("Read SMART Data failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { smart_val_ok = true; if (options.smart_check_status || options.smart_vendor_attrib) { if (ataReadSmartThresholds(device, &smartthres)){ pout("Read SMART Thresholds failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else smart_thres_ok = true; } } } // Enable/Disable Off-line testing bool needupdate = false; if (options.smart_auto_offl_enable) { if (!isSupportAutomaticTimer(&smartval)){ pout("SMART Automatic Timers not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } needupdate = smart_val_ok; if (ataEnableAutoOffline(device)){ pout("SMART Enable Automatic Offline failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else pout("SMART Automatic Offline Testing Enabled every four hours.\n"); } if (options.smart_auto_offl_disable) { if (!isSupportAutomaticTimer(&smartval)){ pout("SMART Automatic Timers not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } needupdate = smart_val_ok; if (ataDisableAutoOffline(device)){ pout("SMART Disable Automatic Offline failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else pout("SMART Automatic Offline Testing Disabled.\n"); } if (needupdate && ataReadSmartValues(device, &smartval)){ pout("Read SMART Data failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); smart_val_ok = false; } // all this for a newline! if ( options.smart_disable || options.smart_enable || options.smart_auto_save_disable || options.smart_auto_save_enable || options.smart_auto_offl_disable || options.smart_auto_offl_enable || options.set_aam || options.set_apm || options.set_lookahead || options.set_wcache || options.set_security_freeze || options.set_standby || options.sct_wcache_reorder_set) pout("\n"); // START OF READ-ONLY OPTIONS APART FROM -V and -i if ( options.smart_check_status || options.smart_general_values || options.smart_vendor_attrib || options.smart_error_log || options.smart_selftest_log || options.smart_selective_selftest_log || options.smart_ext_error_log || options.smart_ext_selftest_log || options.sct_temp_sts || options.sct_temp_hist ) pout("=== START OF READ SMART DATA SECTION ===\n"); // Check SMART status if (options.smart_check_status) { switch (ataSmartStatus2(device)) { case 0: // The case where the disk health is OK pout("SMART overall-health self-assessment test result: PASSED\n"); if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 0)) { if (options.smart_vendor_attrib) pout("See vendor-specific Attribute list for marginal Attributes.\n\n"); else { print_on(); pout("Please note the following marginal Attributes:\n"); PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 2, options.output_format); } returnval|=FAILAGE; } else pout("\n"); break; case 1: // The case where the disk health is NOT OK print_on(); pout("SMART overall-health self-assessment test result: FAILED!\n" "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); print_off(); if (smart_thres_ok && find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) { returnval|=FAILATTR; if (options.smart_vendor_attrib) pout("See vendor-specific Attribute list for failed Attributes.\n\n"); else { print_on(); pout("Failed Attributes:\n"); PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 1, options.output_format); } } else pout("No failed Attributes found.\n\n"); returnval|=FAILSTATUS; print_off(); break; case -1: default: // Something went wrong with the SMART STATUS command. // The ATA SMART RETURN STATUS command provides the result in the ATA output // registers. Buggy ATA/SATA drivers and SAT Layers often do not properly // return the registers values. failuretest(OPTIONAL_CMD, returnval|=FAILSMART); if (!(smart_val_ok && smart_thres_ok)) { print_on(); pout("SMART overall-health self-assessment test result: UNKNOWN!\n" "SMART Status, Attributes and Thresholds cannot be read.\n\n"); } else if (find_failed_attr(&smartval, &smartthres, attribute_defs, 1)) { print_on(); pout("SMART overall-health self-assessment test result: FAILED!\n" "Drive failure expected in less than 24 hours. SAVE ALL DATA.\n"); print_off(); returnval|=FAILATTR; returnval|=FAILSTATUS; if (options.smart_vendor_attrib) pout("See vendor-specific Attribute list for failed Attributes.\n\n"); else { print_on(); pout("Failed Attributes:\n"); PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 1, options.output_format); } } else { pout("SMART overall-health self-assessment test result: PASSED\n"); pout("Warning: This result is based on an Attribute check.\n"); if (find_failed_attr(&smartval, &smartthres, attribute_defs, 0)) { if (options.smart_vendor_attrib) pout("See vendor-specific Attribute list for marginal Attributes.\n\n"); else { print_on(); pout("Please note the following marginal Attributes:\n"); PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, 2, options.output_format); } returnval|=FAILAGE; } else pout("\n"); } print_off(); break; } // end of switch statement print_off(); } // end of checking SMART Status // Print general SMART values if (smart_val_ok && options.smart_general_values) PrintGeneralSmartValues(&smartval, &drive, firmwarebugs); // Print vendor-specific attributes if (smart_val_ok && options.smart_vendor_attrib) { print_on(); PrintSmartAttribWithThres(&smartval, &smartthres, attribute_defs, rpm, (printing_is_switchable ? 2 : 0), options.output_format); print_off(); } // If GP Log is supported use smart log directory for // error and selftest log support check. if ( isGeneralPurposeLoggingCapable(&drive) && ( options.smart_error_log || options.smart_selftest_log || options.retry_error_log || options.retry_selftest_log)) need_smart_logdir = true; ata_smart_log_directory smartlogdir_buf, gplogdir_buf; const ata_smart_log_directory * smartlogdir = 0, * gplogdir = 0; // Read SMART Log directory if (need_smart_logdir) { if (firmwarebugs.is_set(BUG_NOLOGDIR)) smartlogdir = fake_logdir(&smartlogdir_buf, options); else if (ataReadLogDirectory(device, &smartlogdir_buf, false)) { pout("Read SMART Log Directory failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else smartlogdir = &smartlogdir_buf; } // Read GP Log directory if (need_gp_logdir) { if (firmwarebugs.is_set(BUG_NOLOGDIR)) gplogdir = fake_logdir(&gplogdir_buf, options); else if (ataReadLogDirectory(device, &gplogdir_buf, true)) { pout("Read GP Log Directory failed\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else gplogdir = &gplogdir_buf; } // Print log directories if ((options.gp_logdir && gplogdir) || (options.smart_logdir && smartlogdir)) { if (firmwarebugs.is_set(BUG_NOLOGDIR)) pout("Log Directories not read due to '-F nologdir' option\n\n"); else PrintLogDirectories(gplogdir, smartlogdir); } // Print log pages for (i = 0; i < options.log_requests.size(); i++) { const ata_log_request & req = options.log_requests[i]; const char * type; unsigned max_nsectors; if (req.gpl) { type = "General Purpose"; max_nsectors = GetNumLogSectors(gplogdir, req.logaddr, true); } else { type = "SMART"; max_nsectors = GetNumLogSectors(smartlogdir, req.logaddr, false); } if (!max_nsectors) { if (!is_permissive()) { pout("%s Log 0x%02x does not exist (override with '-T permissive' option)\n", type, req.logaddr); continue; } max_nsectors = req.page+1; } if (max_nsectors <= req.page) { pout("%s Log 0x%02x has only %u sectors, output skipped\n", type, req.logaddr, max_nsectors); continue; } unsigned ns = req.nsectors; if (ns > max_nsectors - req.page) { if (req.nsectors != ~0U) // "FIRST-max" pout("%s Log 0x%02x has only %u sectors, output truncated\n", type, req.logaddr, max_nsectors); ns = max_nsectors - req.page; } // SMART log don't support sector offset, start with first sector unsigned offs = (req.gpl ? 0 : req.page); raw_buffer log_buf((offs + ns) * 512); bool ok; if (req.gpl) ok = ataReadLogExt(device, req.logaddr, 0x00, req.page, log_buf.data(), ns); else ok = ataReadSmartLog(device, req.logaddr, log_buf.data(), offs + ns); if (!ok) failuretest(OPTIONAL_CMD, returnval|=FAILSMART); else PrintLogPages(type, log_buf.data() + offs*512, req.logaddr, req.page, ns, max_nsectors); } // Print SMART Extendend Comprehensive Error Log bool do_smart_error_log = options.smart_error_log; if (options.smart_ext_error_log) { bool ok = false; unsigned nsectors = GetNumLogSectors(gplogdir, 0x03, true); if (!nsectors) pout("SMART Extended Comprehensive Error Log (GP Log 0x03) not supported\n\n"); else if (nsectors >= 256) pout("SMART Extended Comprehensive Error Log size %u not supported\n\n", nsectors); else { raw_buffer log_03_buf(nsectors * 512); ata_smart_exterrlog * log_03 = (ata_smart_exterrlog *)log_03_buf.data(); if (!ataReadExtErrorLog(device, log_03, nsectors, firmwarebugs)) { pout("Read SMART Extended Comprehensive Error Log failed\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { if (PrintSmartExtErrorLog(log_03, nsectors, options.smart_ext_error_log)) returnval |= FAILERR; ok = true; } } if (!ok) { if (options.retry_error_log) do_smart_error_log = true; else if (!do_smart_error_log) pout("Try '-l [xerror,]error' to read traditional SMART Error Log\n"); } } // Print SMART error log if (do_smart_error_log) { if (!( ( smartlogdir && GetNumLogSectors(smartlogdir, 0x01, false)) || (!smartlogdir && isSmartErrorLogCapable(&smartval, &drive) ) || is_permissive() )) { pout("SMART Error Log not supported\n\n"); } else { ata_smart_errorlog smarterror; memset(&smarterror, 0, sizeof(smarterror)); if (ataReadErrorLog(device, &smarterror, firmwarebugs)) { pout("Read SMART Error Log failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { // quiet mode is turned on inside PrintSmartErrorLog() if (PrintSmartErrorlog(&smarterror, firmwarebugs)) returnval|=FAILERR; print_off(); } } } // Print SMART Extendend Self-test Log bool do_smart_selftest_log = options.smart_selftest_log; if (options.smart_ext_selftest_log) { bool ok = false; unsigned nsectors = GetNumLogSectors(gplogdir, 0x07, true); if (!nsectors) pout("SMART Extended Self-test Log (GP Log 0x07) not supported\n\n"); else if (nsectors >= 256) pout("SMART Extended Self-test Log size %u not supported\n\n", nsectors); else { raw_buffer log_07_buf(nsectors * 512); ata_smart_extselftestlog * log_07 = (ata_smart_extselftestlog *)log_07_buf.data(); if (!ataReadExtSelfTestLog(device, log_07, nsectors)) { pout("Read SMART Extended Self-test Log failed\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { if (PrintSmartExtSelfTestLog(log_07, nsectors, options.smart_ext_selftest_log)) returnval |= FAILLOG; ok = true; } } if (!ok) { if (options.retry_selftest_log) do_smart_selftest_log = true; else if (!do_smart_selftest_log) pout("Try '-l [xselftest,]selftest' to read traditional SMART Self Test Log\n"); } } // Print SMART self-test log if (do_smart_selftest_log) { if (!( ( smartlogdir && GetNumLogSectors(smartlogdir, 0x06, false)) || (!smartlogdir && isSmartTestLogCapable(&smartval, &drive) ) || is_permissive() )) { pout("SMART Self-test Log not supported\n\n"); } else { ata_smart_selftestlog smartselftest; memset(&smartselftest, 0, sizeof(smartselftest)); if (ataReadSelfTestLog(device, &smartselftest, firmwarebugs)) { pout("Read SMART Self-test Log failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { print_on(); if (ataPrintSmartSelfTestlog(&smartselftest, !printing_is_switchable, firmwarebugs)) returnval |= FAILLOG; print_off(); pout("\n"); } } } // Print SMART selective self-test log if (options.smart_selective_selftest_log) { ata_selective_self_test_log log; if (!isSupportSelectiveSelfTest(&smartval)) pout("Selective Self-tests/Logging not supported\n\n"); else if(ataReadSelectiveSelfTestLog(device, &log)) { pout("Read SMART Selective Self-test Log failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { print_on(); // If any errors were found, they are logged in the SMART Self-test log. // So there is no need to print the Selective Self Test log in silent // mode. if (!printing_is_switchable) ataPrintSelectiveSelfTestLog(&log, &smartval); print_off(); pout("\n"); } } if(!sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int || options.sct_erc_get || options.sct_erc_set )) pout("SCT Commands not supported\n\n"); // Print SCT status and temperature history table if (sct_ok && (options.sct_temp_sts || options.sct_temp_hist || options.sct_temp_int)) { for (;;) { if (options.sct_temp_sts || options.sct_temp_hist) { ata_sct_status_response sts; ata_sct_temperature_history_table tmh; if (!options.sct_temp_hist) { // Read SCT status only if (ataReadSCTStatus(device, &sts)) { failuretest(OPTIONAL_CMD, returnval|=FAILSMART); break; } } else { if (!isSCTDataTableCapable(&drive)) { pout("SCT Data Table command not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); break; } // Read SCT status and temperature history if (ataReadSCTTempHist(device, &tmh, &sts)) { pout("Read SCT Temperature History failed\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); break; } } if (options.sct_temp_sts) ataPrintSCTStatus(&sts); if (options.sct_temp_hist) ataPrintSCTTempHist(&tmh); pout("\n"); } if (options.sct_temp_int) { // Set new temperature logging interval if (!isSCTFeatureControlCapable(&drive)) { pout("SCT Feature Control command not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); break; } if (ataSetSCTTempInterval(device, options.sct_temp_int, options.sct_temp_int_pers)) { pout("Write Temperature Logging Interval failed\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); break; } pout("Temperature Logging Interval set to %u minute%s (%s)\n", options.sct_temp_int, (options.sct_temp_int == 1 ? "" : "s"), (options.sct_temp_int_pers ? "persistent" : "volatile")); } break; } } // SCT Error Recovery Control if (sct_ok && (options.sct_erc_get || options.sct_erc_set)) { if (!isSCTErrorRecoveryControlCapable(&drive)) { pout("SCT Error Recovery Control command not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else { bool sct_erc_get = options.sct_erc_get; if (options.sct_erc_set) { // Set SCT Error Recovery Control if ( ataSetSCTErrorRecoveryControltime(device, 1, options.sct_erc_readtime ) || ataSetSCTErrorRecoveryControltime(device, 2, options.sct_erc_writetime)) { pout("SCT (Set) Error Recovery Control command failed\n"); if (!( (options.sct_erc_readtime == 70 && options.sct_erc_writetime == 70) || (options.sct_erc_readtime == 0 && options.sct_erc_writetime == 0))) pout("Retry with: 'scterc,70,70' to enable ERC or 'scterc,0,0' to disable\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); sct_erc_get = false; } else if (!sct_erc_get) ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime, options.sct_erc_writetime); } if (sct_erc_get) { // Print SCT Error Recovery Control unsigned short read_timer, write_timer; if ( ataGetSCTErrorRecoveryControltime(device, 1, read_timer ) || ataGetSCTErrorRecoveryControltime(device, 2, write_timer)) { pout("SCT (Get) Error Recovery Control command failed\n"); if (options.sct_erc_set) { pout("The previous SCT (Set) Error Recovery Control command succeeded\n"); ataPrintSCTErrorRecoveryControl(true, options.sct_erc_readtime, options.sct_erc_writetime); } failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else ataPrintSCTErrorRecoveryControl(false, read_timer, write_timer); } pout("\n"); } } // Print Device Statistics if (options.devstat_all_pages || options.devstat_ssd_page || !options.devstat_pages.empty()) { unsigned nsectors = GetNumLogSectors(gplogdir, 0x04, true); if (!nsectors) pout("Device Statistics (GP Log 0x04) not supported\n\n"); else if (!print_device_statistics(device, nsectors, options.devstat_pages, options.devstat_all_pages, options.devstat_ssd_page)) failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } // Print SATA Phy Event Counters if (options.sataphy) { unsigned nsectors = GetNumLogSectors(gplogdir, 0x11, true); // Packet interface devices do not provide a log directory, check support bit if (!nsectors && (drive.words047_079[76-47] & 0x0401) == 0x0400) nsectors = 1; if (!nsectors) pout("SATA Phy Event Counters (GP Log 0x11) not supported\n\n"); else if (nsectors != 1) pout("SATA Phy Event Counters with %u sectors not supported\n\n", nsectors); else { unsigned char log_11[512] = {0, }; unsigned char features = (options.sataphy_reset ? 0x01 : 0x00); if (!ataReadLogExt(device, 0x11, features, 0, log_11, 1)) { pout("Read SATA Phy Event Counters failed\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } else PrintSataPhyEventCounters(log_11, options.sataphy_reset); } } // Set to standby (spindown) mode // (Above commands may spinup drive) if (options.set_standby_now) { if (!ata_nodata_command(device, ATA_STANDBY_IMMEDIATE)) { pout("ATA STANDBY IMMEDIATE command failed: %s\n", device->get_errmsg()); returnval |= FAILSMART; } else pout("Device placed in STANDBY mode\n"); } // START OF THE TESTING SECTION OF THE CODE. IF NO TESTING, RETURN if (!smart_val_ok || options.smart_selftest_type == -1) return returnval; pout("=== START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===\n"); // if doing a self-test, be sure it's supported by the hardware switch (options.smart_selftest_type) { case OFFLINE_FULL_SCAN: if (!isSupportExecuteOfflineImmediate(&smartval)){ pout("Execute Offline Immediate function not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } break; case ABORT_SELF_TEST: case SHORT_SELF_TEST: case EXTEND_SELF_TEST: case SHORT_CAPTIVE_SELF_TEST: case EXTEND_CAPTIVE_SELF_TEST: if (!isSupportSelfTest(&smartval)){ pout("Self-test functions not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } break; case CONVEYANCE_SELF_TEST: case CONVEYANCE_CAPTIVE_SELF_TEST: if (!isSupportConveyanceSelfTest(&smartval)){ pout("Conveyance Self-test functions not supported\n\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } break; case SELECTIVE_SELF_TEST: case SELECTIVE_CAPTIVE_SELF_TEST: if (!isSupportSelectiveSelfTest(&smartval)){ pout("Selective Self-test functions not supported\n\n"); failuretest(MANDATORY_CMD, returnval|=FAILSMART); } break; default: break; // Vendor specific type } // Now do the test. Note ataSmartTest prints its own error/success // messages if (ataSmartTest(device, options.smart_selftest_type, options.smart_selftest_force, options.smart_selective_args, &smartval, sizes.sectors )) failuretest(OPTIONAL_CMD, returnval|=FAILSMART); else { // Tell user how long test will take to complete. This is tricky // because in the case of an Offline Full Scan, the completion // timer is volatile, and needs to be read AFTER the command is // given. If this will interrupt the Offline Full Scan, we don't // do it, just warn user. if (options.smart_selftest_type == OFFLINE_FULL_SCAN) { if (isSupportOfflineAbort(&smartval)) pout("Note: giving further SMART commands will abort Offline testing\n"); else if (ataReadSmartValues(device, &smartval)){ pout("Read SMART Data failed: %s\n\n", device->get_errmsg()); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } } // Now say how long the test will take to complete int timewait = TestTime(&smartval, options.smart_selftest_type); if (timewait) { time_t t=time(NULL); if (options.smart_selftest_type == OFFLINE_FULL_SCAN) { t+=timewait; pout("Please wait %d seconds for test to complete.\n", (int)timewait); } else { t+=timewait*60; pout("Please wait %d minutes for test to complete.\n", (int)timewait); } pout("Test will complete after %s\n", ctime(&t)); if ( options.smart_selftest_type != SHORT_CAPTIVE_SELF_TEST && options.smart_selftest_type != EXTEND_CAPTIVE_SELF_TEST && options.smart_selftest_type != CONVEYANCE_CAPTIVE_SELF_TEST && options.smart_selftest_type != SELECTIVE_CAPTIVE_SELF_TEST ) pout("Use smartctl -X to abort test.\n"); } } return returnval; } smartmontools-6.2+svn3841.orig/os_netbsd.cpp0000644000000000000000000003020412125373277017555 0ustar rootroot/* * os_netbsd.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 Sergey Svishchev * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "config.h" #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "utility.h" #include "os_netbsd.h" #include #include const char * os_netbsd_cpp_cvsid = "$Id: os_netbsd.cpp 3806 2013-03-29 20:17:03Z chrfranke $" OS_NETBSD_H_CVSID; /* global variable holding byte count of allocated memory */ extern long long bytes; enum warnings { BAD_SMART, NO_3WARE, NO_ARECA, MAX_MSG }; /* Utility function for printing warnings */ void printwarning(int msgNo, const char *extra) { static int printed[] = {0, 0}; static const char *message[] = { "Error: SMART Status command failed.\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n", PACKAGE_STRING " does not currently support twe(4) and twa(4) devices (3ware Escalade, Apache)\n", }; if (msgNo >= 0 && msgNo <= MAX_MSG) { if (!printed[msgNo]) { printed[msgNo] = 1; pout("%s", message[msgNo]); if (extra) pout("%s", extra); } } return; } static const char *net_dev_prefix = "/dev/"; static const char *net_dev_ata_disk = "wd"; static const char *net_dev_scsi_disk = "sd"; static const char *net_dev_scsi_tape = "enrst"; /* Guess device type (ATA or SCSI) based on device name */ int guess_device_type(const char *dev_name) { int len; int dev_prefix_len = strlen(net_dev_prefix); if (!dev_name || !(len = strlen(dev_name))) return CONTROLLER_UNKNOWN; if (!strncmp(net_dev_prefix, dev_name, dev_prefix_len)) { if (len <= dev_prefix_len) return CONTROLLER_UNKNOWN; else dev_name += dev_prefix_len; } if (!strncmp(net_dev_ata_disk, dev_name, strlen(net_dev_ata_disk))) return CONTROLLER_ATA; if (!strncmp(net_dev_scsi_disk, dev_name, strlen(net_dev_scsi_disk))) return CONTROLLER_SCSI; if (!strncmp(net_dev_scsi_tape, dev_name, strlen(net_dev_scsi_tape))) return CONTROLLER_SCSI; return CONTROLLER_UNKNOWN; } int get_dev_names(char ***names, const char *prefix) { char *disknames, *p, **mp; int n = 0; int sysctl_mib[2]; size_t sysctl_len; *names = NULL; sysctl_mib[0] = CTL_HW; sysctl_mib[1] = HW_DISKNAMES; if (-1 == sysctl(sysctl_mib, 2, NULL, &sysctl_len, NULL, 0)) { pout("Failed to get value of sysctl `hw.disknames'\n"); return -1; } if (!(disknames = (char *)malloc(sysctl_len))) { pout("Out of memory constructing scan device list\n"); return -1; } if (-1 == sysctl(sysctl_mib, 2, disknames, &sysctl_len, NULL, 0)) { pout("Failed to get value of sysctl `hw.disknames'\n"); return -1; } if (!(mp = (char **) calloc(strlen(disknames) / 2, sizeof(char *)))) { pout("Out of memory constructing scan device list\n"); return -1; } for (p = strtok(disknames, " "); p; p = strtok(NULL, " ")) { if (strncmp(p, prefix, strlen(prefix))) { continue; } mp[n] = (char *)malloc(strlen(net_dev_prefix) + strlen(p) + 2); if (!mp[n]) { pout("Out of memory constructing scan device list\n"); return -1; } sprintf(mp[n], "%s%s%c", net_dev_prefix, p, 'a' + getrawpartition()); bytes += strlen(mp[n]) + 1; n++; } mp = (char **)realloc(mp, n * (sizeof(char *))); bytes += (n) * (sizeof(char *)); *names = mp; return n; } int make_device_names(char ***devlist, const char *name) { if (!strcmp(name, "SCSI")) return get_dev_names(devlist, net_dev_scsi_disk); else if (!strcmp(name, "ATA")) return get_dev_names(devlist, net_dev_ata_disk); else return 0; } int deviceopen(const char *pathname, char *type) { if (!strcmp(type, "SCSI")) { int fd = open(pathname, O_RDWR | O_NONBLOCK); if (fd < 0 && errno == EROFS) fd = open(pathname, O_RDONLY | O_NONBLOCK); return fd; } else if (!strcmp(type, "ATA")) return open(pathname, O_RDWR | O_NONBLOCK); else return -1; } int deviceclose(int fd) { return close(fd); } int ata_command_interface(int fd, smart_command_set command, int select, char *data) { struct atareq req; unsigned char inbuf[DEV_BSIZE]; int retval, copydata = 0; memset(&req, 0, sizeof(req)); req.timeout = 1000; memset(&inbuf, 0, sizeof(inbuf)); switch (command) { case READ_VALUES: req.flags = ATACMD_READ; req.features = WDSM_RD_DATA; req.command = WDCC_SMART; req.databuf = (char *)inbuf; req.datalen = sizeof(inbuf); req.cylinder = WDSMART_CYL; copydata = 1; break; case READ_THRESHOLDS: req.flags = ATACMD_READ; req.features = WDSM_RD_THRESHOLDS; req.command = WDCC_SMART; req.databuf = (char *)inbuf; req.datalen = sizeof(inbuf); req.cylinder = WDSMART_CYL; copydata = 1; break; case READ_LOG: req.flags = ATACMD_READ; req.features = ATA_SMART_READ_LOG_SECTOR; /* XXX missing from wdcreg.h */ req.command = WDCC_SMART; req.databuf = (char *)inbuf; req.datalen = sizeof(inbuf); req.cylinder = WDSMART_CYL; req.sec_num = select; req.sec_count = 1; copydata = 1; break; case WRITE_LOG: memcpy(inbuf, data, 512); req.flags = ATACMD_WRITE; req.features = ATA_SMART_WRITE_LOG_SECTOR; /* XXX missing from wdcreg.h */ req.command = WDCC_SMART; req.databuf = (char *)inbuf; req.datalen = sizeof(inbuf); req.cylinder = WDSMART_CYL; req.sec_num = select; req.sec_count = 1; break; case IDENTIFY: req.flags = ATACMD_READ; req.command = WDCC_IDENTIFY; req.databuf = (char *)inbuf; req.datalen = sizeof(inbuf); copydata = 1; break; case PIDENTIFY: req.flags = ATACMD_READ; req.command = ATAPI_IDENTIFY_DEVICE; req.databuf = (char *)inbuf; req.datalen = sizeof(inbuf); copydata = 1; break; case ENABLE: req.flags = ATACMD_READREG; req.features = WDSM_ENABLE_OPS; req.command = WDCC_SMART; req.cylinder = WDSMART_CYL; break; case DISABLE: req.flags = ATACMD_READREG; req.features = WDSM_DISABLE_OPS; req.command = WDCC_SMART; req.cylinder = WDSMART_CYL; break; case AUTO_OFFLINE: /* NOTE: According to ATAPI 4 and UP, this command is obsolete */ req.flags = ATACMD_READREG; req.features = ATA_SMART_AUTO_OFFLINE; /* XXX missing from wdcreg.h */ req.command = WDCC_SMART; req.cylinder = WDSMART_CYL; req.sec_count = select; break; case AUTOSAVE: req.flags = ATACMD_READREG; req.features = ATA_SMART_AUTOSAVE; /* XXX missing from wdcreg.h */ req.command = WDCC_SMART; req.cylinder = WDSMART_CYL; req.sec_count = select; break; case IMMEDIATE_OFFLINE: /* NOTE: According to ATAPI 4 and UP, this command is obsolete */ req.flags = ATACMD_READREG; req.features = ATA_SMART_IMMEDIATE_OFFLINE; /* XXX missing from wdcreg.h */ req.command = WDCC_SMART; req.cylinder = WDSMART_CYL; req.sec_num = select; req.sec_count = 1; break; case STATUS: /* should return 0 if SMART is enabled at all */ case STATUS_CHECK: /* should return 0 if disk's health is ok */ req.flags = ATACMD_READREG; req.features = WDSM_STATUS; req.command = WDCC_SMART; req.cylinder = WDSMART_CYL; break; case CHECK_POWER_MODE: req.flags = ATACMD_READREG; req.command = WDCC_CHECK_PWR; break; default: pout("Unrecognized command %d in ata_command_interface()\n", command); errno = ENOSYS; return -1; } if (command == STATUS_CHECK || command == AUTOSAVE || command == AUTO_OFFLINE) { char buf[512]; unsigned const short normal = WDSMART_CYL, failed = 0x2cf4; if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) { perror("Failed command"); return -1; } if (req.retsts != ATACMD_OK) { return -1; } /* Cyl low and Cyl high unchanged means "Good SMART status" */ if (req.cylinder == normal) return 0; /* These values mean "Bad SMART status" */ if (req.cylinder == failed) return 1; /* We haven't gotten output that makes sense; * print out some debugging info */ snprintf(buf, sizeof(buf), "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", (int) req.command, (int) req.features, (int) req.sec_count, (int) req.sec_num, (int) (le16toh(req.cylinder) & 0xff), (int) ((le16toh(req.cylinder) >> 8) & 0xff), (int) req.error); printwarning(BAD_SMART, buf); return 0; } if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) { perror("Failed command"); return -1; } if (req.retsts != ATACMD_OK) { return -1; } if (command == CHECK_POWER_MODE) data[0] = req.sec_count; if (copydata) memcpy(data, inbuf, 512); return 0; } int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) { struct scsireq sc; if (report > 0) { size_t k; const unsigned char *ucp = iop->cmnd; const char *np; np = scsi_get_opcode_name(ucp[0]); pout(" [%s: ", np ? np : ""); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout("]\n Outgoing data, len=%d%s:\n", (int) iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len), 1); } else pout("]"); } memset(&sc, 0, sizeof(sc)); memcpy(sc.cmd, iop->cmnd, iop->cmnd_len); sc.cmdlen = iop->cmnd_len; sc.databuf = (char *)iop->dxferp; sc.datalen = iop->dxfer_len; sc.senselen = iop->max_sense_len; sc.timeout = iop->timeout == 0 ? 60000 : (1000 * iop->timeout); sc.flags = (iop->dxfer_dir == DXFER_NONE ? SCCMD_READ : (iop->dxfer_dir == DXFER_FROM_DEVICE ? SCCMD_READ : SCCMD_WRITE)); if (ioctl(fd, SCIOCCOMMAND, &sc) < 0) { warn("error sending SCSI ccb"); return -1; } iop->resid = sc.datalen - sc.datalen_used; iop->scsi_status = sc.status; if (iop->sensep) { memcpy(iop->sensep, sc.sense, sc.senselen_used); iop->resp_sense_len = sc.senselen_used; } if (report > 0) { int trunc; pout(" status=0\n"); trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int) iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len), 1); } switch (sc.retsts) { case SCCMD_OK: return 0; case SCCMD_TIMEOUT: return -ETIMEDOUT; case SCCMD_BUSY: return -EBUSY; default: return -EIO; } } /* print examples for smartctl */ void print_smartctl_examples() { char p; p = 'a' + getrawpartition(); printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); #ifdef HAVE_GETOPT_LONG printf( " smartctl -a /dev/wd0%c (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/wd0%c\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/wd0%c\n" " (Prints Self-Test & Attribute errors)\n", p, p, p, p ); #else printf( " smartctl -a /dev/wd0%c (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/wd0%c (Enables SMART on first disk)\n" " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/wd0%c" " (Prints Self-Test & Attribute errors)\n", p, p, p, p ); #endif return; } smartmontools-6.2+svn3841.orig/os_openbsd.h0000644000000000000000000000340012062413436017363 0ustar rootroot/* * os_openbsd.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 David Snyder * * Derived from os_netbsd.c by Sergey Svishchev , Copyright (C) 2003-8 * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef OS_OPENBSD_H_ #define OS_OPENBSD_H_ #define OS_OPENBSD_H_CVSID "$Id: os_openbsd.h 3728 2012-12-13 17:57:50Z chrfranke $\n" /* from NetBSD: atareg.h,v 1.17, by Manuel Bouyer */ /* Actually fits _perfectly_ into OBSDs wdcreg.h, but... */ /* Subcommands for SMART (features register) */ #define WDSMART_CYL 0xc24f #include #include #include #include #include #define ata_smart_selftestlog __openbsd_ata_smart_selftestlog #include #if HAVE_DEV_ATA_ATAVAR_H #include #endif #include #undef ata_smart_selftestlog #include #include #include #include #endif /* OS_OPENBSD_H_ */ smartmontools-6.2+svn3841.orig/os_openbsd.cpp0000644000000000000000000003074512062407372017734 0ustar rootroot/* * os_openbsd.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-10 David Snyder * * Derived from os_netbsd.cpp by Sergey Svishchev , Copyright (C) 2003-8 * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "config.h" #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "utility.h" #include "os_openbsd.h" #include const char * os_openbsd_cpp_cvsid = "$Id: os_openbsd.cpp 3727 2012-12-13 17:23:06Z samm2 $" OS_OPENBSD_H_CVSID; /* global variable holding byte count of allocated memory */ extern long long bytes; enum warnings { BAD_SMART, NO_3WARE, NO_ARECA, MAX_MSG }; /* Utility function for printing warnings */ void printwarning(int msgNo, const char *extra) { static int printed[] = {0, 0}; static const char *message[] = { "Error: SMART Status command failed.\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n", PACKAGE_STRING " does not currentlly support twe(4) devices (3ware Escalade)\n", }; if (msgNo >= 0 && msgNo <= MAX_MSG) { if (!printed[msgNo]) { printed[msgNo] = 1; pout("%s", message[msgNo]); if (extra) pout("%s", extra); } } return; } static const char *net_dev_prefix = "/dev/"; static const char *net_dev_ata_disk = "wd"; static const char *net_dev_scsi_disk = "sd"; static const char *net_dev_scsi_tape = "st"; /* Guess device type(ata or scsi) based on device name */ int guess_device_type(const char *dev_name) { int len; int dev_prefix_len = strlen(net_dev_prefix); if (!dev_name || !(len = strlen(dev_name))) return CONTROLLER_UNKNOWN; if (!strncmp(net_dev_prefix, dev_name, dev_prefix_len)) { if (len <= dev_prefix_len) return CONTROLLER_UNKNOWN; else dev_name += dev_prefix_len; } if (!strncmp(net_dev_ata_disk, dev_name, strlen(net_dev_ata_disk))) return CONTROLLER_ATA; if (!strncmp(net_dev_scsi_disk, dev_name, strlen(net_dev_scsi_disk))) return CONTROLLER_SCSI; if (!strncmp(net_dev_scsi_tape, dev_name, strlen(net_dev_scsi_tape))) return CONTROLLER_SCSI; return CONTROLLER_UNKNOWN; } int get_dev_names(char ***names, const char *prefix) { char *disknames, *p, **mp; int n = 0; int sysctl_mib[2]; size_t sysctl_len; *names = NULL; sysctl_mib[0] = CTL_HW; sysctl_mib[1] = HW_DISKNAMES; if (-1 == sysctl(sysctl_mib, 2, NULL, &sysctl_len, NULL, 0)) { pout("Failed to get value of sysctl `hw.disknames'\n"); return -1; } if (!(disknames = (char *)malloc(sysctl_len))) { pout("Out of memory constructing scan device list\n"); return -1; } if (-1 == sysctl(sysctl_mib, 2, disknames, &sysctl_len, NULL, 0)) { pout("Failed to get value of sysctl `hw.disknames'\n"); return -1; } if (!(mp = (char **) calloc(strlen(disknames) / 2, sizeof(char *)))) { pout("Out of memory constructing scan device list\n"); return -1; } for (p = strtok(disknames, ","); p; p = strtok(NULL, ",")) { if (strncmp(p, prefix, strlen(prefix))) { continue; } char * u = strchr(p, ':'); if (u) *u = 0; mp[n] = (char *)malloc(strlen(net_dev_prefix) + strlen(p) + 2); if (!mp[n]) { pout("Out of memory constructing scan device list\n"); return -1; } sprintf(mp[n], "%s%s%c", net_dev_prefix, p, 'a' + getrawpartition()); bytes += strlen(mp[n]) + 1; n++; } mp = (char **)realloc(mp, n * (sizeof(char *))); bytes += (n) * (sizeof(char *)); *names = mp; return n; } int make_device_names(char ***devlist, const char *name) { if (!strcmp(name, "SCSI")) return get_dev_names(devlist, net_dev_scsi_disk); else if (!strcmp(name, "ATA")) return get_dev_names(devlist, net_dev_ata_disk); else return 0; } int deviceopen(const char *pathname, char *type) { if (!strcmp(type, "SCSI")) { int fd = open(pathname, O_RDWR | O_NONBLOCK); if (fd < 0 && errno == EROFS) fd = open(pathname, O_RDONLY | O_NONBLOCK); return fd; } else if (!strcmp(type, "ATA")) return open(pathname, O_RDWR | O_NONBLOCK); else return -1; } int deviceclose(int fd) { return close(fd); } int ata_command_interface(int fd, smart_command_set command, int select, char *data) { struct atareq req; unsigned char inbuf[DEV_BSIZE]; int retval, copydata = 0; memset(&req, 0, sizeof(req)); memset(&inbuf, 0, sizeof(inbuf)); switch (command) { case READ_VALUES: req.flags = ATACMD_READ; req.features = ATA_SMART_READ_VALUES; req.command = ATAPI_SMART; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.cylinder = htole16(WDSMART_CYL); req.timeout = 1000; copydata = 1; break; case READ_THRESHOLDS: req.flags = ATACMD_READ; req.features = ATA_SMART_READ_THRESHOLDS; req.command = ATAPI_SMART; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.cylinder = htole16(WDSMART_CYL); req.timeout = 1000; copydata = 1; break; case READ_LOG: req.flags = ATACMD_READ; req.features = ATA_SMART_READ_LOG_SECTOR; /* XXX missing from wdcreg.h */ req.command = ATAPI_SMART; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.cylinder = htole16(WDSMART_CYL); req.sec_num = select; req.sec_count = 1; req.timeout = 1000; copydata = 1; break; case WRITE_LOG: memcpy(inbuf, data, 512); req.flags = ATACMD_WRITE; req.features = ATA_SMART_WRITE_LOG_SECTOR; /* XXX missing from wdcreg.h */ req.command = ATAPI_SMART; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.cylinder = htole16(WDSMART_CYL); req.sec_num = select; req.sec_count = 1; req.timeout = 1000; break; case IDENTIFY: req.flags = ATACMD_READ; req.command = WDCC_IDENTIFY; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.timeout = 1000; copydata = 1; break; case PIDENTIFY: req.flags = ATACMD_READ; req.command = ATAPI_IDENTIFY_DEVICE; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.timeout = 1000; copydata = 1; break; case ENABLE: req.flags = ATACMD_READ; req.features = ATA_SMART_ENABLE; req.command = ATAPI_SMART; req.cylinder = htole16(WDSMART_CYL); req.timeout = 1000; break; case DISABLE: req.flags = ATACMD_READ; req.features = ATA_SMART_DISABLE; req.command = ATAPI_SMART; req.cylinder = htole16(WDSMART_CYL); req.timeout = 1000; break; case AUTO_OFFLINE: /* NOTE: According to ATAPI 4 and UP, this command is obsolete */ req.flags = ATACMD_READ; req.features = ATA_SMART_AUTO_OFFLINE; /* XXX missing from wdcreg.h */ req.command = ATAPI_SMART; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.cylinder = htole16(WDSMART_CYL); req.sec_num = select; req.sec_count = 1; req.timeout = 1000; break; case AUTOSAVE: req.flags = ATACMD_READ; req.features = ATA_SMART_AUTOSAVE; /* XXX missing from wdcreg.h */ req.command = ATAPI_SMART; req.cylinder = htole16(WDSMART_CYL); req.sec_count = 0xf1; /* to enable autosave */ req.timeout = 1000; break; case IMMEDIATE_OFFLINE: /* NOTE: According to ATAPI 4 and UP, this command is obsolete */ req.flags = ATACMD_READ; req.features = ATA_SMART_IMMEDIATE_OFFLINE; /* XXX missing from wdcreg.h */ req.command = ATAPI_SMART; req.databuf = (caddr_t) inbuf; req.datalen = sizeof(inbuf); req.cylinder = htole16(WDSMART_CYL); req.sec_num = select; req.sec_count = 1; req.timeout = 1000; break; case STATUS_CHECK: /* same command, no HDIO in NetBSD */ case STATUS: req.flags = ATACMD_READ; req.features = ATA_SMART_STATUS; req.command = ATAPI_SMART; req.cylinder = htole16(WDSMART_CYL); req.timeout = 1000; break; case CHECK_POWER_MODE: req.flags = ATACMD_READREG; req.command = WDCC_CHECK_PWR; req.timeout = 1000; break; default: pout("Unrecognized command %d in ata_command_interface()\n", command); errno = ENOSYS; return -1; } if (command == STATUS_CHECK) { char buf[512]; unsigned const short normal = WDSMART_CYL, failed = 0x2cf4; if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) { perror("Failed command"); return -1; } /* Cyl low and Cyl high unchanged means "Good SMART status" */ if (letoh16(req.cylinder) == normal) return 0; /* These values mean "Bad SMART status" */ if (letoh16(req.cylinder) == failed) return 1; /* We haven't gotten output that makes sense; * print out some debugging info */ snprintf(buf, sizeof(buf), "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", (int) req.command, (int) req.features, (int) req.sec_count, (int) req.sec_num, (int) (letoh16(req.cylinder) & 0xff), (int) ((letoh16(req.cylinder) >> 8) & 0xff), (int) req.error); printwarning(BAD_SMART, buf); return 0; } if ((retval = ioctl(fd, ATAIOCCOMMAND, &req))) { perror("Failed command"); return -1; } if (command == CHECK_POWER_MODE) data[0] = req.sec_count; if (copydata) memcpy(data, inbuf, 512); return 0; } int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) { struct scsireq sc; if (report > 0) { size_t k; const unsigned char *ucp = iop->cmnd; const char *np; np = scsi_get_opcode_name(ucp[0]); pout(" [%s: ", np ? np : ""); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout("]\n Outgoing data, len=%d%s:\n", (int) iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len), 1); } else pout("]"); } memset(&sc, 0, sizeof(sc)); memcpy(sc.cmd, iop->cmnd, iop->cmnd_len); sc.cmdlen = iop->cmnd_len; sc.databuf = (char *)iop->dxferp; sc.datalen = iop->dxfer_len; sc.senselen = iop->max_sense_len; sc.timeout = iop->timeout == 0 ? 60000 : iop->timeout; /* XXX */ sc.flags = (iop->dxfer_dir == DXFER_NONE ? SCCMD_READ : (iop->dxfer_dir == DXFER_FROM_DEVICE ? SCCMD_READ : SCCMD_WRITE)); if (ioctl(fd, SCIOCCOMMAND, &sc) < 0) { warn("error sending SCSI ccb"); return -1; } iop->resid = sc.datalen - sc.datalen_used; iop->scsi_status = sc.status; if (iop->sensep) { memcpy(iop->sensep, sc.sense, sc.senselen_used); iop->resp_sense_len = sc.senselen_used; } if (report > 0) { int trunc; pout(" status=0\n"); trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int) iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len), 1); } return 0; } /* print examples for smartctl */ void print_smartctl_examples() { char p; p = 'a' + getrawpartition(); printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); #ifdef HAVE_GETOPT_LONG printf( " smartctl -a /dev/wd0%c (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/wd0%c\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/wd0%c\n" " (Prints Self-Test & Attribute errors)\n", p, p, p, p ); #else printf( " smartctl -a /dev/wd0%c (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/wd0%c (Enables SMART on first disk)\n" " smartctl -t long /dev/wd0%c (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/wd0%c" " (Prints Self-Test & Attribute errors)\n", p, p, p, p ); #endif return; } smartmontools-6.2+svn3841.orig/ataidentify.cpp0000644000000000000000000006244312116206555020102 0ustar rootroot/* * ataidentify.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2012-13 Christian Franke * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see . * */ #include "config.h" #include "ataidentify.h" const char * ataidentify_cpp_cvsid = "$Id: ataidentify.cpp 3785 2013-03-07 21:58:05Z chrfranke $" ATAIDENTIFY_H_CVSID; #include "int64.h" #include "utility.h" // Table 12 of X3T10/0948D (ATA-2) Revision 4c, March 18, 1996 // Table 9 of X3T13/2008D (ATA-3) Revision 7b, January 27, 1997 // Tables 11 and 13 of T13/1153D (ATA/ATAPI-4) revision 18, August 19, 1998 // Tables 20 and 22 of T13/1321D (ATA/ATAPI-5) Revision 3, February 29, 2000 // Tables 27 and 29 of T13/1410D (ATA/ATAPI-6) Revision 3b, February 26, 2002 // Tables 16 and 18 of T13/1532D (ATA/ATAPI-7) Volume 1 Revision 4b, April 21, 2004 // Tables 29 and 39 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008 // Tables 50 and 61 of T13/2015-D (ACS-2) Revision 7, June 22, 2011 // Tables 51 and 56 of T13/2161-D (ACS-3) Revision 4g, February 27, 2013 const char * const identify_descriptions[] = { " 0 General configuration", ". 15 Device identifier: 0 = ATA, 1 = ATAPI", ". 14:8 ATA: Vendor specific [RET-3]", ". 14 ATAPI: Must be set to 0", ". 13 ATAPI: Reserved", ". 12:8 ATAPI: Command set: 0x05 = CD/DVD", ". 7 Removable media device", ". 6 ATA: Not removable controller and/or device [OBS-6]", ". 5:3 ATA: Vendor specific [RET-3]", ". 6:5 ATAPI: DRQ after PACKET cmd: 0x0 = 3ms, 0x2 = 50us", ". 4:3 ATAPI: Reserved", ". 2 Response incomplete", ". 1 ATA: Vendor specific [RET-3]", ". 0 ATA: Reserved", ". 1:0 ATAPI: Packet size: 0x0 = 12 byte, 0x1 = 16 byte", " 1 Cylinders [OBS-6]", " 2 Specific configuration (0x37c8/738c/8c73/c837)", " 3 Heads [OBS-6]", " 4 Vendor specific [RET-3]", " 5 Vendor specific [RET-3]", " 6 Sectors per track [OBS-6]", " 7-8 Reserved for CFA (Sectors per card)", " 9 Vendor specific [RET-4]", " 10-19 Serial number (String)", " 20 Vendor specific [RET-3]", " 21 Vendor specific [RET-3]", " 22 Vendor specific bytes on READ/WRITE LONG [OBS-4]", " 23-26 Firmware revision (String)", " 27-46 Model number (String)", " 47 READ/WRITE MULTIPLE support", ". 15:8 Must be set to 0x80", ". 7:0 Maximum sectors per DRQ on READ/WRITE MULTIPLE", " 48 Trusted Computing feature set options", ". 15:14 Must be set to 0x1", ". 13:1 Reserved for the Trusted Computing Group", ". 0 Trusted Computing feature set supported", " 49 Capabilities", ". 15:14 ATA: Reserved for IDENTIFY PACKET DEVICE", ". 15 ATAPI: Interleaved DMA supported [OBS-8]", ". 14 ATAPI: Command queuing supported [OBS-8]", ". 13 ATA: Standard standby timer values supported", ". 13 ATAPI: Overlap operation supported [OBS-8]", ". 12 ATA: Reserved for IDENTIFY PACKET DEVICE", ". 12 ATAPI: ATA software reset required [OBS-5]", ". 11 IORDY supported", ". 10 IORDY may be disabled", ". 9 LBA supported", ". 8 DMA supported", ". 7:0 Vendor specific [RET-4]", " 50 Capabilities", ". 15:14 Must be set to 0x1", ". 13:2 Reserved", ". 1 Reserved [OBS-6]", ". 0 Vendor specific minimum standby timer value", " 51 PIO data transfer mode [OBS-5]", " 52 Single Word DMA data transfer mode [OBS-3]", " 53 Field validity / Free-fall Control", ". 15:8 Free-fall Control sensitivity", ". 7:3 Reserved", ". 2 Word 88 (Ultra DMA modes) is valid", ". 1 Words 64-70 (PIO modes) are valid", ". 0 Words 54-58 (CHS) are valid [OBS-6]", " 54 Current cylinders [OBS-6]", " 55 Current heads [OBS-6]", " 56 Current sectors per track [OBS-6]", " 57-58 Current capacity in sectors (DWord) [OBS-6]", " 59 Sanitize Device - READ/WRITE MULTIPLE support", ". 15 BLOCK ERASE EXT supported", ". 14 OVERWRITE EXT supported", ". 13 CRYPTO SCRAMBLE EXT supported", ". 12 Sanitize Device feature set supported", ". 11:9 Reserved", ". 8 Bits 7:0 are valid", ". 7:0 Current sectors per DRQ on READ/WRITE MULTIPLE", " 60-61 User addressable sectors for 28-bit commands (DWord)", " 62 Single Word DMA modes [OBS-3]", " 63 Multiword DMA modes", ". 15:11 Reserved", ". 10 Multiword DMA mode 2 selected", ". 9 Multiword DMA mode 1 selected", ". 8 Multiword DMA mode 0 selected", ". 7:3 Reserved", ". 2 Multiword DMA mode 2 and below supported", ". 1 Multiword DMA mode 1 and below supported", ". 0 Multiword DMA mode 0 supported", " 64 PIO modes", ". 15:2 Reserved", ". 1 PIO mode 4 supported", ". 0 PIO mode 3 supported", " 65 Minimum Multiword DMA cycle time per word in ns", " 66 Recommended Multiword DMA cycle time in ns", " 67 Minimum PIO cycle time without flow control in ns", " 68 Minimum PIO cycle time with IORDY flow control in ns", " 69 Additional support", ". 15 CFast specification supported", ". 14 Deterministic data after trim supported", ". 13 LPS Alignment Error Reporting Control supported", ". 12 DCO IDENTIFY/SET DMA supported [OBS-ACS-3]", ". 11 READ BUFFER DMA supported", ". 10 WRITE BUFFER DMA supported", ". 9 SET MAX SET PASSWORD/UNLOCK DMA supported [OBS-ACS-3]", ". 8 DOWNLOAD MICROCODE DMA supported", ". 7 Reserved for IEEE 1667", ". 6 Optional ATA device 28-bit commands supported", ". 5 Trimmed LBA range(s) returning zeroed data supported", ". 4 Device encrypts all user data", ". 3 Extended number of user addressable sectors supported", ". 2 All write cache is non-volatile", ". 1:0 Reserved", " 70 Reserved", " 71-74 ATA: Reserved for IDENTIFY PACKET DEVICE", " 71 ATAPI: Time in ns from PACKET to bus release [OBS-8]", " 72 ATAPI: Time in ns from SERVICE to BSY cleared [OBS-8]", " 73-74 ATAPI: Reserved", " 75 Queue depth", ". 15:5 Reserved", ". 4:0 Maximum queue depth - 1", " 76 Serial ATA capabilities", ". 15 READ LOG DMA EXT as equiv to READ LOG EXT supported", ". 14 Device Auto Partial to Slumber transitions supported", ". 13 Host Auto Partial to Slumber transitions supported", ". 12 NCQ priority information supported", ". 11 Unload while NCQ commands are outstanding supported", ". 10 Phy Event Counters supported", ". 9 Receipt of host initiated PM requests supported", ". 8 NCQ feature set supported", ". 7:4 Reserved for Serial ATA", ". 3 SATA Gen3 signaling speed (6.0 Gb/s) supported", ". 2 SATA Gen2 signaling speed (3.0 Gb/s) supported", ". 1 SATA Gen1 signaling speed (1.5 Gb/s) supported", ". 0 Must be set to 0", " 77 Serial ATA additional capabilities", // ACS-3 ". 15:7 Reserved for Serial ATA", ". 6 RECEIVE/SEND FPDMA QUEUED supported", ". 5 NCQ Queue Management supported", ". 4 NCQ Streaming supported", ". 3:1 Current Serial ATA signal speed", ". 0 Must be set to 0", " 78 Serial ATA features supported", ". 15:8 Reserved for Serial ATA", ". 7 NCQ Autosense supported", // ACS-3 ". 6 Software Settings Preservation supported", ". 5 Hardware Feature Control supported", // ACS-3 ". 4 In-order data delivery supported", ". 3 Device initiated power management supported", ". 2 DMA Setup auto-activation supported", ". 1 Non-zero buffer offsets supported", ". 0 Must be set to 0", " 79 Serial ATA features enabled", ". 15:8 Reserved for Serial ATA", ". 7 Automatic Partial to Slumber transitions enabled", // ACS-3 ". 6 Software Settings Preservation enabled", ". 5 Hardware Feature Control enabled", // ACS-3 ". 4 In-order data delivery enabled", ". 3 Device initiated power management enabled", ". 2 DMA Setup auto-activation enabled", ". 1 Non-zero buffer offsets enabled", ". 0 Must be set to 0", " 80 Major version number", ". 15:11 Reserved", ". 10 ACS-3 supported", ". 9 ACS-2 supported", ". 8 ATA8-ACS supported", ". 7 ATA/ATAPI-7 supported", ". 6 ATA/ATAPI-6 supported", ". 5 ATA/ATAPI-5 supported", ". 4 ATA/ATAPI-4 supported [OBS-8]", ". 3 ATA-3 supported [OBS-7]", ". 2 ATA-2 supported [OBS-6]", ". 1 ATA-1 supported [OBS-5]", ". 0 Reserved", " 81 Minor version number", " 82 Commands and feature sets supported", ". 15 IDENTIFY DEVICE DMA supported [OBS-4]", // ATA-4 r07-r14 only ". 14 NOP supported", ". 13 READ BUFFER supported", ". 12 WRITE BUFFER supported", ". 11 WRITE VERIFY supported [OBS-4]", // ATA-4 r07-r13 only ". 10 HPA feature set supported [OBS-ACS-3]", ". 9 DEVICE RESET supported", // ATA:0, ATAPI:1 ". 8 SERVICE interrupt supported [OBS-ACS-2]", ". 7 Release interrupt supported [OBS-ACS-2]", ". 6 Read look-ahead supported", ". 5 Volatile write cache supported", ". 4 PACKET feature set supported", // ATA:0, ATAPI:1 ". 3 Power Management feature set supported", ". 2 Removable Media feature set supported [OBS-8]", ". 1 Security feature set supported", ". 0 SMART feature set supported", " 83 Commands and feature sets supported", ". 15:14 Must be set to 0x1", ". 13 FLUSH CACHE EXT supported", ". 12 FLUSH CACHE supported", ". 11 DCO feature set supported [OBS-ACS-3]", ". 10 48-bit Address feature set supported", ". 9 AAM feature set supported [OBS-ACS-2]", ". 8 SET MAX security extension supported [OBS-ACS-3]", ". 7 Reserved for Address Offset Reserved Area Boot Method", ". 6 SET FEATURES subcommand required to spin-up", ". 5 PUIS feature set supported", ". 4 Removable Media Status Notification supported [OBS-8]", ". 3 APM feature set supported", ". 2 CFA feature set supported", ". 1 TCQ feature set supported [OBS-ACS-2]", ". 0 DOWNLOAD MICROCODE supported", " 84 Commands and feature sets supported", ". 15:14 Must be set to 0x1", ". 13 IDLE IMMEDIATE with UNLOAD feature supported", ". 12:11 Reserved for TLC [OBS-ACS-3]", ". 10 URG bit for WRITE STREAM (DMA) EXT supported [OBS-8]", ". 9 URG bit for READ STREAM (DMA) EXT supported [OBS-8]", ". 8 64-bit World Wide Name supported", ". 7 WRITE DMA QUEUED FUA EXT supported", ". 6 WRITE DMA/MULTIPLE FUA EXT supported", ". 5 GPL feature set supported", ". 4 Streaming feature set supported [OBS-ACS-3]", ". 3 Media Card Pass Through Command supported [OBS-ACS-2]", ". 2 Media serial number supported", // ACS-3 r3 or later: Reserved ". 1 SMART self-test supported", ". 0 SMART error logging supported", " 85 Commands and feature sets supported or enabled", ". 15 IDENTIFY DEVICE DMA supported [OBS-4]", // ATA-4 r07-r14 only ". 14 NOP supported", ". 13 READ BUFFER supported", ". 12 WRITE BUFFER supported", ". 11 WRITE VERIFY supported [OBS-4]", // ATA-4 r07-r13 only ". 10 HPA feature set supported [OBS-ACS-3]", ". 9 DEVICE RESET supported", // ATA:0, ATAPI:1 ". 8 SERVICE interrupt enabled [OBS-ACS-2]", ". 7 Release interrupt enabled [OBS-ACS-2]", ". 6 Read look-ahead enabled", ". 5 Write cache enabled", ". 4 PACKET feature set supported", // ATA:0, ATAPI:1 ". 3 Power Management feature set supported", ". 2 Removable Media feature set supported [OBS-8]", ". 1 Security feature set enabled", ". 0 SMART feature set enabled", " 86 Commands and feature sets supported or enabled", ". 15 Words 119-120 are valid", ". 14 Reserved", ". 13 FLUSH CACHE EXT supported", ". 12 FLUSH CACHE supported", ". 11 DCO feature set supported [OBS-ACS-3]", ". 10 48-bit Address features set supported", ". 9 AAM feature set enabled [OBS-ACS-2]", ". 8 SET MAX security extension enabled [OBS-ACS-3]", ". 7 Reserved for Address Offset Reserved Area Boot Method", ". 6 SET FEATURES subcommand required to spin-up", ". 5 PUIS feature set enabled", ". 4 Removable Media Status Notification enabled [OBS-8]", ". 3 APM feature set enabled", ". 2 CFA feature set supported", ". 1 TCQ feature set supported [OBS-ACS-2]", ". 0 DOWNLOAD MICROCODE supported", " 87 Commands and feature sets supported or enabled", ". 15:14 Must be set to 0x1", ". 13 IDLE IMMEDIATE with UNLOAD FEATURE supported", ". 12:11 Reserved for TLC [OBS-ACS-3]", ". 10 URG bit for WRITE STREAM (DMA) EXT supported [OBS-8]", ". 9 URG bit for READ STREAM (DMA) EXT supported [OBS-8]", ". 8 64-bit World Wide Name supported", ". 7 WRITE DMA QUEUED FUA EXT supported [OBS-ACS-2]", ". 6 WRITE DMA/MULTIPLE FUA EXT supported", ". 5 GPL feature set supported", ". 4 Valid CONFIGURE STREAM has been executed [OBS-8]", ". 3 Media Card Pass Through Command supported [OBS-ACS-2]", ". 2 Media serial number is valid", ". 1 SMART self-test supported", ". 0 SMART error logging supported", " 88 Ultra DMA modes", ". 15 Reserved", ". 14 Ultra DMA mode 6 selected", ". 13 Ultra DMA mode 5 selected", ". 12 Ultra DMA mode 4 selected", ". 11 Ultra DMA mode 3 selected", ". 10 Ultra DMA mode 2 selected", ". 9 Ultra DMA mode 1 selected", ". 8 Ultra DMA mode 0 selected", ". 7 Reserved", ". 6 Ultra DMA mode 6 and below supported", ". 5 Ultra DMA mode 5 and below supported", ". 4 Ultra DMA mode 4 and below supported", ". 3 Ultra DMA mode 3 and below supported", ". 2 Ultra DMA mode 2 and below supported", ". 1 Ultra DMA mode 1 and below supported", ". 0 Ultra DMA mode 0 supported", " 89 SECURITY ERASE UNIT time", " 90 ENHANCED SECURITY ERASE UNIT time", " 91 Current APM level", " 92 Master password revision code", " 93 Hardware reset result (PATA)", ". 15:14 Must be set to 0x1", ". 13 Device detected CBLID- above(1)/below(0) ViHB", ". 12 Reserved", ". 11 Device 1 asserted PDIAG-", ". 10:9 Device 1 detection method: -, Jumper, CSEL, other", ". 8 Must be set to 1", ". 7 Reserved", ". 6 Device 0 responds when device 1 selected", ". 5 Device 0 detected the assertion of DASP-", ". 4 Device 0 detected the assertion of PDIAG-", ". 3 Device 0 passed diagnostics", ". 2:1 Device 0 detection method: -, Jumper, CSEL, other", ". 0 Must be set to 1", " 94 AAM level [OBS-ACS-2]", ". 15:8 Recommended AAM level [OBS-ACS-2]", ". 7:0 Current AAM level [OBS-ACS-2]", " 95 Stream Minimum Request Size", " 96 Streaming Transfer Time - DMA", " 97 Streaming Access Latency - DMA and PIO", " 98-99 Streaming Performance Granularity (DWord)", "100-103 User addressable sectors for 48-bit commands (QWord)", "104 Streaming Transfer Time - PIO", "105 Max blocks of LBA Range Entries per DS MANAGEMENT cmd", "106 Physical sector size / logical sector size", ". 15:14 Must be set to 0x1", ". 13 Multiple logical sectors per physical sector", ". 12 Logical Sector longer than 256 words", ". 11:4 Reserved", ". 3:0 2^X logical sectors per physical sector", "107 Inter-seek delay for ISO 7779 acoustic testing", "108-111 64-bit World Wide Name", "112-115 Reserved for a 128-bit World Wide Name", "116 Reserved for TLC [OBS-ACS-3]", "117-118 Logical sector size (DWord)", "119 Commands and feature sets supported", ". 15:14 Must be set to 0x1", ". 13:10 Reserved", ". 9 DSN feature set supported", // ACS-3 ". 8 Accessible Max Address Config feature set supported", // ACS-3 ". 7 Extended Power Conditions feature set supported", ". 6 Sense Data Reporting feature set supported", ". 5 Free-fall Control feature set supported", ". 4 DOWNLOAD MICROCODE with mode 3 supported", ". 3 READ/WRITE LOG DMA EXT supported", ". 2 WRITE UNCORRECTABLE EXT supported", ". 1 Write-Read-Verify feature set supported", ". 0 Reserved for DDT [OBS-ACS-3]", "120 Commands and feature sets supported or enabled", ". 15:14 Must be set to 0x1", ". 13:10 Reserved", ". 9 DSN feature set enabled", // ACS-3 ". 8 Reserved", ". 7 Extended Power Conditions feature set enabled", ". 6 Sense Data Reporting feature set enabled", ". 5 Free-fall Control feature set enabled", ". 4 DOWNLOAD MICROCODE with mode 3 supported", ". 3 READ/WRITE LOG DMA EXT supported", ". 2 WRITE UNCORRECTABLE EXT supported", ". 1 Write-Read-Verify feature set enabled", ". 0 Reserved for DDT [OBS-ACS-3]", "121-126 ATA: Reserved", "121-124 ATAPI: Reserved", "125 ATAPI: Byte count = 0 behavior", "126 ATAPI: Byte count = 0 behavior [OBS-6]", "127 Removable Media Status Notification [OBS-8]", ". 15:1 Reserved", ". 0 Removable Media Status Notification supported", "128 Security status", ". 15:9 Reserved", ". 8 Master password capability: 0 = High, 1 = Maximum", ". 7:6 Reserved", ". 5 Enhanced security erase supported", ". 4 Security count expired", ". 3 Security frozen", ". 2 Security locked", ". 1 Security enabled", ". 0 Security supported", "129-159 Vendor specific", "160 CFA power mode", // ". 15 Word 160 supported", // ". 14 Reserved", // ". 13 CFA power mode 1 is required for some commands", // ". 12 CFA power mode 1 disabled", // ". 11:0 Maximum current in mA", "161-167 Reserved for CFA", "168 Form factor", ". 15:4 Reserved", ". 3:0 Nominal form factor: -, 5.25, 3.5, 2.5, 1.8, <1.8", "169 Data Set Management support", ". 15:1 Reserved", ". 0 Trim bit in DATA SET MANAGEMENT command supported", "170-173 Additional product identifier (String)", "174-175 Reserved", "176-205 Current media serial number (String)", "206 SCT Command Transport", ". 15:12 Vendor Specific", ". 11:8 Reserved", ". 7 Reserved for Serial ATA", ". 6 Reserved", ". 5 SCT Data Tables supported", ". 4 SCT Feature Control supported", ". 3 SCT Error Recovery Control supported", ". 2 SCT Write Same supported", ". 1 SCT Read/Write Long supported [OBS-ACS-2]", ". 0 SCT Command Transport supported", "207-208 Reserved for CE-ATA", "209 Alignment of logical sectors", ". 15:14 Must be set to 0x1", ". 13:0 Logical sector offset", "210-211 Write-Read-Verify sector count mode 3 (DWord)", "212-213 Write-Read-Verify sector count mode 2 (DWord)", "214 NV Cache capabilities [OBS-ACS-3]", ". 15:12 NV Cache feature set version [OBS-ACS-3]", ". 11:8 NV Cache Power Mode feature set version [OBS-ACS-3]", ". 7:5 Reserved [OBS-ACS-3]", ". 4 NV Cache feature set enabled [OBS-ACS-3]", ". 3:2 Reserved", ". 1 NV Cache Power Mode feature set enabled [OBS-ACS-3]", ". 0 NV Cache Power Mode feature set supported [OBS-ACS-3]", "215-216 NV Cache size in logical blocks (DWord) [OBS-ACS-3]", "217 Nominal media rotation rate", "218 Reserved", "219 NV Cache options [OBS-ACS-3]", ". 15:8 Reserved [OBS-ACS-3]", ". 7:0 Estimated time to spin up in seconds [OBS-ACS-3]", "220 Write-Read-Verify mode", ". 15:8 Reserved", ". 7:0 Write-Read-Verify feature set current mode", "221 Reserved", "222 Transport major version number", ". 15:12 Transport type: 0x0 = Parallel, 0x1 = Serial", ". 11:7 Reserved | Reserved", ". 6 Reserved | SATA 3.1", ". 5 Reserved | SATA 3.0", ". 4 Reserved | SATA 2.6", ". 3 Reserved | SATA 2.5", ". 2 Reserved | SATA II: Extensions", ". 1 ATA/ATAPI-7 | SATA 1.0a", ". 0 ATA8-APT | ATA8-AST", "223 Transport minor version number", "224-229 Reserved", "230-233 Extended number of user addressable sectors (QWord)", "234 Minimum blocks per DOWNLOAD MICROCODE mode 3 command", "235 Maximum blocks per DOWNLOAD MICROCODE mode 3 command", "236-254 Reserved", "255 Integrity word", ". 15:8 Checksum", ". 7:0 Signature" }; const int num_identify_descriptions = sizeof(identify_descriptions)/sizeof(identify_descriptions[0]); static inline unsigned short get_word(const void * id, int word) { const unsigned char * p = ((const unsigned char *)id) + 2 * word; return p[0] + (p[1] << 8); } void ata_print_identify_data(const void * id, bool all_words, int bit_level) { // ATA or ATAPI ? unsigned short w = get_word(id, 0); bool is_atapi = ((w & 0x8000) && (w != 0x848a/*CompactFlash Signature*/)); int prev_word = -1, prev_bit = -1; pout("Word %s Value Description\n", (bit_level >= 0 ? "Bit " : " ")); for (int i = 0; i < num_identify_descriptions; i++) { // Parse table entry const char * desc = identify_descriptions[i]; int word = prev_word, word2 = -1; int bit = -1, bit2 = -1; int nc; unsigned v1, v2; if (word >= 0 && sscanf(desc, ". %u:%u %n", &v1, &v2, (nc=-1, &nc)) == 2 && nc > 0 && 16 > v1 && v1 > v2) { bit = v1; bit2 = v2; } else if (word >= 0 && sscanf(desc, ". %u %n", &v1, (nc=-1, &nc)) == 1 && nc > 0 && v1 < 16) { bit = v1; } else if (sscanf(desc, "%u-%u %n", &v1, &v2, (nc=-1, &nc)) == 2 && nc > 0 && v1 < v2 && v2 < 256) { word = v1, word2 = v2; } else if (sscanf(desc, "%u %n", &v1, (nc=-1, &nc)) == 1 && nc > 0 && v1 < 256) { word = v1; } else { pout("Error: #%d: Syntax\n", i); continue; } desc += nc; // Check for ATA/ATAPI specific entries if (str_starts_with(desc, "ATA: ")) { if (is_atapi) continue; desc += sizeof("ATA: ")-1; } else if (str_starts_with(desc, "ATAPI: ")) { if (!is_atapi) continue; } // Check table entry if (bit < 0) { if (word != prev_word+1) { pout("Error: #%d: Missing word %d\n", i, prev_word+1); return; } else if (prev_bit > 0) { pout("Error: #%d: Missing bit 0 from word %d\n", i, prev_word); return; } } else if (!((prev_bit < 0 && bit == 15) || bit == prev_bit-1)) { pout("Error: #%d: Missing bit %d from word %d\n", i, bit+1, word); return; } w = get_word(id, word); bool w_is_set = (w != 0x0000 && w != 0xffff); if (bit >= 0) { int b; if (bit2 >= 0) b = (w >> bit2) & ~(~0 << (bit-bit2+1)); else b = (w >> bit) & 1; if ( (bit_level >= 0 && b) || (bit_level >= 1 && w_is_set) || (bit_level >= 2 && all_words)) { if (bit2 >= 0) { // Print bitfield char valstr[20]; snprintf(valstr, sizeof(valstr), "0x%0*x", (bit - bit2 + 4) >> 2, b); pout("%4d %2d:%-2d %6s %s\n", word, bit, bit2, valstr, desc); } else { // Print bit pout("%4d %2d %u %s\n", word, bit, b, desc); } } prev_bit = (bit2 >= 0 ? bit2 : bit); } else { if (word2 >= 0) { for (int j = word+1; !w_is_set && j <= word2; j++) { if (get_word(id, j) != w) w_is_set = true; } // Print word array if (all_words || w_is_set) { pout("%s%4d-%-3d %s", (bit_level >= 0 ? "\n" : ""), word, word2, (bit_level >= 0 ? "- " : "")); if (!w_is_set) { pout("0x%02x... %s\n", w & 0xff, desc); } else { bool is_str = !!strstr(desc, "(String)"); pout(". %s", desc); for (int j = word; j <= word2; j += 4) { if (j + 2*4 < word2 && !nonempty((const unsigned char *)id + 2*j, 2*(word2-j+1))) { // Remaining words are null pout("\n%4d-%-3d %s0x0000:0000:0000:00...", j, word2, (bit_level >= 0 ? ". " : "")); break; } // Print 4 words in a row pout("\n%4d-%-3d %s0x", j, (j+3 <= word2 ? j+3 : word2), (bit_level >= 0 ? ". " : "")); int k; for (k = 0; k < 4 && j+k <= word2; k++) pout("%s%04x", (k == 0 ? "" : ":"), get_word(id, j+k)); if (is_str) { // Append little endian string pout("%*s \"", 20 - 5 * k, ""); for (k = 0; k < 4 && j+k <= word2; k++) { char c2 = ((const char *)id)[2*(j+k) ]; char c1 = ((const char *)id)[2*(j+k) + 1]; pout("%c%c", (' ' <= c1 && c1 <= '~' ? c1 : '.'), (' ' <= c2 && c2 <= '~' ? c2 : '.') ); } pout("\""); } } // Print decimal value of D/QWords if (word + 1 == word2 && strstr(desc, "(DWord)")) pout(" (%u)\n", ((unsigned)get_word(id, word2) << 16) | w); else if (word + 3 == word2 && strstr(desc, "(QWord)")) pout(" (%"PRIu64")\n", ((uint64_t)get_word(id, word + 3) << 48) | ((uint64_t)get_word(id, word + 2) << 32) | ((unsigned)get_word(id, word + 1) << 16) | (unsigned)w); else pout("\n"); } } } else { // Print word if (all_words || w_is_set) pout("%s%4d %s0x%04x %s\n", (bit_level >= 0 ? "\n" : ""), word, (bit_level >= 0 ? "- " : ""), w, desc); } prev_word = (word2 >= 0 ? word2 : word); prev_bit = -1; } } pout("\n"); } smartmontools-6.2+svn3841.orig/scsiata.cpp0000644000000000000000000013124512071064456017227 0ustar rootroot/* * scsiata.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2006-12 Douglas Gilbert * Copyright (C) 2009-13 Christian Franke * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * The code in this file is based on the SCSI to ATA Translation (SAT) * draft found at http://www.t10.org . The original draft used for this * code is sat-r08.pdf which is not too far away from becoming a * standard. The SAT commands of interest to smartmontools are the * ATA PASS THROUGH SCSI (16) and ATA PASS THROUGH SCSI (12) defined in * section 12 of that document. * * sat-r09.pdf is the most recent, easily accessible draft prior to the * original SAT standard (ANSI INCITS 431-2007). By mid-2009 the second * version of the SAT standard (SAT-2) is nearing standardization. In * their wisdom an incompatible change has been introduced in draft * sat2r08a.pdf in the area of the ATA RETURN DESCRIPTOR. A new "fixed * format" ATA RETURN buffer has been defined (sat2r08b.pdf section * 12.2.7) for the case when DSENSE=0 in the Control mode page. * Unfortunately this is the normal case. If the change stands our * code will need to be extended for this case. * * With more transports "hiding" SATA disks (and other S-ATAPI devices) * behind a SCSI command set, accessing special features like SMART * information becomes a challenge. The SAT standard offers ATA PASS * THROUGH commands for special usages. Note that the SAT layer may * be inside a generic OS layer (e.g. libata in linux), in a host * adapter (HA or HBA) firmware, or somewhere on the interconnect * between the host computer and the SATA devices (e.g. a RAID made * of SATA disks and the RAID talks "SCSI" to the host computer). * Note that in the latter case, this code does not solve the * addressing issue (i.e. which SATA disk to address behind the logical * SCSI (RAID) interface). * */ #include #include #include #include #include #include "config.h" #include "int64.h" #include "scsicmds.h" #include "atacmds.h" // ataReadHDIdentity() #include "knowndrives.h" // lookup_usb_device() #include "utility.h" #include "dev_interface.h" #include "dev_ata_cmd_set.h" // ata_device_with_command_set #include "dev_tunnelled.h" // tunnelled_device<> const char * scsiata_cpp_cvsid = "$Id: scsiata.cpp 3741 2013-01-02 17:06:54Z chrfranke $"; /* This is a slightly stretched SCSI sense "descriptor" format header. The addition is to allow the 0x70 and 0x71 response codes. The idea is to place the salient data of both "fixed" and "descriptor" sense format into one structure to ease application processing. The original sense buffer should be kept around for those cases in which more information is required (e.g. the LBA of a MEDIUM ERROR). */ /// Abridged SCSI sense data struct sg_scsi_sense_hdr { unsigned char response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */ unsigned char sense_key; unsigned char asc; unsigned char ascq; unsigned char byte4; unsigned char byte5; unsigned char byte6; unsigned char additional_length; }; /* Maps the salient data from a sense buffer which is in either fixed or descriptor format into a structure mimicking a descriptor format header (i.e. the first 8 bytes of sense descriptor format). If zero response code returns 0. Otherwise returns 1 and if 'sshp' is non-NULL then zero all fields and then set the appropriate fields in that structure. sshp::additional_length is always 0 for response codes 0x70 and 0x71 (fixed format). */ static int sg_scsi_normalize_sense(const unsigned char * sensep, int sb_len, struct sg_scsi_sense_hdr * sshp); #define SAT_ATA_PASSTHROUGH_12LEN 12 #define SAT_ATA_PASSTHROUGH_16LEN 16 #define DEF_SAT_ATA_PASSTHRU_SIZE 16 #define ATA_RETURN_DESCRIPTOR 9 namespace sat { // no need to publish anything, name provided for Doxygen /// SAT support. /// Implements ATA by tunnelling through SCSI. class sat_device : public tunnelled_device< /*implements*/ ata_device /*by tunnelling through a*/, scsi_device >, virtual public /*implements*/ scsi_device { public: sat_device(smart_interface * intf, scsi_device * scsidev, const char * req_type, int passthrulen = 0, bool enable_auto = false); virtual ~sat_device() throw(); virtual smart_device * autodetect_open(); virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); virtual bool scsi_pass_through(scsi_cmnd_io * iop); private: int m_passthrulen; bool m_enable_auto; }; sat_device::sat_device(smart_interface * intf, scsi_device * scsidev, const char * req_type, int passthrulen /* = 0 */, bool enable_auto /* = false */) : smart_device(intf, scsidev->get_dev_name(), (enable_auto ? "sat,auto" : "sat"), req_type), tunnelled_device(scsidev), m_passthrulen(passthrulen), m_enable_auto(enable_auto) { if (enable_auto) hide_ata(); // Start as SCSI, switch to ATA in autodetect_open() else hide_scsi(); // ATA always if (strcmp(scsidev->get_dev_type(), "scsi")) set_info().dev_type += strprintf("+%s", scsidev->get_dev_type()); set_info().info_name = strprintf("%s [%sSAT]", scsidev->get_info_name(), (enable_auto ? "SCSI/" : "")); } sat_device::~sat_device() throw() { } // cdb[0]: ATA PASS THROUGH (16) SCSI command opcode byte (0x85) // cdb[1]: multiple_count, protocol + extend // cdb[2]: offline, ck_cond, t_dir, byte_block + t_length // cdb[3]: features (15:8) // cdb[4]: features (7:0) // cdb[5]: sector_count (15:8) // cdb[6]: sector_count (7:0) // cdb[7]: lba_low (15:8) // cdb[8]: lba_low (7:0) // cdb[9]: lba_mid (15:8) // cdb[10]: lba_mid (7:0) // cdb[11]: lba_high (15:8) // cdb[12]: lba_high (7:0) // cdb[13]: device // cdb[14]: (ata) command // cdb[15]: control (SCSI, leave as zero) // // 24 bit lba (from MSB): cdb[12] cdb[10] cdb[8] // 48 bit lba (from MSB): cdb[11] cdb[9] cdb[7] cdb[12] cdb[10] cdb[8] // // // cdb[0]: ATA PASS THROUGH (12) SCSI command opcode byte (0xa1) // cdb[1]: multiple_count, protocol + extend // cdb[2]: offline, ck_cond, t_dir, byte_block + t_length // cdb[3]: features (7:0) // cdb[4]: sector_count (7:0) // cdb[5]: lba_low (7:0) // cdb[6]: lba_mid (7:0) // cdb[7]: lba_high (7:0) // cdb[8]: device // cdb[9]: (ata) command // cdb[10]: reserved // cdb[11]: control (SCSI, leave as zero) // // // ATA Return Descriptor (component of descriptor sense data) // des[0]: descriptor code (0x9) // des[1]: additional descriptor length (0xc) // des[2]: extend (bit 0) // des[3]: error // des[4]: sector_count (15:8) // des[5]: sector_count (7:0) // des[6]: lba_low (15:8) // des[7]: lba_low (7:0) // des[8]: lba_mid (15:8) // des[9]: lba_mid (7:0) // des[10]: lba_high (15:8) // des[11]: lba_high (7:0) // des[12]: device // des[13]: status // PURPOSE // This interface routine takes ATA SMART commands and packages // them in the SAT-defined ATA PASS THROUGH SCSI commands. There are // two available SCSI commands: a 12 byte and 16 byte variant; the // one used is chosen via this->m_passthrulen . // DETAILED DESCRIPTION OF ARGUMENTS // device: is the file descriptor provided by (a SCSI dvice type) open() // command: defines the different ATA operations. // select: additional input data if needed (which log, which type of // self-test). // data: location to write output data, if needed (512 bytes). // Note: not all commands use all arguments. // RETURN VALUES // -1 if the command failed // 0 if the command succeeded, // STATUS_CHECK routine: // -1 if the command failed // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" bool sat_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_supported(in, ata_device::supports_data_out | ata_device::supports_output_regs | ata_device::supports_multi_sector | ata_device::supports_48bit, "SAT") ) return false; struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; struct sg_scsi_sense_hdr ssh; unsigned char cdb[SAT_ATA_PASSTHROUGH_16LEN]; unsigned char sense[32]; const unsigned char * ardp; int status, ard_len, have_sense; int extend = 0; int ck_cond = 0; /* set to 1 to read register(s) back */ int protocol = 3; /* non-data */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 0; /* 0 -> no data transferred */ int passthru_size = DEF_SAT_ATA_PASSTHRU_SIZE; memset(cdb, 0, sizeof(cdb)); memset(sense, 0, sizeof(sense)); // Set data direction // TODO: This works only for commands where sector_count holds count! switch (in.direction) { case ata_cmd_in::no_data: break; case ata_cmd_in::data_in: protocol = 4; // PIO data-in t_length = 2; // sector_count holds count break; case ata_cmd_in::data_out: protocol = 5; // PIO data-out t_length = 2; // sector_count holds count t_dir = 0; // to device break; default: return set_err(EINVAL, "sat_device::ata_pass_through: invalid direction=%d", (int)in.direction); } // Check condition if any output register needed if (in.out_needed.is_set()) ck_cond = 1; if ((SAT_ATA_PASSTHROUGH_12LEN == m_passthrulen) || (SAT_ATA_PASSTHROUGH_16LEN == m_passthrulen)) passthru_size = m_passthrulen; // Set extend bit on 48-bit ATA command if (in.in_regs.is_48bit_cmd()) { if (passthru_size != SAT_ATA_PASSTHROUGH_16LEN) return set_err(ENOSYS, "48-bit ATA commands require SAT ATA PASS-THROUGH (16)"); extend = 1; } cdb[0] = (SAT_ATA_PASSTHROUGH_12LEN == passthru_size) ? SAT_ATA_PASSTHROUGH_12 : SAT_ATA_PASSTHROUGH_16; cdb[1] = (protocol << 1) | extend; cdb[2] = (ck_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; if (passthru_size == SAT_ATA_PASSTHROUGH_12LEN) { // ATA PASS-THROUGH (12) const ata_in_regs & lo = in.in_regs; cdb[3] = lo.features; cdb[4] = lo.sector_count; cdb[5] = lo.lba_low; cdb[6] = lo.lba_mid; cdb[7] = lo.lba_high; cdb[8] = lo.device; cdb[9] = lo.command; } else { // ATA PASS-THROUGH (16) const ata_in_regs & lo = in.in_regs; const ata_in_regs & hi = in.in_regs.prev; // Note: all 'in.in_regs.prev.*' are always zero for 28-bit commands cdb[ 3] = hi.features; cdb[ 4] = lo.features; cdb[ 5] = hi.sector_count; cdb[ 6] = lo.sector_count; cdb[ 7] = hi.lba_low; cdb[ 8] = lo.lba_low; cdb[ 9] = hi.lba_mid; cdb[10] = lo.lba_mid; cdb[11] = hi.lba_high; cdb[12] = lo.lba_high; cdb[13] = lo.device; cdb[14] = lo.command; } memset(&io_hdr, 0, sizeof(io_hdr)); if (0 == t_length) { io_hdr.dxfer_dir = DXFER_NONE; io_hdr.dxfer_len = 0; } else if (t_dir) { /* from device */ io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = in.size; io_hdr.dxferp = (unsigned char *)in.buffer; memset(in.buffer, 0, in.size); // prefill with zeroes } else { /* to device */ io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = in.size; io_hdr.dxferp = (unsigned char *)in.buffer; } io_hdr.cmnd = cdb; io_hdr.cmnd_len = passthru_size; io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; scsi_device * scsidev = get_tunnel_dev(); if (!scsidev->scsi_pass_through(&io_hdr)) { if (scsi_debugmode > 0) pout("sat_device::ata_pass_through: scsi_pass_through() failed, " "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg()); return set_err(scsidev->get_err()); } ardp = NULL; ard_len = 0; have_sense = sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, &ssh); if (have_sense) { /* look for SAT ATA Return Descriptor */ ardp = sg_scsi_sense_desc_find(io_hdr.sensep, io_hdr.resp_sense_len, ATA_RETURN_DESCRIPTOR); if (ardp) { ard_len = ardp[1] + 2; if (ard_len < 12) ard_len = 12; else if (ard_len > 14) ard_len = 14; } scsi_do_sense_disect(&io_hdr, &sinfo); status = scsiSimpleSenseFilter(&sinfo); if (0 != status) { if (scsi_debugmode > 0) { pout("sat_device::ata_pass_through: scsi error: %s\n", scsiErrString(status)); if (ardp && (scsi_debugmode > 1)) { pout("Values from ATA Return Descriptor are:\n"); dStrHex((const char *)ardp, ard_len, 1); } } if (t_dir && (t_length > 0) && (in.direction == ata_cmd_in::data_in)) memset(in.buffer, 0, in.size); return set_err(EIO, "scsi error %s", scsiErrString(status)); } } if (ck_cond) { /* expecting SAT specific sense data */ if (have_sense) { if (ardp) { if (scsi_debugmode > 1) { pout("Values from ATA Return Descriptor are:\n"); dStrHex((const char *)ardp, ard_len, 1); } // Set output registers ata_out_regs & lo = out.out_regs; lo.error = ardp[ 3]; lo.sector_count = ardp[ 5]; lo.lba_low = ardp[ 7]; lo.lba_mid = ardp[ 9]; lo.lba_high = ardp[11]; lo.device = ardp[12]; lo.status = ardp[13]; if (in.in_regs.is_48bit_cmd()) { ata_out_regs & hi = out.out_regs.prev; hi.sector_count = ardp[ 4]; hi.lba_low = ardp[ 6]; hi.lba_mid = ardp[ 8]; hi.lba_high = ardp[10]; } } } if (ardp == NULL) ck_cond = 0; /* not the type of sense data expected */ } if (0 == ck_cond) { if (have_sense) { if ((ssh.response_code >= 0x72) && ((SCSI_SK_NO_SENSE == ssh.sense_key) || (SCSI_SK_RECOVERED_ERR == ssh.sense_key)) && (0 == ssh.asc) && (SCSI_ASCQ_ATA_PASS_THROUGH == ssh.ascq)) { if (ardp) { if (scsi_debugmode > 0) { pout("Values from ATA Return Descriptor are:\n"); dStrHex((const char *)ardp, ard_len, 1); } return set_err(EIO, "SAT command failed"); } } } } return true; } bool sat_device::scsi_pass_through(scsi_cmnd_io * iop) { scsi_device * scsidev = get_tunnel_dev(); if (!scsidev->scsi_pass_through(iop)) { set_err(scsidev->get_err()); return false; } return true; } smart_device * sat_device::autodetect_open() { if (!open() || !m_enable_auto) return this; scsi_device * scsidev = get_tunnel_dev(); unsigned char inqdata[36] = {0, }; if (scsiStdInquiry(scsidev, inqdata, sizeof(inqdata))) { smart_device::error_info err = scsidev->get_err(); close(); set_err(err.no, "INQUIRY [SAT]: %s", err.msg.c_str()); return this; } // Check for SAT "VENDOR" int inqsize = inqdata[4] + 5; bool sat = (inqsize >= 36 && !memcmp(inqdata + 8, "ATA ", 8)); // Change interface hide_ata(!sat); hide_scsi(sat); set_info().dev_type = (sat ? "sat" : scsidev->get_dev_type()); set_info().info_name = strprintf("%s [%s]", scsidev->get_info_name(), (sat ? "SAT" : "SCSI")); return this; } } // namespace ///////////////////////////////////////////////////////////////////////////// /* Attempt an IDENTIFY DEVICE ATA command via SATL when packet_interface is false otherwise attempt IDENTIFY PACKET DEVICE. If successful return true, else false */ static bool has_sat_pass_through(ata_device * dev, bool packet_interface = false) { /* Note: malloc() ensures the read buffer lands on a single page. This avoids some bugs seen on LSI controlers under FreeBSD */ char *data = (char *)malloc(512); ata_cmd_in in; in.in_regs.command = (packet_interface ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); in.set_data_in(data, 1); bool ret = dev->ata_pass_through(in); free(data); return ret; } ///////////////////////////////////////////////////////////////////////////// /* Next two functions are borrowed from sg_lib.c in the sg3_utils package. Same copyrght owner, same license as this file. */ static int sg_scsi_normalize_sense(const unsigned char * sensep, int sb_len, struct sg_scsi_sense_hdr * sshp) { if (sshp) memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr)); if ((NULL == sensep) || (0 == sb_len) || (0x70 != (0x70 & sensep[0]))) return 0; if (sshp) { sshp->response_code = (0x7f & sensep[0]); if (sshp->response_code >= 0x72) { /* descriptor format */ if (sb_len > 1) sshp->sense_key = (0xf & sensep[1]); if (sb_len > 2) sshp->asc = sensep[2]; if (sb_len > 3) sshp->ascq = sensep[3]; if (sb_len > 7) sshp->additional_length = sensep[7]; } else { /* fixed format */ if (sb_len > 2) sshp->sense_key = (0xf & sensep[2]); if (sb_len > 7) { sb_len = (sb_len < (sensep[7] + 8)) ? sb_len : (sensep[7] + 8); if (sb_len > 12) sshp->asc = sensep[12]; if (sb_len > 13) sshp->ascq = sensep[13]; } } } return 1; } // Call scsi_pass_through and check sense. // TODO: Provide as member function of class scsi_device (?) static bool scsi_pass_through_and_check(scsi_device * scsidev, scsi_cmnd_io * iop, const char * msg = "") { // Provide sense buffer unsigned char sense[32] = {0, }; iop->sensep = sense; iop->max_sense_len = sizeof(sense); iop->timeout = SCSI_TIMEOUT_DEFAULT; // Run cmd if (!scsidev->scsi_pass_through(iop)) { if (scsi_debugmode > 0) pout("%sscsi_pass_through() failed, errno=%d [%s]\n", msg, scsidev->get_errno(), scsidev->get_errmsg()); return false; } // Check sense scsi_sense_disect sinfo; scsi_do_sense_disect(iop, &sinfo); int err = scsiSimpleSenseFilter(&sinfo); if (err) { if (scsi_debugmode > 0) pout("%sscsi error: %s\n", msg, scsiErrString(err)); return scsidev->set_err(EIO, "scsi error %s", scsiErrString(err)); } return true; } ///////////////////////////////////////////////////////////////////////////// namespace sat { /// Cypress USB Brigde support. class usbcypress_device : public tunnelled_device< /*implements*/ ata_device_with_command_set /*by tunnelling through a*/, scsi_device > { public: usbcypress_device(smart_interface * intf, scsi_device * scsidev, const char * req_type, unsigned char signature); virtual ~usbcypress_device() throw(); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); unsigned char m_signature; }; usbcypress_device::usbcypress_device(smart_interface * intf, scsi_device * scsidev, const char * req_type, unsigned char signature) : smart_device(intf, scsidev->get_dev_name(), "sat", req_type), tunnelled_device(scsidev), m_signature(signature) { set_info().info_name = strprintf("%s [USB Cypress]", scsidev->get_info_name()); } usbcypress_device::~usbcypress_device() throw() { } /* see cy7c68300c_8.pdf for more information */ #define USBCYPRESS_PASSTHROUGH_LEN 16 int usbcypress_device::ata_command_interface(smart_command_set command, int select, char *data) { struct scsi_cmnd_io io_hdr; unsigned char cdb[USBCYPRESS_PASSTHROUGH_LEN]; unsigned char sense[32]; int copydata = 0; int outlen = 0; int ck_cond = 0; /* set to 1 to read register(s) back */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 0; /* 0 -> no data transferred */ int feature = 0; int ata_command = 0; int sector_count = 0; int lba_low = 0; int lba_mid = 0; int lba_high = 0; int passthru_size = USBCYPRESS_PASSTHROUGH_LEN; memset(cdb, 0, sizeof(cdb)); memset(sense, 0, sizeof(sense)); ata_command = ATA_SMART_CMD; switch (command) { case CHECK_POWER_MODE: ata_command = ATA_CHECK_POWER_MODE; ck_cond = 1; copydata = 1; break; case READ_VALUES: /* READ DATA */ feature = ATA_SMART_READ_VALUES; sector_count = 1; /* one (512 byte) block */ t_length = 2; /* sector count holds count */ copydata = 512; break; case READ_THRESHOLDS: /* obsolete */ feature = ATA_SMART_READ_THRESHOLDS; sector_count = 1; /* one (512 byte) block */ lba_low = 1; t_length = 2; /* sector count holds count */ copydata=512; break; case READ_LOG: feature = ATA_SMART_READ_LOG_SECTOR; sector_count = 1; /* one (512 byte) block */ lba_low = select; t_length = 2; /* sector count holds count */ copydata = 512; break; case WRITE_LOG: feature = ATA_SMART_WRITE_LOG_SECTOR; sector_count = 1; /* one (512 byte) block */ lba_low = select; t_length = 2; /* sector count holds count */ t_dir = 0; /* to device */ outlen = 512; break; case IDENTIFY: ata_command = ATA_IDENTIFY_DEVICE; sector_count = 1; /* one (512 byte) block */ t_length = 2; /* sector count holds count */ copydata = 512; break; case PIDENTIFY: ata_command = ATA_IDENTIFY_PACKET_DEVICE; sector_count = 1; /* one (512 byte) block */ t_length = 2; /* sector count (7:0) holds count */ copydata = 512; break; case ENABLE: feature = ATA_SMART_ENABLE; lba_low = 1; break; case DISABLE: feature = ATA_SMART_DISABLE; lba_low = 1; break; case STATUS: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. feature = ATA_SMART_STATUS; ck_cond = 1; break; case AUTO_OFFLINE: feature = ATA_SMART_AUTO_OFFLINE; sector_count = select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case AUTOSAVE: feature = ATA_SMART_AUTOSAVE; sector_count = select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case IMMEDIATE_OFFLINE: feature = ATA_SMART_IMMEDIATE_OFFLINE; lba_low = select; break; case STATUS_CHECK: // This command uses HDIO_DRIVE_TASK and has different syntax than // the other commands. feature = ATA_SMART_STATUS; /* SMART RETURN STATUS */ ck_cond = 1; break; default: pout("Unrecognized command %d in usbcypress_device::ata_command_interface()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); errno=ENOSYS; return -1; } if (ATA_SMART_CMD == ata_command) { lba_mid = 0x4f; lba_high = 0xc2; } cdb[0] = m_signature; // bVSCBSignature : vendor-specific command cdb[1] = 0x24; // bVSCBSubCommand : 0x24 for ATACB cdb[2] = 0x0; if (ata_command == ATA_IDENTIFY_DEVICE || ata_command == ATA_IDENTIFY_PACKET_DEVICE) cdb[2] |= (1<<7); //set IdentifyPacketDevice for these cmds cdb[3] = 0xff - (1<<0) - (1<<6); //features, sector count, lba low, lba med // lba high, command are valid cdb[4] = byte_block; //TransferBlockCount : 512 cdb[6] = feature; cdb[7] = sector_count; cdb[8] = lba_low; cdb[9] = lba_mid; cdb[10] = lba_high; cdb[12] = ata_command; memset(&io_hdr, 0, sizeof(io_hdr)); if (0 == t_length) { io_hdr.dxfer_dir = DXFER_NONE; io_hdr.dxfer_len = 0; } else if (t_dir) { /* from device */ io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = copydata; io_hdr.dxferp = (unsigned char *)data; memset(data, 0, copydata); /* prefill with zeroes */ } else { /* to device */ io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = outlen; io_hdr.dxferp = (unsigned char *)data; } io_hdr.cmnd = cdb; io_hdr.cmnd_len = passthru_size; io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; scsi_device * scsidev = get_tunnel_dev(); if (!scsidev->scsi_pass_through(&io_hdr)) { if (scsi_debugmode > 0) pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, " "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg()); set_err(scsidev->get_err()); return -1; } // if there is a sense the command failed or the // device doesn't support usbcypress if (io_hdr.scsi_status == SCSI_STATUS_CHECK_CONDITION && sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, NULL)) { return -1; } if (ck_cond) { unsigned char ardp[8]; int ard_len = 8; /* XXX this is racy if there other scsi command between * the first usbcypress command and this one */ //pout("If you got strange result, please retry without traffic on the disc\n"); /* we use the same command as before, but we set * * the read taskfile bit, for not executing usbcypress command, * * but reading register selected in srb->cmnd[4] */ cdb[2] = (1<<0); /* ask read taskfile */ memset(sense, 0, sizeof(sense)); /* transfert 8 bytes */ memset(&io_hdr, 0, sizeof(io_hdr)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = ard_len; io_hdr.dxferp = (unsigned char *)ardp; memset(ardp, 0, ard_len); /* prefill with zeroes */ io_hdr.cmnd = cdb; io_hdr.cmnd_len = passthru_size; io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!scsidev->scsi_pass_through(&io_hdr)) { if (scsi_debugmode > 0) pout("usbcypress_device::ata_command_interface: scsi_pass_through() failed, " "errno=%d [%s]\n", scsidev->get_errno(), scsidev->get_errmsg()); set_err(scsidev->get_err()); return -1; } // if there is a sense the command failed or the // device doesn't support usbcypress if (io_hdr.scsi_status == SCSI_STATUS_CHECK_CONDITION && sg_scsi_normalize_sense(io_hdr.sensep, io_hdr.resp_sense_len, NULL)) { return -1; } if (scsi_debugmode > 1) { pout("Values from ATA Return Descriptor are:\n"); dStrHex((const char *)ardp, ard_len, 1); } if (ATA_CHECK_POWER_MODE == ata_command) data[0] = ardp[2]; /* sector count (0:7) */ else if (STATUS_CHECK == command) { if ((ardp[4] == 0x4f) && (ardp[5] == 0xc2)) return 0; /* GOOD smart status */ if ((ardp[4] == 0xf4) && (ardp[5] == 0x2c)) return 1; // smart predicting failure, "bad" status // We haven't gotten output that makes sense so // print out some debugging info syserror("Error SMART Status command failed"); pout("This may be due to a race in usbcypress\n"); pout("Retry without other disc access\n"); pout("Please get assistance from " PACKAGE_HOMEPAGE "\n"); pout("Values from ATA Return Descriptor are:\n"); dStrHex((const char *)ardp, ard_len, 1); return -1; } } return 0; } #if 0 // Not used, see autodetect_sat_device() below. static int isprint_string(const char *s) { while (*s) { if (isprint(*s) == 0) return 0; s++; } return 1; } /* Attempt an IDENTIFY DEVICE ATA or IDENTIFY PACKET DEVICE command If successful return 1, else 0 */ // TODO: Combine with has_sat_pass_through above static int has_usbcypress_pass_through(ata_device * atadev, const char *manufacturer, const char *product) { struct ata_identify_device drive; char model[40], serial[20], firm[8]; /* issue the command and do a checksum if possible */ if (ataReadHDIdentity(atadev, &drive) < 0) return 0; /* check if model string match, revision doesn't work for me */ format_ata_string(model, drive.model, 40); if (*model == 0 || isprint_string(model) == 0) return 0; if (manufacturer && strncmp(manufacturer, model, 8)) pout("manufacturer doesn't match in pass_through test\n"); if (product && strlen(model) > 8 && strncmp(product, model+8, strlen(model)-8)) pout("product doesn't match in pass_through test\n"); /* check serial */ format_ata_string(serial, drive.serial_no, 20); if (isprint_string(serial) == 0) return 0; format_ata_string(firm, drive.fw_rev, 8); if (isprint_string(firm) == 0) return 0; return 1; } #endif ///////////////////////////////////////////////////////////////////////////// /// JMicron USB Bridge support. class usbjmicron_device : public tunnelled_device< /*implements*/ ata_device, /*by tunnelling through a*/ scsi_device > { public: usbjmicron_device(smart_interface * intf, scsi_device * scsidev, const char * req_type, bool prolific, bool ata_48bit_support, int port); virtual ~usbjmicron_device() throw(); virtual bool open(); virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); private: bool get_registers(unsigned short addr, unsigned char * buf, unsigned short size); bool m_prolific; bool m_ata_48bit_support; int m_port; }; usbjmicron_device::usbjmicron_device(smart_interface * intf, scsi_device * scsidev, const char * req_type, bool prolific, bool ata_48bit_support, int port) : smart_device(intf, scsidev->get_dev_name(), "usbjmicron", req_type), tunnelled_device(scsidev), m_prolific(prolific), m_ata_48bit_support(ata_48bit_support), m_port(port >= 0 || !prolific ? port : 0) { set_info().info_name = strprintf("%s [USB JMicron]", scsidev->get_info_name()); } usbjmicron_device::~usbjmicron_device() throw() { } bool usbjmicron_device::open() { // Open USB first if (!tunnelled_device::open()) return false; // Detect port if not specified if (m_port < 0) { unsigned char regbuf[1] = {0}; if (!get_registers(0x720f, regbuf, sizeof(regbuf))) { close(); return false; } switch (regbuf[0] & 0x44) { case 0x04: m_port = 0; break; case 0x40: m_port = 1; break; case 0x44: close(); return set_err(EINVAL, "Two devices connected, try '-d usbjmicron,[01]'"); default: close(); return set_err(ENODEV, "No device connected"); } } return true; } bool usbjmicron_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_supported(in, ata_device::supports_data_out | ata_device::supports_smart_status | (m_ata_48bit_support ? ata_device::supports_48bit_hi_null : 0), "JMicron") ) return false; if (m_port < 0) return set_err(EIO, "Unknown JMicron port"); scsi_cmnd_io io_hdr; memset(&io_hdr, 0, sizeof(io_hdr)); bool rwbit = true; unsigned char smart_status = 0; bool is_smart_status = ( in.in_regs.command == ATA_SMART_CMD && in.in_regs.features == ATA_SMART_STATUS); if (is_smart_status && in.out_needed.is_set()) { io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = 1; io_hdr.dxferp = &smart_status; } else switch (in.direction) { case ata_cmd_in::no_data: io_hdr.dxfer_dir = DXFER_NONE; break; case ata_cmd_in::data_in: io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = in.size; io_hdr.dxferp = (unsigned char *)in.buffer; memset(in.buffer, 0, in.size); break; case ata_cmd_in::data_out: io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = in.size; io_hdr.dxferp = (unsigned char *)in.buffer; rwbit = false; break; default: return set_err(EINVAL); } // Build pass through command unsigned char cdb[14]; cdb[ 0] = 0xdf; cdb[ 1] = (rwbit ? 0x10 : 0x00); cdb[ 2] = 0x00; cdb[ 3] = (unsigned char)(io_hdr.dxfer_len >> 8); cdb[ 4] = (unsigned char)(io_hdr.dxfer_len ); cdb[ 5] = in.in_regs.features; cdb[ 6] = in.in_regs.sector_count; cdb[ 7] = in.in_regs.lba_low; cdb[ 8] = in.in_regs.lba_mid; cdb[ 9] = in.in_regs.lba_high; cdb[10] = in.in_regs.device | (m_port == 0 ? 0xa0 : 0xb0); cdb[11] = in.in_regs.command; // Prolific PL3507 cdb[12] = 0x06; cdb[13] = 0x7b; io_hdr.cmnd = cdb; io_hdr.cmnd_len = (!m_prolific ? 12 : 14); scsi_device * scsidev = get_tunnel_dev(); if (!scsi_pass_through_and_check(scsidev, &io_hdr, "usbjmicron_device::ata_pass_through: ")) return set_err(scsidev->get_err()); if (in.out_needed.is_set()) { if (is_smart_status) { switch (smart_status) { case 0x01: case 0xc2: out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f; break; case 0x00: case 0x2c: out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4; break; } } #if 0 // Not needed for SMART STATUS, see also notes below else { // Read ATA output registers // NOTE: The register addresses are not valid for some older chip revisions // NOTE: There is a small race condition here! unsigned char regbuf[16] = {0, }; if (!get_registers((m_port == 0 ? 0x8000 : 0x9000), regbuf, sizeof(regbuf))) return false; out.out_regs.sector_count = regbuf[ 0]; out.out_regs.lba_mid = regbuf[ 4]; out.out_regs.lba_low = regbuf[ 6]; out.out_regs.device = regbuf[ 9]; out.out_regs.lba_high = regbuf[10]; out.out_regs.error = regbuf[13]; out.out_regs.status = regbuf[14]; } #endif } return true; } bool usbjmicron_device::get_registers(unsigned short addr, unsigned char * buf, unsigned short size) { unsigned char cdb[14]; cdb[ 0] = 0xdf; cdb[ 1] = 0x10; cdb[ 2] = 0x00; cdb[ 3] = (unsigned char)(size >> 8); cdb[ 4] = (unsigned char)(size ); cdb[ 5] = 0x00; cdb[ 6] = (unsigned char)(addr >> 8); cdb[ 7] = (unsigned char)(addr ); cdb[ 8] = 0x00; cdb[ 9] = 0x00; cdb[10] = 0x00; cdb[11] = 0xfd; // Prolific PL3507 cdb[12] = 0x06; cdb[13] = 0x7b; scsi_cmnd_io io_hdr; memset(&io_hdr, 0, sizeof(io_hdr)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = size; io_hdr.dxferp = buf; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.cmnd_len = (!m_prolific ? 12 : 14); scsi_device * scsidev = get_tunnel_dev(); if (!scsi_pass_through_and_check(scsidev, &io_hdr, "usbjmicron_device::get_registers: ")) return set_err(scsidev->get_err()); return true; } ///////////////////////////////////////////////////////////////////////////// /// SunplusIT USB Bridge support. class usbsunplus_device : public tunnelled_device< /*implements*/ ata_device, /*by tunnelling through a*/ scsi_device > { public: usbsunplus_device(smart_interface * intf, scsi_device * scsidev, const char * req_type); virtual ~usbsunplus_device() throw(); virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); }; usbsunplus_device::usbsunplus_device(smart_interface * intf, scsi_device * scsidev, const char * req_type) : smart_device(intf, scsidev->get_dev_name(), "usbsunplus", req_type), tunnelled_device(scsidev) { set_info().info_name = strprintf("%s [USB Sunplus]", scsidev->get_info_name()); } usbsunplus_device::~usbsunplus_device() throw() { } bool usbsunplus_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_supported(in, ata_device::supports_data_out | ata_device::supports_output_regs | ata_device::supports_48bit, "Sunplus") ) return false; scsi_cmnd_io io_hdr; unsigned char cdb[12]; if (in.in_regs.is_48bit_cmd()) { // Set "previous" registers memset(&io_hdr, 0, sizeof(io_hdr)); io_hdr.dxfer_dir = DXFER_NONE; cdb[ 0] = 0xf8; cdb[ 1] = 0x00; cdb[ 2] = 0x23; // Subcommand: Pass through presetting cdb[ 3] = 0x00; cdb[ 4] = 0x00; cdb[ 5] = in.in_regs.prev.features; cdb[ 6] = in.in_regs.prev.sector_count; cdb[ 7] = in.in_regs.prev.lba_low; cdb[ 8] = in.in_regs.prev.lba_mid; cdb[ 9] = in.in_regs.prev.lba_high; cdb[10] = 0x00; cdb[11] = 0x00; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); scsi_device * scsidev = get_tunnel_dev(); if (!scsi_pass_through_and_check(scsidev, &io_hdr, "usbsunplus_device::scsi_pass_through (presetting): ")) return set_err(scsidev->get_err()); } // Run Pass through command memset(&io_hdr, 0, sizeof(io_hdr)); unsigned char protocol; switch (in.direction) { case ata_cmd_in::no_data: io_hdr.dxfer_dir = DXFER_NONE; protocol = 0x00; break; case ata_cmd_in::data_in: io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = in.size; io_hdr.dxferp = (unsigned char *)in.buffer; memset(in.buffer, 0, in.size); protocol = 0x10; break; case ata_cmd_in::data_out: io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = in.size; io_hdr.dxferp = (unsigned char *)in.buffer; protocol = 0x11; break; default: return set_err(EINVAL); } cdb[ 0] = 0xf8; cdb[ 1] = 0x00; cdb[ 2] = 0x22; // Subcommand: Pass through cdb[ 3] = protocol; cdb[ 4] = (unsigned char)(io_hdr.dxfer_len >> 9); cdb[ 5] = in.in_regs.features; cdb[ 6] = in.in_regs.sector_count; cdb[ 7] = in.in_regs.lba_low; cdb[ 8] = in.in_regs.lba_mid; cdb[ 9] = in.in_regs.lba_high; cdb[10] = in.in_regs.device | 0xa0; cdb[11] = in.in_regs.command; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); scsi_device * scsidev = get_tunnel_dev(); if (!scsi_pass_through_and_check(scsidev, &io_hdr, "usbsunplus_device::scsi_pass_through: ")) // Returns sense key 0x03 (medium error) on ATA command error return set_err(scsidev->get_err()); if (in.out_needed.is_set()) { // Read ATA output registers unsigned char regbuf[8] = {0, }; memset(&io_hdr, 0, sizeof(io_hdr)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = sizeof(regbuf); io_hdr.dxferp = regbuf; cdb[ 0] = 0xf8; cdb[ 1] = 0x00; cdb[ 2] = 0x21; // Subcommand: Get status memset(cdb+3, 0, sizeof(cdb)-3); io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); if (!scsi_pass_through_and_check(scsidev, &io_hdr, "usbsunplus_device::scsi_pass_through (get registers): ")) return set_err(scsidev->get_err()); out.out_regs.error = regbuf[1]; out.out_regs.sector_count = regbuf[2]; out.out_regs.lba_low = regbuf[3]; out.out_regs.lba_mid = regbuf[4]; out.out_regs.lba_high = regbuf[5]; out.out_regs.device = regbuf[6]; out.out_regs.status = regbuf[7]; } return true; } } // namespace using namespace sat; ///////////////////////////////////////////////////////////////////////////// // Return ATA->SCSI filter for SAT or USB. ata_device * smart_interface::get_sat_device(const char * type, scsi_device * scsidev) { if (!strncmp(type, "sat", 3)) { const char * t = type + 3; bool enable_auto = false; if (!strncmp(t, ",auto", 5)) { t += 5; enable_auto = true; } int ptlen = 0, n = -1; if (*t && !(sscanf(t, ",%d%n", &ptlen, &n) == 1 && n == (int)strlen(t) && (ptlen == 0 || ptlen == 12 || ptlen == 16))) { set_err(EINVAL, "Option '-d sat[,auto][,N]' requires N to be 0, 12 or 16"); return 0; } return new sat_device(this, scsidev, type, ptlen, enable_auto); } else if (!strncmp(type, "usbcypress", 10)) { unsigned signature = 0x24; int n1 = -1, n2 = -1; if (!(((sscanf(type, "usbcypress%n,0x%x%n", &n1, &signature, &n2) == 1 && n2 == (int)strlen(type)) || n1 == (int)strlen(type)) && signature <= 0xff)) { set_err(EINVAL, "Option '-d usbcypress,' requires to be " "an hexadecimal number between 0x0 and 0xff"); return 0; } return new usbcypress_device(this, scsidev, type, signature); } else if (!strncmp(type, "usbjmicron", 10)) { const char * t = type + 10; bool prolific = false; if (!strncmp(t, ",p", 2)) { t += 2; prolific = true; } bool ata_48bit_support = false; if (!strncmp(t, ",x", 2)) { t += 2; ata_48bit_support = true; } int port = -1, n = -1; if (*t && !( (sscanf(t, ",%d%n", &port, &n) == 1 && n == (int)strlen(t) && 0 <= port && port <= 1))) { set_err(EINVAL, "Option '-d usbjmicron[,p][,x],' requires to be 0 or 1"); return 0; } return new usbjmicron_device(this, scsidev, type, prolific, ata_48bit_support, port); } else if (!strcmp(type, "usbsunplus")) { return new usbsunplus_device(this, scsidev, type); } else { set_err(EINVAL, "Unknown USB device type '%s'", type); return 0; } } // Try to detect a SAT device behind a SCSI interface. ata_device * smart_interface::autodetect_sat_device(scsi_device * scsidev, const unsigned char * inqdata, unsigned inqsize) { if (!scsidev->is_open()) return 0; // SAT ? if (inqdata && inqsize >= 36 && !memcmp(inqdata + 8, "ATA ", 8)) { // TODO: Linux-specific? ata_device_auto_ptr atadev( new sat_device(this, scsidev, "") , scsidev); if (has_sat_pass_through(atadev.get())) return atadev.release(); // Detected SAT } return 0; } ///////////////////////////////////////////////////////////////////////////// // USB device type detection // Format USB ID for error messages static std::string format_usb_id(int vendor_id, int product_id, int version) { if (version >= 0) return strprintf("[0x%04x:0x%04x (0x%03x)]", vendor_id, product_id, version); else return strprintf("[0x%04x:0x%04x]", vendor_id, product_id); } // Get type name for USB device with known VENDOR:PRODUCT ID. const char * smart_interface::get_usb_dev_type_by_id(int vendor_id, int product_id, int version /*= -1*/) { usb_dev_info info, info2; int n = lookup_usb_device(vendor_id, product_id, version, info, info2); if (n <= 0) { set_err(EINVAL, "Unknown USB bridge %s", format_usb_id(vendor_id, product_id, version).c_str()); return 0; } if (n > 1) { set_err(EINVAL, "USB bridge %s type is ambiguous: '%s' or '%s'", format_usb_id(vendor_id, product_id, version).c_str(), (!info.usb_type.empty() ? info.usb_type.c_str() : "[unsupported]"), (!info2.usb_type.empty() ? info2.usb_type.c_str() : "[unsupported]")); return 0; } if (info.usb_type.empty()) { set_err(ENOSYS, "Unsupported USB bridge %s", format_usb_id(vendor_id, product_id, version).c_str()); return 0; } // TODO: change return type to std::string static std::string type; type = info.usb_type; return type.c_str(); } smartmontools-6.2+svn3841.orig/INSTALL0000644000000000000000000007353112155132206016120 0ustar rootrootSmartmontools installation instructions ======================================= $Id: INSTALL 3817 2013-06-09 16:59:50Z chrfranke $ Please also see the smartmontools home page: http://smartmontools.sourceforge.net/ Table of contents: [1] System requirements [2] Installing from SVN [3] Installing from source tarball [4] Guidelines for different Linux distributions [5] Guidelines for FreeBSD [6] Guidelines for Darwin [7] Guidelines for NetBSD [8] Guidelines for Solaris [9] Guidelines for Cygwin [10] Guidelines for Windows [11] Guidelines for OS/2, eComStation [12] Guidelines for OpenBSD [13] Comments [14] Detailed description of ./configure options [1] System requirements ======================= A) Linux Any Linux distribution will support smartmontools if it has a kernel version greater than or equal to 2.2.14. So any recent Linux distribution should support smartmontools. There are two parts of smartmontools that may require a patched or nonstandard kernel: (1) To get the ATA RETURN SMART STATUS command, the kernel needs to support the HDIO_DRIVE_TASK ioctl(). (2) To run Selective Self-tests, the kernel needs to support the HDIO_DRIVE_TASKFILE ioctl(). If your kernel does not support one or both of these ioctls, then smartmontools will "mostly" work. The things that don't work will give you harmless warning messages. For item (1) above, any 2.4 or 2.6 series kernel will provide HDIO_DRIVE_TASK support. Some 2.2.20 and later kernels also provide this support IF they're properly patched and configured. [Andre Hedrick's IDE patches may be found at http://www.nic.funet.fi/pub/linux/kernel/people/hedrick/ide-2.2.20/ or are available from your local kernel.org mirror. They are not updated for 2.2.21 or later, and may contain a few bugs.]. If the configuration option CONFIG_IDE_TASK_IOCTL exists in your 2.2.X kernel source code tree, then your 2.2.X kernel will probably support this ioctl. [Note that this kernel configuration option does NOT need to be enabled. Its presence merely indicates that the required HDIO_DRIVE_TASK ioctl() is supported.] For item (2) above, your kernel must be configured with the kernel configuration option CONFIG_IDE_TASKFILE_IO enabled. This configuration option is present in all 2.4 and 2.6 series kernels. Some 2.2.20 and later kernels also provide this support IF they're properly patched and configured as described above. Please see FAQ section of the URL above for additional details. If you are using 3ware controllers, for full functionality you must either use version 1.02.00.037 or greater of the 3w-xxxx driver, or patch earlier 3ware 3w-xxxx drivers. See http://smartmontools.sourceforge.net/3w-xxxx.txt for the patch. The version 1.02.00.037 3w-xxxx.c driver was incorporated into kernel 2.4.23-bk2 on 3 December 2003 and into kernel 2.6.0-test5-bk11 on 23 September 2003. B) FreeBSD For FreeBSD support, a 5-current kernel that includes ATAng is required in order to support ATA drives. Even current versions of ATAng will not support 100% operation, as the SMART status can not be reliably retrieved. There is patch pending approval of the ATAng driver maintainer that will address this issue. C) Solaris The SCSI code has been tested on a variety of Solaris 8 and 9 systems. ATA/IDE code only works on SPARC platform. All tested kernels worked correctly. D) NetBSD/OpenBSD The code was tested on a 1.6ZG (i.e., 1.6-current) system. It should also function under 1.6.1 and later releases (unverified). Currently it doesn't support ATA devices on 3ware RAID controllers. E) Cygwin The code was tested on Cygwin 1.7.15-1. It should also work on other recent releases. Both Cygwin and Windows versions of smartmontools share the same code to access the IDE/ATA or SCSI devices. The information in the "Windows" section below also applies to the Cygwin version. F) Windows The code was tested on Windows XP SP3, 2003, Vista, Windows 7 and Windows 8 Release Preview. Support von Windows 9x/ME and NT4 was removed after smartmontools 5.43. ATA or SATA devices are supported if the device driver implements the SMART IOCTLs or IOCTL_IDE_PASS_THROUGH or IOCTL_ATA_PASS_THROUGH. Only the latter provides full pass-through support which is needed for all smartmontools features. SCSI and USB devices are accessed through SPTI. Special driver support is not required. 3ware 9000 RAID controllers are supported using features available in the Windows driver release 9.4.0 (3wareDrv.sys 3.0.2.70) or later. Older drivers provide SMART access to the first physical drive (port) of each logical drive (unit). If driver support is not available (7000/8000 series, 9000 on XP 64), smartctl can be used to parse SMART data output from CLI or 3DM. G) MacOS/Darwin The code was tested on MacOS 10.3.4. It should work from 10.3 forwards. It doesn't support 10.2. It's important to know that on 10.3.x, some things don't work (see WARNINGS): due to bugs in the libraries used, you cannot run a short test or switch SMART support off on a drive; if you try, you will just run an extended test or switch SMART support on. So don't panic when your "short" test seems to be taking hours. It's also not possible at present to control when the offline routine runs. If your drive doesn't have it running automatically by default, you can't run it at all. SCSI devices are not currently supported. Detecting the power status of a drive is also not currently supported. To summarize this, from another point of view, the things that are not supported fall into two categories: * Can't be implemented easily without more kernel-level support, so far as I know: - running immediate offline, conveyance, or selective tests - running any test in captive mode - aborting tests - switching automatic offline testing on or off - support for SCSI - checking the power mode [-n Directive of smartd] (this is not completely impossible, but not by using a documented API) * Work on 10.4 and later, but not on 10.3: - switching off SMART (switching *on* works fine) - switching off auto-save (but why would you want to?) - running the short test (that leaves you with only the extended test) However, some things do work well. For ATA devices, all the informational output is available, unless you want something that only an offline test updates. On many newer Mac OS systems, the hard drive comes with the offline test switched on by default, so even that works. The OS X SAT SMART Driver provides access to SMART data for SAT capable USB and Firewire devices: https://github.com/kasbert/OS-X-SAT-SMART-Driver https://github.com/RJVB/OS-X-SAT-SMART-Driver This does not require any smartctl -d TYPE option and should work also with older smartmontools releases. H) OS/2, eComStation The code was tested on eComStation 1.1, but it should work on all versions of OS/2. Innotek LibC 0.5 runtime is required. Currently only ATA disks are supported, SCSI support will be added. [2] Installing from SVN ======================= Get the sources from the SVN repository: svn co http://svn.code.sf.net/p/smartmontools/code/trunk/smartmontools smartmontools Then type: ./autogen.sh and continue with step [3] below, skipping the "unpack the tarball" step. The autogen.sh command is ONLY required when installing from SVN. You need GNU Autoconf (version 2.50 or greater), GNU Automake (version 1.7 or greater) and their dependencies installed in order to run it. You can get these here: http://directory.fsf.org/project/autoconf/ http://directory.fsf.org/project/automake/ [3] Installing from the source tarball ====================================== If you are NOT installing from SVN, then unpack the tarball: tar zxvf smartmontools-5.VERSION.tar.gz Then: ./configure make make install (you may need to be root to do this) As shown (with no options to ./configure) this defaults to the following set of installation directories: --prefix=/usr/local --sbindir=/usr/local/sbin --sysconfdir=/usr/local/etc --mandir=/usr/local/share/man --docdir=/usr/local/share/doc/smartmontools --with-exampledir=/usr/local/share/doc/smartmontools/examplescripts --with-drivedbdir=/usr/local/share/smartmontools --with-initscriptdir=auto --with-systemdsystemunitdir=auto --enable-drivedb --disable-attributelog --disable-sample --disable-savestates --with-libcap-ng=auto --without-selinux These will usually not overwrite existing "distribution" installations on Linux Systems since the FHS reserves this area for use by the system administrator. For different installation locations or distributions, simply add arguments to ./configure as shown in [4] below. If you wish to alter the default C++ compiler flags, set an environment variable CXXFLAGS='your options' before doing ./configure, or else do: make CXXFLAGS='your options' The first output line of smartctl and smartd provides information about release number, last SVN checkin date and revison, platform, and package. The latter defaults to "(local build)" and can be changed by the variable BUILD_INFO, for example: make BUILD_INFO='"(Debian 5.39-2)"' [4] Guidelines for different Linux distributions ================================================ Note: Please send corrections/additions to: smartmontools-support@lists.sourceforge.net Debian: If you don't want to overwrite any distribution package, use: ./configure Filesystem Hierarchy Standard (FHS, http://www.pathname.com/fhs/): ./configure --sbindir=/usr/local/sbin \ --sysconfdir=/usr/local/etc \ --mandir=/usr/local/man \ --docdir=/usr/local/share/doc/smartmontools \ --with-initscriptdir=/usr/local/etc/init.d Red Hat: ./configure --sbindir=/usr/sbin \ --sysconfdir=/etc \ --mandir=/usr/share/man \ --docdir=/usr/share/doc/smartmontools \ --with-initscriptdir=/etc/rc.d/init.d Slackware: If you don't want to overwrite any "distribution" package, use: ./configure Otherwise use: ./configure --sbindir=/usr/sbin \ --sysconfdir=/etc \ --mandir=/usr/share/man \ --docdir=/usr/share/doc/smartmontools \ --with-initscriptdir=/etc/rc.d And removepkg smartmontools smartsuite (only root can do this) before make install The init script works on Slackware. You just have to add an entry like the following in /etc/rc.d/rc.M or /etc/rc.d/rc.local: if [ -x /etc/rc.d/smartd ]; then . /etc/rc.d/smartd start fi To disable it: chmod 644 /etc/rc.d/smartd For a list of options: /etc/rc.d/smartd SuSE: ./configure --sbindir=/usr/sbin \ --sysconfdir=/etc \ --mandir=/usr/share/man \ --docdir=/usr/share/doc/packages/smartmontools-VERSION \ --with-initscriptdir=/etc/init.d \ [5] Guidelines for FreeBSD ========================== To match the way it will installed when it becomes available as a PORT, use the following: ./configure --prefix=/usr/local \ --docdir=/usr/local/share/doc/smartmontools-VERSION \ --with-initscriptdir=/usr/local/etc/rc.d/ \ --enable-sample NOTE: --enable-sample will cause the smartd.conf and smartd RC files to be installed with the string '.sample' append to the name, so you will end up with the following: /usr/local/etc/smartd.conf.sample /usr/local/etc/rc.d/smartd.sample [6] Guidelines for Darwin ========================= ./configure --with-initscriptdir=/Library/StartupItems If you'd like to build the i386 version on a powerpc machine, you can use CXX='g++ -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386' \ ./configure --host=i386-apple-darwin \ --with-initscriptdir=/Library/StartupItems [7] Guidelines for NetBSD ========================= ./configure --prefix=/usr/pkg \ --docdir=/usr/pkg/share/doc/smartmontools [8] Guidelines for Solaris ========================== smartmontools has been partially but not completely ported to Solaris. It includes complete SCSI support but no ATA or 3ware support. It can be compiled with either CC (Sun's C++ compiler) or GNU g++. To compile with g++: ./configure [args] make To compile with Sun CC: env CC=cc CXX=CC ./configure [args] make The correct arguments [args] to configure are: --sbindir=/usr/sbin \ --sysconfdir=/etc \ --mandir=/usr/share/man \ --docdir=/usr/share/doc/smartmontools-VERSION \ --with-initscriptdir=/etc/init.d To start the script automatically on bootup, create hardlinks that indicate when to start/stop in: /etc/rc[S0123].d/ pointing to /etc/init.d/smartd. Create: Ksmartd in rcS.d, rc0.d, rc1.d, rc2.d Ssmartd in rc3.d where is related to such that the higher snum is the lower knum must be. On usual configuration, '95' would be suitable for and '05' for respectively. If you choose these value, you can create hardlinks by: cd /etc sh -c 'for n in S 0 1 2; do ln init.d/smartd rc$n.d/K05smartd; done' sh -c 'for n in 3 ; do ln init.d/smartd rc$n.d/S95smartd; done' [9] Guidelines for Cygwin ========================= Same as Red Hat: ./configure --prefix=/usr \ --sysconfdir=/etc \ --mandir='${prefix}/share/man' OR EQUIVALENTLY ./configure --sbindir=/usr/sbin \ --sysconfdir=/etc \ --mandir=/usr/share/man \ --docdir=/usr/share/doc/smartmontools \ --with-initscriptdir=/etc/rc.d/init.d Using DOS text file type as default for the working directories ("textmode" mount option) is not recommended. Building the binaries and man pages using "make" is possible, but "make dist" and related targets work only with UNIX file type ("binmode" mount option) set. The "autogen.sh" script prints a warning if DOS type is selected. Files may also be checked out with a non-Cygwin SVN client which uses CR/LF for svn:eol-style=native. The "autogen.sh" script has svn:eol-style=LF. Bash option "-o igncr" is not required. [10] Guidelines for Windows =========================== To compile the Windows release with MinGW gcc on MSYS, use: ./configure make Instead of using "make install", copy the .exe files into some directory in the PATH. Cross-compile statically linked 32-bit version with MinGW-w64: ./configure --build=$(./config.guess) \ --host=i686-w64-mingw32 \ LDFLAGS=-static Tested on Cygwin and Debian Linux. Cross-compile statically linked 64-bit version with MinGW-w64: ./configure --build=$(./config.guess) \ --host=x86_64-w64-mingw32 \ LDFLAGS=-static Tested on Cygwin and Debian Linux with MinGW-w64 from http://mingw-w64.sourceforge.net/. Cross-compile on Cygwin with old gcc-mingw 3.x: ./configure --build=$(./config.guess) \ --host=i686-pc-mingw32 \ CC='gcc-3 -mno-cygwin' \ CXX='g++-3 -mno-cygwin' \ CXXFLAGS='-g -O2 -Wall -W -Wno-format' Cross-compile on Debian Linux with gcc-mingw32: ./configure --build=$(./config.guess) \ --host=i586-mingw32msvc To build the Windows binary distribution, use: make dist-win32 This builds the distribution in directory ./smartmontools-VERSION.win32/ and packs it into ./smartmontools-VERSION.win32.zip To create a Windows installer, use: make installer-win32 This builds the distribution directory and packs it into the self-extracting install program ./smartmontools-VERSION.win32-setup.exe The installer is build using the command "makensis" from the NSIS package. See http://nsis.sourceforge.net/ for documentation and download location. It is also possible to (cross-)build the installer on Linux. This was successfully tested on Debian with package "nsis". To create a combined 32-/64-bit installer, use this in 32-bit build directory if 64-build directory is at ../build64: make builddir_win64=../build64 installer_win32 To both create and run the (interactive) installer, use: make install-win32 Additional make targets are distdir-win32 to build the directory only and cleandist-win32 for cleanup. The binary distribution includes all documentation files converted to DOS text file format and *.html and *.txt preformatted man pages. The tools unix2dos.exe (package cygutils) and zip.exe (package zip or a native Win32 release of Info-ZIP, http://www.info-zip.org) are necessary but may be not installed by Cygwin's default settings. The event message file tool syslogevt.exe (see smartd man page) is included in the binary distribution if message compiler (windmc) and resource compiler (windres) are available. This may be disabled by passing 'WINDMC=no' to configure. To prepare os_win32 directory for MS Visual Studio C++ 2010 [Express], use the following on MSYS or Cygwin: mkdir vctmp && cd vctmp ../configure [... any MinGW option set from above ...] make config-vc10 The MSVC project files (os_win32/vc10/*) are included in SVN (but not in source tarball). The target config-vc10 from a Makefile configured for MinGW creates os_win32/vc10/{config,svnversion}.h from ./{config,svnversion}.h. The configure skript must be run outside of the source directory to avoid inclusion of the original config.h. [11] Guidelines for OS/2, eComStation ===================================== To compile the OS/2 code, please run ./os_os2/configure.os2 make make install [12] Guidelines for OpenBSD =========================== To match the way it will installed when it becomes available as a PORT, use the following: ./configure --prefix=/usr/local \ --sysconfdir=/etc \ --docdir=/usr/local/share/doc/smartmontools-VERSION \ --without-initscriptdir \ --enable-sample NOTE: --enable-sample will cause the smartd.conf and smartd RC files to be installed with the string '.sample' append to the name, so you will end up with the following: /etc/smartd.conf.sample [13] Comments ============ To compile from another directory, you can replace the step ./configure [options] by the following: mkdir objdir cd objdir ../configure [options] Man pages contents is platform-specific by default. Info specific to other platforms may be not visible. To generate man pages with full contents use: make os_man_filter= To install to another destination (used mainly by package maintainers, or to examine the package contents without risk of modifying any system files) you can replace the step: make install with: make DESTDIR=/home/myself/smartmontools-package install Use a full path. Paths like ./smartmontools-package may not work. After installing smartmontools, you can read the man pages, and try out the commands: man smartd.conf man smartctl man smartd /usr/sbin/smartctl -s on -o on -S on /dev/hda (only root can do this) /usr/sbin/smartctl -a /dev/hda (only root can do this) Note that the default location for the manual pages are /usr/share/man/man5 and /usr/share/man/man8. If "man" doesn't find them, you may need to add /usr/share/man to your MANPATH environment variable. Source and binary packages for Windows are available at http://sourceforge.net/projects/smartmontools/files/ Refer to http://sourceforge.net/apps/trac/smartmontools/wiki/Download for any additional download and installation instructions. The following files are installed if ./configure has no options: /usr/local/sbin/smartctl [Executable command-line utility] /usr/local/sbin/smartd [Executable daemon] /usr/local/sbin/update-smart-drivedb [Drive database update script] /usr/local/etc/smartd.conf [Configuration file for smartd daemon] /usr/local/etc/rc.d/init.d/smartd [Init/Startup script for smartd] /usr/local/share/man/man5/smartd.conf.5 [Manual page] /usr/local/share/man/man8/smartctl.8 [Manual page] /usr/local/share/man/man8/smartd.8 [Manual page] /usr/local/share/doc/smartmontools/AUTHORS [Information about the authors and developers] /usr/local/share/doc/smartmontools/ChangeLog [A log of changes. Also see SVN] /usr/local/share/doc/smartmontools/COPYING [GNU General Public License Version 2] /usr/local/share/doc/smartmontools/INSTALL [Installation instructions: what you're reading!] /usr/local/share/doc/smartmontools/NEWS [Significant bugs discovered in old versions] /usr/local/share/doc/smartmontools/README [Overview] /usr/local/share/doc/smartmontools/TODO [Things that need to be done/fixed] /usr/local/share/doc/smartmontools/WARNINGS [Systems where lockups or other serious problems were reported] /usr/local/share/doc/smartmontools/smartd.conf [Example configuration file for smartd] /usr/local/share/doc/smartmontools/examplescripts/ [Executable scripts for -M exec of smartd.conf (4 files)] /usr/local/share/smartmontools/drivedb.h [Drive database] If /usr/local/etc/smartd.conf exists and differs from the default then the default configuration file is installed as /usr/local/etc/smartd.conf.sample instead. The commands: make htmlman make txtman may be used to build .html and .txt preformatted man pages. These are used by the dist-win32 make target to build the Windows distribution. The commands also work on other operating system configurations if suitable versions of man2html, groff and grotty are installed. On systems without man2html, the following command should work if groff is available: make MAN2HTML='groff -man -Thtml' htmlman Some of the source files are prepared for the documentation generator Doxygen (http://www.doxygen.org/). If Doxygen is installed, the command: doxygen creates HTML documentation in doc/html and LaTeX documentation in doc/latex. If TeX is installed, the following command creates a documentation file doc/latex/refman.pdf: ( cd doc/latex && make pdf ) [14] Detailed description of arguments to configure command =========================================================== When you type: ./configure [options] there are six particularly important variables that affect where the smartmontools software is installed. The variables are listed here, with their default values in square brackets, and the quantities that they affect described following that. This is a very wide table: please read it in a wide window. OPTIONS DEFAULT AFFECTS ------- ------- ------- --prefix /usr/local Please see below --sbindir ${prefix}/sbin Directory for smartd/smartctl executables; Contents of smartd/smartctl man pages --docdir ${prefix}/share/doc/smartmontools Location of the documentation (autoconf >= 2.60 only, see also --with-docdir below) --mandir ${prefix}/share/man Directory for smartctl/smartd/smartd.conf man pages --sysconfdir ${prefix}/etc Directory for smartd.conf; Contents of smartd executable; Contents of smartd/smartd.conf man pages; Directory for rc.d/init.d/smartd init script --with-initscriptdir auto Location of init scripts --with-systemdsystemunitdir auto Location of systemd service files --with-docdir ${prefix}/share/doc/smartmontools Location of the documentation --with-exampledir ${docdir}/examplescripts Location of example scripts --enable-sample --disable-sample Adds the string '.sample' to the names of the smartd.conf file and the smartd RC file --with-os-deps os_.o OS dependent module(s) --with-selinux --without-selinux Enables SELinux support. If smartmontools has to create the /dev/tw[ae] device nodes for 3ware/AMCC controllers, this option ensures that the nodes are created with correct SELinux file contexts. --with-libcap-ng --with-libcap-ng=auto Enables/disables libcap-ng support. If enabled and libcap-ng is available, option --capabilities is added to smartd. --disable-drivedb --enable-drivedb Disables default drive database file '${drivedbdir}/drivedb.h' --with-drivedbdir ${prefix}/share/smartmontools Directory for 'drivedb.h' (implies --enable-drivedb) --enable-savestates --disable-savestates Enables default smartd state files '${savestates}MODEL-SERIAL.ata.state' --with-savestates ${prefix}/var/lib/smartmontools/smartd. Prefix for smartd state files (implies --enable-savestates) --enable-attributelog --disable-attributelog Enables default smartd attribute log files --with-attributelog ${prefix}/var/lib/smartmontools/attrlog. Prefix for smartd attribute log files (implies --enable-attributelog) Please note that in previous versions of smartmontools (<= 5.39) the default for --with-docdir was ${prefix}/share/doc/smartmontools-VERSION This was changed to make it consistent with the default of the new --docdir option added in autoconf 2.60. The defaults for --with-initscriptdir and --with-systemdsystemunitdir are guessed such that the following rules apply: - If --prefix=/usr --sysconfdir=/etc is specified, the guessed directories should be the defaults used by the current OS or distribution. - If --sysconfdir=/etc is NOT specified, the guessed directories should always be below ${prefix} or below ${sysconfdir}. Here's an example: If you set --prefix=/home/joe and none of the other four variables then the different directories that are used would be: --sbindir /home/joe/sbin --docdir /home/joe/share/doc/smartmontools --mandir /home/joe/share/man --sysconfdir /home/joe/etc --with-exampledir /home/joe/share/doc/smartmontools/examplescripts --with-drivedbdir /home/joe/share/smartmontools --with-initscriptdir [see below] --with-systemdsystemunitdir [see below] If systemd is present (and pkg-config reports /lib/systemd/system as the systemdsystemunitdir): --with-initscriptdir [disabled] --with-systemdsystemunitdir /home/joe/lib/systemd/system else if /etc/rc.d/init.d exists: --with-initscriptdir /home/joe/etc/rc.d/init.d --with-systemdsystemunitdir [disabled] else if /etc/init.d exists: --with-initscriptdir /home/joe/etc/init.d --with-systemdsystemunitdir [disabled] else if /etc/rc.d exists: --with-initscriptdir /home/joe/etc/rc.d --with-systemdsystemunitdir [disabled] else --with-initscriptdir [disabled] --with-systemdsystemunitdir [disabled] This is useful for test installs in a harmless subdirectory somewhere. Here are the four possible cases for the four variables above: Case 1: --prefix not set --variable not set ===> VARIABLE gets default value above Case 2: --prefix set --variable not set ===> VARIABLE gets PREFIX/ prepended to default value above Case 3: --prefix not set --variable set ===> VARIABLE gets value that is set Case 4: --prefix is set --variable is set ===> PREFIX is IGNORED, VARIABLE gets value that is set Here are the differences with and without --enable-sample, assuming that initscript location is set and no other options specified (see above for details) Case 1: --enable-sample provided ==> Files installed are: /usr/local/etc/smartd.conf.sample /usr/local/etc/rc.d/init.d/smartd.sample Case 2: --disable-sample provided or parameter left out ==> Files installed are: /usr/local/etc/smartd.conf /usr/local/etc/rc.d/init.d/smartd Additional information about using configure can be found here: http://www.gnu.org/software/autoconf/manual/autoconf.html#Running-configure-Scripts smartmontools-6.2+svn3841.orig/smartd.initd.in0000644000000000000000000004453712062407372020031 0ustar rootroot#! /bin/sh # smartmontools init file for smartd # Copyright (C) 2002-8 Bruce Allen # $Id: smartd.initd.in 3727 2012-12-13 17:23:06Z samm2 $ # For RedHat and cousins: # chkconfig: 2345 40 40 # description: Self Monitoring and Reporting Technology (SMART) Daemon # processname: smartd # For SuSE and cousins ### BEGIN INIT INFO # Provides: smartd # Required-Start: $syslog $remote_fs # Should-Start: sendmail # Required-Stop: $syslog $remote_fs # Should-Stop: sendmail # Default-Start: 2 3 5 # Default-Stop: # Short-Description: Monitors disk and tape health via S.M.A.R.T. # Description: Start S.M.A.R.T. disk and tape monitor. ### END INIT INFO # 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 # Software Foundation; either version 2, or (at your option) any later # version. # You should have received a copy of the GNU General Public License (for # example COPYING); if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # This code was originally developed as a Senior Thesis by Michael Cornwell # 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/. # Uncomment the line below to pass options to smartd on startup. # Note that distribution specific configuration files like # /etc/{default,sysconfig}/smartmontools might override these #smartd_opts="--interval=1800" SMARTD_BIN=/usr/local/sbin/smartd report_unsupported () { echo "Currently the smartmontools package has no init script for" echo "the $1 OS/distribution. If you can provide one or this" echo "one works after removing some ifdefs, please contact" echo "smartmontools-support@lists.sourceforge.net." exit 1 } # Red Hat or Yellow Dog or Mandrake if [ -f /etc/redhat-release -o -f /etc/yellowdog-release -o -f /etc/mandrake-release -o -f /etc/whitebox-release -o -f /etc/trustix-release -o -f /etc/tinysofa-release ] ; then # Source function library . /etc/rc.d/init.d/functions # Source configuration file. This should define the shell variable smartd_opts [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools RETVAL=0 prog=smartd pidfile=/var/lock/subsys/smartd config=/etc/smartd.conf start() { [ $UID -eq 0 ] || exit 4 [ -x $SMARTD_BIN ] || exit 5 [ -f $config ] || exit 6 echo -n $"Starting $prog: " daemon $SMARTD_BIN $smartd_opts RETVAL=$? echo [ $RETVAL = 0 ] && touch $pidfile return $RETVAL } stop() { [ $UID -eq 0 ] || exit 4 echo -n $"Shutting down $prog: " killproc $SMARTD_BIN RETVAL=$? echo rm -f $pidfile return $RETVAL } reload() { echo -n $"Reloading $prog daemon configuration: " killproc $SMARTD_BIN -HUP RETVAL=$? echo return $RETVAL } report() { echo -n $"Checking SMART devices now: " killproc $SMARTD_BIN -USR1 RETVAL=$? echo return $RETVAL } case "$1" in start) start ;; stop) stop ;; reload) reload ;; report) report ;; restart) stop start ;; condrestart|try-restart) if [ -f $pidfile ]; then stop start fi ;; force-reload) reload || (stop; start) ;; status) status $prog RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|status|condrestart|try-restart|reload|force-reload|report}" RETVAL=2 [ "$1" = 'usage' ] && RETVAL=0 esac exit $RETVAL # Slackware elif [ -f /etc/slackware-version ] ; then # Source configuration file. This should define the shell variable smartd_opts. # Email smartmontools-support@lists.sourceforge.net if there is a better choice # of path for Slackware. [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools RETVAL=0 case "$1" in start) echo -n "Starting smartd: " $SMARTD_BIN $smartd_opts RETVAL=$? echo ;; stop) echo -n "Shutting down smartd: " killall $SMARTD_BIN RETVAL=$? echo ;; restart) $0 stop sleep 1 $0 start RETVAL=$? ;; try-restart) if pidof $SMARTD_BIN >/dev/null; then $0 restart RETVAL=$? fi ;; force-reload) $0 reload || $0 restart RETVAL=$? ;; reload) echo -n "Reloading smartd configuration: " killall -s HUP $SMARTD_BIN RETVAL=$? echo ;; report) echo -n "Checking SMART devices now: " killall -s USR1 $SMARTD_BIN RETVAL=$? echo ;; status) if pidof $SMARTD_BIN >/dev/null; then echo "$SMARTD_BIN is running." else echo "$SMARTD_BIN is not running." RETVAL=1 fi ;; *) echo "Usage: $0 {start|stop|restart|try-restart|force-reload|reload|report|status}" RETVAL=1 esac exit $RETVAL # SuSE elif [ -f /etc/SuSE-release ] ; then test -x $SMARTD_BIN || exit 5 # Existence of config file is optional SMARTD_CONFIG=/etc/smartd.conf # source configuration file. [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools smartd_opts= if test -n "$SMARTD_CHECK_INTERVAL" -a "$SMARTD_CHECK_INTERVAL" != 1800 ; then smartd_opts=" -i $SMARTD_CHECK_INTERVAL" fi if test -n "$SMARTD_LOG_FACILITY" -a "$SMARTD_LOG_FACILITY" != "daemon" ; then smartd_opts="$smartd_opts -l $SMARTD_LOG_FACILITY" fi if test -n "$SMARTD_DRIVEDB" ; then smartd_opts="$smartd_opts -B $SMARTD_DRIVEDB" fi if test "$SMARTD_SAVESTATES" = "no" ; then smartd_opts="$smartd_opts -s \"\"" fi if test "$SMARTD_ATTRLOG" = "no" ; then smartd_opts="$smartd_opts -A \"\"" fi if test -n "$SMARTD_EXTRA_OPTS" ; then smartd_opts="$smartd_opts $SMARTD_EXTRA_OPTS" fi # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v be verbose in local rc status and clear it afterwards # rc_status -v -r ditto and clear both the local and overall rc status # rc_status -s display "skipped" and exit with status 3 # rc_status -u display "unused" and exit with status 3 # rc_failed set local and overall rc status to failed # rc_failed set local and overall rc status to # rc_reset clear both the local and overall rc status # rc_exit exit appropriate to overall rc status # rc_active checks whether a service is activated by symlinks . /etc/rc.status # Reset status of this service rc_reset # Return values acc. to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - user had insufficient privileges # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # 8--199 - reserved (8--99 LSB, 100--149 distrib, 150--199 appl) # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signaling is not supported) are # considered a success. case "$1" in start) echo -n "Starting smartd " ## Start daemon with startproc(8). If this fails ## the return value is set appropriately by startproc. # We don't use startproc - we need to check for return code 17. if ! /sbin/checkproc $SMARTD_BIN ; then eval $SMARTD_BIN$smartd_opts # Remember status and be verbose if test $? -ne 17 ; then rc_status -v else rc_status -u fi else rc_reset rc_status -v fi ;; stop) echo -n "Shutting down smartd " /sbin/killproc -TERM $SMARTD_BIN # Remember status and be verbose rc_status -v ;; try-restart) ## Do a restart only if the service was active before. ## Note: try-restart is now part of LSB (as of 1.9). $0 status if test $? = 0; then $0 restart else rc_reset # Not running is not a failure. fi # Remember status and be quiet rc_status ;; restart) $0 stop $0 start # Remember status and be quiet rc_status ;; force-reload|reload) echo -n "Reload service smartd " /sbin/killproc -HUP $SMARTD_BIN rc_status -v ;; report) ## Checking SMART devices now (smartd specific function) echo -n "Checking SMART devices now " /sbin/killproc -USR1 $SMARTD_BIN rc_status -v ;; status) echo -n "Checking for service smartd " ## Check status with checkproc(8), if process is running ## checkproc will return with exit status 0. # Return value is slightly different for the status command: # 0 - service up and running # 1 - service dead, but /var/run/ pid file exists # 2 - service dead, but /var/lock/ lock file exists # 3 - service not running (unused) # 4 - service status unknown :-( # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.) # NOTE: checkproc returns LSB compliant status values. /sbin/checkproc $SMARTD_BIN rc_status -v ;; probe) ## Optional: Probe for the necessity of a reload, print out the ## argument to this init script which is required for a reload. ## Note: probe is not (yet) part of LSB (as of 1.9) test $SMARTD_CONFIG -nt /var/run/smartd.pid && echo reload ;; *) echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|report|probe}" exit 1 esac rc_exit # Debian case elif [ -f /etc/debian_version ] ; then PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin SMARTDPID=/var/run/smartd.pid [ -x $SMARTD_BIN ] || exit 0 RET=0 # source configuration file [ -r /etc/default/rcS ] && . /etc/default/rcS [ -r /etc/default/smartmontools ] && . /etc/default/smartmontools smartd_opts="--pidfile $SMARTDPID $smartd_opts" case "$1" in start) echo -n "Starting S.M.A.R.T. daemon: smartd" if start-stop-daemon --start --quiet --pidfile $SMARTDPID \ --exec $SMARTD_BIN -- $smartd_opts; then echo "." else echo " (failed)" RET=1 fi ;; stop) echo -n "Stopping S.M.A.R.T. daemon: smartd" start-stop-daemon --stop --quiet --oknodo --pidfile $SMARTDPID echo "." ;; restart) $0 stop $0 start ;; force-reload) $0 reload || $0 restart ;; reload) echo -n "Reload S.M.A.R.T. daemon: smartd" if start-stop-daemon --stop --quiet --signal 1 \ --pidfile $SMARTDPID; then echo "." else echo " (failed)" RET=1 fi ;; report) echo -n "Checking SMART devices now" if start-stop-daemon --stop --quiet --signal 10 \ --pidfile $SMARTDPID; then echo "." else echo " (failed)" RET=1 fi ;; status) if pidof $SMARTD_BIN >/dev/null; then echo "$SMARTD_BIN is running." else echo "$SMARTD_BIN is not running." RET=1 fi ;; *) echo "Usage: $0 {start|stop|restart|force-reload|reload|report|status}" exit 1 esac exit $RET elif [ -f /etc/gentoo-release ] ; then report_unsupported "Gentoo" elif [ -f /etc/turbolinux-release ] ; then report_unsupported "Turbolinux" elif [ -f /etc/environment.corel ] ; then report_unsupported "Corel" # PLEASE ADD OTHER LINUX DISTRIBUTIONS JUST BEFORE THIS LINE, USING elif elif uname -a | grep FreeBSD > /dev/null 2>&1 ; then # following is replaced by port install PREFIX=@@PREFIX@@ # Updated to try both the RCNG version of things from 5.x, or fallback to # oldfashioned rc.conf if [ -r /etc/rc.subr ]; then # This is RC-NG, pick up our values . /etc/rc.subr name="smartd" rcvar="smartd_enable" command="$SMARTD_BIN" load_rc_config $name elif [ -r /etc/defaults/rc.conf ]; then # Not a 5.x system, try the default location for variables . /etc/defaults/rc.conf source_rc_confs elif [ -r /etc/rc.conf ]; then # Worst case, fallback to system config file . /etc/rc.conf fi if [ -r /etc/rc.subr ]; then # Use new functionality from RC-NG run_rc_command "$1" else PID_FILE=/var/run/smartd.pid case "$1" in start) $SMARTD_BIN -p $PID_FILE $smartd_flags echo -n " smartd" ;; stop) kill `cat $PID_FILE` echo -n " smartd" ;; restart) $0 stop sleep 1 $0 start ;; reload) kill -s HUP `cat $PID_FILE` ;; report) kill -s USR1 `cat $PID_FILE` ;; *) echo "Usage: $0 {start|stop|restart|reload|report}" exit 1 esac exit 0 fi elif uname -a | grep SunOS > /dev/null 2>&1 ; then # Source configuration file. This should define the shell variable smartd_opts. # Email smartmontools-support@lists.sourceforge.net if there is a better choice # of path for Solaris [ -r /etc/default/smartmontools ] && . /etc/default/smartmontools PID_FILE=/var/run/smartd.pid case "$1" in start) $SMARTD_BIN -p $PID_FILE $smartd_opts echo -n "smartd " ;; stop) [ -f $PID_FILE ] && kill `cat $PID_FILE` echo -n "smartd " ;; restart) $0 stop sleep 1 $0 start ;; reload) kill -s HUP `cat $PID_FILE` ;; report) kill -s USR1 `cat $PID_FILE` ;; *) echo "Usage: $0 {start|stop|restart|reload|report}" exit 1 esac exit 0 # Cygwin elif uname | grep -i CYGWIN > /dev/null 2>&1 ; then # The following settings may be changed by the configuration file below # Service Name (must be unique) smartd_svcname=smartd # Service display name smartd_svcdisp="CYGWIN smartd" # Service description smartd_svcdesc="\ Controls and monitors storage devices using the Self-Monitoring \ Analysis and Reporting Technology System (S.M.A.R.T.) \ built into ATA and SCSI Hard Drives. \ http://smartmontools.sourceforge.net/" # Source configuration file. This should define the shell variable smartd_opts. # Email smartmontools-support@lists.sourceforge.net if there is a better choice # of path for Cygwin [ -r /etc/sysconfig/smartmontools ] && . /etc/sysconfig/smartmontools PID_FILE=/var/run/smartd.pid RETVAL=0 # Note: "[ -r $PID_FILE ]" is not used here. On Cygwin, this command may # return success even if the file is present but cannot be read by current user. # If smartd is running as service, smartd.pid is owned by local system account # which is different from any user ever executing this script. case "$1" in start) if cygrunsrv -L 2>/dev/null | grep "^${smartd_svcname}$" >/dev/null 2>&1; then echo -n "Starting service $smartd_svcname: " cygrunsrv -S "$smartd_svcname" else echo -n "Starting smartd as daemon: " $SMARTD_BIN -p $PID_FILE $smartd_opts fi RETVAL=$? ;; stop) echo -n "Shutting down smartd: " pid="`cat $PID_FILE 2>/dev/null`" && kill "$pid" RETVAL=$? ;; reload) echo -n "Reloading smartd configuration: " pid="`cat $PID_FILE 2>/dev/null`" && kill -HUP "$pid" RETVAL=$? ;; report) echo -n "Checking SMART devices now: " pid="`cat $PID_FILE 2>/dev/null`" && kill -USR1 "$pid" RETVAL=$? ;; restart) $0 stop sleep 1 $0 start exit $? ;; install) shift [ $# -eq 0 ] || smartd_opts="$*" dep=; dep2= if cygrunsrv -L 2>/dev/null | grep "^syslogd$" >/dev/null 2>&1; then dep="syslogd" fi if cygrunsrv -L 2>/dev/null | grep "^syslog-ng" >/dev/null 2>&1; then dep2="syslog-ng" fi if [ -z "$dep" ]; then if [ -z "$dep2" ]; then echo "Warning: no syslog service installed, smartd will write to windows event log."; else dep="$dep2" fi else if [ -z "$dep2" ]; then : else dep= echo "Warning: both syslogd and syslog-ng installed, dependency not set." fi fi echo "Installing service ${smartd_svcname}${dep:+ (depending on '$dep')}${smartd_opts:+ with options '$smartd_opts'}:" cygrunsrv -I "$smartd_svcname" -d "$smartd_svcdisp" -f "$smartd_svcdesc" ${dep:+-y} $dep \ -e CYGWIN="$CYGWIN" -p $SMARTD_BIN -a "-n -p ${PID_FILE}${smartd_opts:+ }$smartd_opts" RETVAL=$? ;; remove) echo "Removing service $smartd_svcname:" cygrunsrv -R "$smartd_svcname" RETVAL=$? ;; status) echo -n "Checking smartd status: " if cygrunsrv -L 2>/dev/null | grep "^${smartd_svcname}$" >/dev/null 2>&1; then if cygrunsrv -Q "$smartd_svcname" 2>/dev/null | grep "State *: Running" >/dev/null 2>&1; then echo "running as service '$smartd_svcname'." elif ps -e 2>/dev/null | grep " ${SMARTD_BIN}$" >/dev/null 2>&1; then echo "installed as service '$smartd_svcname' but running as daemon." else echo "installed as service '$smartd_svcname' but not running." RETVAL=1 fi elif ps -e 2>/dev/null | grep " ${SMARTD_BIN}$" >/dev/null 2>&1; then echo "running as daemon." else echo "not running." RETVAL=1 fi exit $RETVAL ;; *) echo "Usage: $0 {start|stop|restart|reload|report|status}" echo " $0 {install [options]|remove}" exit 1 esac if [ "$RETVAL" -eq 0 ]; then echo "done"; else echo "ERROR"; fi exit $RETVAL # Add other OSes HERE, using elif... else report_unsupported "Unknown" fi # One should NEVER arrive here, except for a badly written case above, # that fails to exit. echo "SOMETHING IS WRONG WITH THE SMARTD STARTUP SCRIPT" echo "PLEASE CONTACT smartmontools-support@lists.sourceforge.net" exit 1 smartmontools-6.2+svn3841.orig/update-smart-drivedb.in0000644000000000000000000000645412153441061021442 0ustar rootroot#! /bin/sh # # smartmontools drive database update script # # Copyright (C) 2010-13 Christian Franke # # 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 Software Foundation; either version 2, or (at your option) # any later version. # # You should have received a copy of the GNU General Public License # (for example COPYING); If not, see . # # $Id: update-smart-drivedb.in 3814 2013-06-04 19:38:25Z chrfranke $ # set -e # Set by config.status PACKAGE="@PACKAGE@" VERSION="@VERSION@" prefix="@prefix@" exec_prefix="@exec_prefix@" sbindir="@sbindir@" datarootdir="@datarootdir@" datadir="@datadir@" drivedbdir="@drivedbdir@" # Download tools os_dltools="@os_dltools@" # drivedb.h update branch BRANCH="@DRIVEDB_BRANCH@" # Default drivedb location DEST="$drivedbdir/drivedb.h" # Smartctl used for syntax check SMARTCTL="$sbindir/smartctl" # Download URL for sourceforge code browser SRCEXPR='http://sourceforge.net/p/smartmontools/code/HEAD/tree/$location/smartmontools/drivedb.h?format=raw' # Parse options q="-q " case "$1" in -v) q=; shift ;; esac case "$*" in -*|*\ *) cat </dev/null || exit 1 # Find download tool DOWNLOAD= for t in $os_dltools; do if which $t >/dev/null 2>/dev/null; then case $t in curl) DOWNLOAD="curl ${q:+-s }"'-f -o "$DEST.new" "$SRC"' ;; lynx) DOWNLOAD='lynx -source "$SRC" >"$DEST.new"' ;; wget) DOWNLOAD="wget $q"'-O "$DEST.new" "$SRC"' ;; fetch) DOWNLOAD='fetch -o "$DEST.new" "$SRC"' ;; # FreeBSD ftp) DOWNLOAD='ftp -o "$DEST.new" "$SRC"' ;; # OpenBSD esac break fi done if [ -z "$DOWNLOAD" ]; then echo "$0: found none of: $os_dltools" >&2; exit 1 fi # Try possible branch first, then trunk for location in "branches/$BRANCH" "trunk"; do test -n "$q" || echo "Download from $location" errmsg= rm -f "$DEST.new" SRC="`eval echo "$SRCEXPR"`" if (eval $DOWNLOAD); then :; else errmsg="download from $location failed (HTTP error)" continue fi if grep -i '.*Error has Occurred' "$DEST.new" >/dev/null; then errmsg="download from $location failed (SF code browser error)" continue fi break done if [ -n "$errmsg" ]; then rm -f "$DEST.new" echo "$0: $errmsg" >&2 exit 1 fi # Adjust timestamp and permissions touch "$DEST.new" chmod 0644 "$DEST.new" # Check syntax rm -f "$DEST.error" if $SMARTCTL -B "$DEST.new" -P showall >/dev/null; then :; else mv "$DEST.new" "$DEST.error" echo "$DEST.error: rejected by $SMARTCTL, probably no longer compatible" >&2 exit 1 fi # Keep old file if identical rm -f "$DEST.lastcheck" if [ -f "$DEST" ]; then if cmp "$DEST" "$DEST.new" >/dev/null 2>/dev/null; then rm -f "$DEST.new" touch "$DEST.lastcheck" echo "$DEST is already up to date" exit 0 fi mv "$DEST" "$DEST.old" fi mv "$DEST.new" "$DEST" echo "$DEST updated from $location" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32.cpp���������������������������������������������������������0000644�0000000�0000000�00000342225�12172053511�017235� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2012 Hank Wu <hank@areca.com.tw> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "config.h" #define WINVER 0x0502 #define _WIN32_WINNT WINVER #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "utility.h" #include "smartctl.h" // TODO: Do not use smartctl only variables here #include "dev_interface.h" #include "dev_ata_cmd_set.h" #include "dev_areca.h" #include "os_win32/wmiquery.h" #include <errno.h> #ifdef _DEBUG #include <assert.h> #else #undef assert #define assert(x) /* */ #endif #include <stddef.h> // offsetof() #include <io.h> // access() // WIN32_LEAN_AND_MEAN may be required to prevent inclusion of <winioctl.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> #if HAVE_NTDDDISK_H // i686-pc-cygwin, i686-w64-mingw32, x86_64-w64-mingw32 // (Missing: FILE_DEVICE_SCSI) #include <devioctl.h> #include <ntdddisk.h> #include <ntddscsi.h> #include <ntddstor.h> #elif HAVE_DDK_NTDDDISK_H // older i686-pc-cygwin, i686-pc-mingw32, i586-mingw32msvc // (Missing: IOCTL_IDE_PASS_THROUGH, IOCTL_ATA_PASS_THROUGH, FILE_DEVICE_SCSI) #include <ddk/ntdddisk.h> #include <ddk/ntddscsi.h> #include <ddk/ntddstor.h> #else // MSVC10, older MinGW // (Missing: IOCTL_SCSI_MINIPORT_*) #include <ntddscsi.h> #include <winioctl.h> #endif #ifndef _WIN32 // csmisas.h requires _WIN32 but w32api-headers no longer define it on Cygwin #define _WIN32 #endif // CSMI support #include "csmisas.h" // Silence -Wunused-local-typedefs warning from g++ >= 4.8 #if __GNUC__ >= 4 #define ATTR_UNUSED __attribute__((unused)) #else #define ATTR_UNUSED /**/ #endif // Macro to check constants at compile time using a dummy typedef #define ASSERT_CONST(c, n) \ typedef char assert_const_##c[((c) == (n)) ? 1 : -1] ATTR_UNUSED #define ASSERT_SIZEOF(t, n) \ typedef char assert_sizeof_##t[(sizeof(t) == (n)) ? 1 : -1] ATTR_UNUSED #ifndef _WIN64 #define SELECT_WIN_32_64(x32, x64) (x32) #else #define SELECT_WIN_32_64(x32, x64) (x64) #endif const char * os_win32_cpp_cvsid = "$Id: os_win32.cpp 3830 2013-07-18 20:59:53Z chrfranke $"; ///////////////////////////////////////////////////////////////////////////// // Windows I/O-controls, some declarations are missing in the include files extern "C" { // SMART_* IOCTLs, also known as DFP_* (Disk Fault Protection) ASSERT_CONST(SMART_GET_VERSION, 0x074080); ASSERT_CONST(SMART_SEND_DRIVE_COMMAND, 0x07c084); ASSERT_CONST(SMART_RCV_DRIVE_DATA, 0x07c088); ASSERT_SIZEOF(GETVERSIONINPARAMS, 24); ASSERT_SIZEOF(SENDCMDINPARAMS, 32+1); ASSERT_SIZEOF(SENDCMDOUTPARAMS, 16+1); // IDE PASS THROUGH (2000, XP, undocumented) #ifndef IOCTL_IDE_PASS_THROUGH #define IOCTL_IDE_PASS_THROUGH \ CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #endif // IOCTL_IDE_PASS_THROUGH #pragma pack(1) typedef struct { IDEREGS IdeReg; ULONG DataBufferSize; UCHAR DataBuffer[1]; } ATA_PASS_THROUGH; #pragma pack() ASSERT_CONST(IOCTL_IDE_PASS_THROUGH, 0x04d028); ASSERT_SIZEOF(ATA_PASS_THROUGH, 12+1); // ATA PASS THROUGH (Win2003, XP SP2) #ifndef IOCTL_ATA_PASS_THROUGH #define IOCTL_ATA_PASS_THROUGH \ CTL_CODE(IOCTL_SCSI_BASE, 0x040B, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) typedef struct _ATA_PASS_THROUGH_EX { USHORT Length; USHORT AtaFlags; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR ReservedAsUchar; ULONG DataTransferLength; ULONG TimeOutValue; ULONG ReservedAsUlong; ULONG_PTR DataBufferOffset; UCHAR PreviousTaskFile[8]; UCHAR CurrentTaskFile[8]; } ATA_PASS_THROUGH_EX; #define ATA_FLAGS_DRDY_REQUIRED 0x01 #define ATA_FLAGS_DATA_IN 0x02 #define ATA_FLAGS_DATA_OUT 0x04 #define ATA_FLAGS_48BIT_COMMAND 0x08 #define ATA_FLAGS_USE_DMA 0x10 #define ATA_FLAGS_NO_MULTIPLE 0x20 // Vista #endif // IOCTL_ATA_PASS_THROUGH ASSERT_CONST(IOCTL_ATA_PASS_THROUGH, 0x04d02c); ASSERT_SIZEOF(ATA_PASS_THROUGH_EX, SELECT_WIN_32_64(40, 48)); // IOCTL_SCSI_PASS_THROUGH[_DIRECT] ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH, 0x04d004); ASSERT_CONST(IOCTL_SCSI_PASS_THROUGH_DIRECT, 0x04d014); ASSERT_SIZEOF(SCSI_PASS_THROUGH, SELECT_WIN_32_64(44, 56)); ASSERT_SIZEOF(SCSI_PASS_THROUGH_DIRECT, SELECT_WIN_32_64(44, 56)); // SMART IOCTL via SCSI MINIPORT ioctl #ifndef FILE_DEVICE_SCSI #define FILE_DEVICE_SCSI 0x001b #endif #ifndef IOCTL_SCSI_MINIPORT_SMART_VERSION #define IOCTL_SCSI_MINIPORT_SMART_VERSION ((FILE_DEVICE_SCSI << 16) + 0x0500) #define IOCTL_SCSI_MINIPORT_IDENTIFY ((FILE_DEVICE_SCSI << 16) + 0x0501) #define IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS ((FILE_DEVICE_SCSI << 16) + 0x0502) #define IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS ((FILE_DEVICE_SCSI << 16) + 0x0503) #define IOCTL_SCSI_MINIPORT_ENABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0504) #define IOCTL_SCSI_MINIPORT_DISABLE_SMART ((FILE_DEVICE_SCSI << 16) + 0x0505) #define IOCTL_SCSI_MINIPORT_RETURN_STATUS ((FILE_DEVICE_SCSI << 16) + 0x0506) #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE ((FILE_DEVICE_SCSI << 16) + 0x0507) #define IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES ((FILE_DEVICE_SCSI << 16) + 0x0508) #define IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS ((FILE_DEVICE_SCSI << 16) + 0x0509) #define IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE ((FILE_DEVICE_SCSI << 16) + 0x050a) #define IOCTL_SCSI_MINIPORT_READ_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050b) #define IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG ((FILE_DEVICE_SCSI << 16) + 0x050c) #endif // IOCTL_SCSI_MINIPORT_SMART_VERSION ASSERT_CONST(IOCTL_SCSI_MINIPORT, 0x04d008); ASSERT_SIZEOF(SRB_IO_CONTROL, 28); // IOCTL_STORAGE_QUERY_PROPERTY #ifndef IOCTL_STORAGE_QUERY_PROPERTY #define IOCTL_STORAGE_QUERY_PROPERTY \ CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) typedef struct _STORAGE_DEVICE_DESCRIPTOR { ULONG Version; ULONG Size; UCHAR DeviceType; UCHAR DeviceTypeModifier; BOOLEAN RemovableMedia; BOOLEAN CommandQueueing; ULONG VendorIdOffset; ULONG ProductIdOffset; ULONG ProductRevisionOffset; ULONG SerialNumberOffset; STORAGE_BUS_TYPE BusType; ULONG RawPropertiesLength; UCHAR RawDeviceProperties[1]; } STORAGE_DEVICE_DESCRIPTOR; typedef enum _STORAGE_QUERY_TYPE { PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined } STORAGE_QUERY_TYPE; typedef enum _STORAGE_PROPERTY_ID { StorageDeviceProperty = 0, StorageAdapterProperty, StorageDeviceIdProperty, StorageDeviceUniqueIdProperty, StorageDeviceWriteCacheProperty, StorageMiniportProperty, StorageAccessAlignmentProperty } STORAGE_PROPERTY_ID; typedef struct _STORAGE_PROPERTY_QUERY { STORAGE_PROPERTY_ID PropertyId; STORAGE_QUERY_TYPE QueryType; UCHAR AdditionalParameters[1]; } STORAGE_PROPERTY_QUERY; #endif // IOCTL_STORAGE_QUERY_PROPERTY ASSERT_CONST(IOCTL_STORAGE_QUERY_PROPERTY, 0x002d1400); ASSERT_SIZEOF(STORAGE_DEVICE_DESCRIPTOR, 36+1+3); ASSERT_SIZEOF(STORAGE_PROPERTY_QUERY, 8+1+3); // IOCTL_STORAGE_PREDICT_FAILURE ASSERT_CONST(IOCTL_STORAGE_PREDICT_FAILURE, 0x002d1100); ASSERT_SIZEOF(STORAGE_PREDICT_FAILURE, 4+512); // 3ware specific versions of SMART ioctl structs #define SMART_VENDOR_3WARE 0x13C1 // identifies 3ware specific parameters #pragma pack(1) typedef struct _GETVERSIONINPARAMS_EX { BYTE bVersion; BYTE bRevision; BYTE bReserved; BYTE bIDEDeviceMap; DWORD fCapabilities; DWORD dwDeviceMapEx; // 3ware specific: RAID drive bit map WORD wIdentifier; // Vendor specific identifier WORD wControllerId; // 3ware specific: Controller ID (0,1,...) ULONG dwReserved[2]; } GETVERSIONINPARAMS_EX; typedef struct _SENDCMDINPARAMS_EX { DWORD cBufferSize; IDEREGS irDriveRegs; BYTE bDriveNumber; BYTE bPortNumber; // 3ware specific: port number WORD wIdentifier; // Vendor specific identifier DWORD dwReserved[4]; BYTE bBuffer[1]; } SENDCMDINPARAMS_EX; #pragma pack() ASSERT_SIZEOF(GETVERSIONINPARAMS_EX, sizeof(GETVERSIONINPARAMS)); ASSERT_SIZEOF(SENDCMDINPARAMS_EX, sizeof(SENDCMDINPARAMS)); // CSMI structs ASSERT_SIZEOF(IOCTL_HEADER, sizeof(SRB_IO_CONTROL)); ASSERT_SIZEOF(CSMI_SAS_DRIVER_INFO_BUFFER, 204); ASSERT_SIZEOF(CSMI_SAS_PHY_INFO_BUFFER, 2080); ASSERT_SIZEOF(CSMI_SAS_STP_PASSTHRU_BUFFER, 168); } // extern "C" ///////////////////////////////////////////////////////////////////////////// namespace os_win32 { // no need to publish anything, name provided for Doxygen #ifdef _MSC_VER #pragma warning(disable:4250) #endif class win_smart_device : virtual public /*implements*/ smart_device { public: win_smart_device() : smart_device(never_called), m_fh(INVALID_HANDLE_VALUE) { } virtual ~win_smart_device() throw(); virtual bool is_open() const; virtual bool close(); protected: /// Set handle for open() in derived classes. void set_fh(HANDLE fh) { m_fh = fh; } /// Return handle for derived classes. HANDLE get_fh() const { return m_fh; } private: HANDLE m_fh; ///< File handle }; ///////////////////////////////////////////////////////////////////////////// class win_ata_device : public /*implements*/ ata_device, public /*extends*/ win_smart_device { public: win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual ~win_ata_device() throw(); virtual bool open(); virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); virtual bool ata_identify_is_cached() const; private: bool open(int phydrive, int logdrive, const char * options, int port); std::string m_options; bool m_usr_options; // options set by user? bool m_admin; // open with admin access? int m_phydrive; // PhysicalDriveN or -1 bool m_id_is_cached; // ata_identify_is_cached() return value. bool m_is_3ware; // LSI/3ware controller detected? int m_port; // LSI/3ware port int m_smartver_state; }; ///////////////////////////////////////////////////////////////////////////// class win_scsi_device : public /*implements*/ scsi_device, virtual public /*extends*/ win_smart_device { public: win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual bool open(); virtual bool scsi_pass_through(scsi_cmnd_io * iop); private: bool open(int pd_num, int ld_num, int tape_num, int sub_addr); }; ///////////////////////////////////////////////////////////////////////////// class csmi_device : virtual public /*extends*/ smart_device { public: /// Get phy info bool get_phy_info(CSMI_SAS_PHY_INFO & phy_info); /// Check physical drive existence bool check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no); protected: csmi_device() : smart_device(never_called) { memset(&m_phy_ent, 0, sizeof(m_phy_ent)); } /// Select physical drive bool select_phy(unsigned phy_no); /// Get info for selected physical drive const CSMI_SAS_PHY_ENTITY & get_phy_ent() const { return m_phy_ent; } /// Call platform-specific CSMI ioctl virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer, unsigned csmi_bufsiz) = 0; private: CSMI_SAS_PHY_ENTITY m_phy_ent; ///< CSMI info for this phy }; class csmi_ata_device : virtual public /*extends*/ csmi_device, virtual public /*implements*/ ata_device { public: virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); protected: csmi_ata_device() : smart_device(never_called) { } }; ////////////////////////////////////////////////////////////////////// class win_csmi_device : public /*implements*/ csmi_ata_device { public: win_csmi_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual ~win_csmi_device() throw(); virtual bool open(); virtual bool close(); virtual bool is_open() const; bool open_scsi(); protected: virtual bool csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer, unsigned csmi_bufsiz); private: HANDLE m_fh; ///< Controller device handle unsigned m_phy_no; ///< Physical drive number }; ////////////////////////////////////////////////////////////////////// class win_tw_cli_device : public /*implements*/ ata_device_with_command_set { public: win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual bool is_open() const; virtual bool open(); virtual bool close(); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); private: bool m_ident_valid, m_smart_valid; ata_identify_device m_ident_buf; ata_smart_values m_smart_buf; }; ///////////////////////////////////////////////////////////////////////////// /// Areca RAID support /////////////////////////////////////////////////////////////////// // SATA(ATA) device behind Areca RAID Controller class win_areca_ata_device : public /*implements*/ areca_ata_device, public /*extends*/ win_smart_device { public: win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); virtual bool open(); virtual smart_device * autodetect_open(); virtual bool arcmsr_lock(); virtual bool arcmsr_unlock(); virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); private: HANDLE m_mutex; }; /////////////////////////////////////////////////////////////////// // SAS(SCSI) device behind Areca RAID Controller class win_areca_scsi_device : public /*implements*/ areca_scsi_device, public /*extends*/ win_smart_device { public: win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); virtual bool open(); virtual smart_device * autodetect_open(); virtual bool arcmsr_lock(); virtual bool arcmsr_unlock(); virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); private: HANDLE m_mutex; }; ////////////////////////////////////////////////////////////////////// // Platform specific interface class win_smart_interface : public /*implements part of*/ smart_interface { public: virtual std::string get_os_version_str(); virtual std::string get_app_examples(const char * appname); #ifndef __CYGWIN__ virtual int64_t get_timer_usec(); #endif virtual bool disable_system_auto_standby(bool disable); virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern = 0); protected: virtual ata_device * get_ata_device(const char * name, const char * type); virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); virtual smart_device * get_custom_smart_device(const char * name, const char * type); virtual std::string get_valid_custom_dev_types_str(); }; ////////////////////////////////////////////////////////////////////// #ifndef _WIN64 // Running on 64-bit Windows as 32-bit app ? static bool is_wow64() { BOOL (WINAPI * IsWow64Process_p)(HANDLE, PBOOL) = (BOOL (WINAPI *)(HANDLE, PBOOL)) GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process"); if (!IsWow64Process_p) return false; BOOL w64 = FALSE; if (!IsWow64Process_p(GetCurrentProcess(), &w64)) return false; return !!w64; } #endif // _WIN64 // Return info string about build host and OS version std::string win_smart_interface::get_os_version_str() { char vstr[sizeof(SMARTMONTOOLS_BUILD_HOST)-1+sizeof("-2003r2(64)-sp2.1")+13] = SMARTMONTOOLS_BUILD_HOST; if (vstr[1] < '6') vstr[1] = '6'; char * const vptr = vstr+sizeof(SMARTMONTOOLS_BUILD_HOST)-1; const int vlen = sizeof(vstr)-sizeof(SMARTMONTOOLS_BUILD_HOST); assert(vptr == vstr+strlen(vstr) && vptr+vlen+1 == vstr+sizeof(vstr)); OSVERSIONINFOEXA vi; memset(&vi, 0, sizeof(vi)); vi.dwOSVersionInfoSize = sizeof(vi); if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { memset(&vi, 0, sizeof(vi)); vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); if (!GetVersionExA((OSVERSIONINFOA *)&vi)) return vstr; } const char * w = 0; if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) { if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) { // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the // actual OS version, see: // http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx ULONGLONG major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); for (unsigned major = vi.dwMajorVersion; major <= 9; major++) { OSVERSIONINFOEXA vi2; memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major; if (!VerifyVersionInfo(&vi2, VER_MAJORVERSION, major_equal)) continue; if (vi.dwMajorVersion < major) { vi.dwMajorVersion = major; vi.dwMinorVersion = 0; } ULONGLONG minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); for (unsigned minor = vi.dwMinorVersion; minor <= 9; minor++) { memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMinorVersion = minor; if (!VerifyVersionInfo(&vi2, VER_MINORVERSION, minor_equal)) continue; vi.dwMinorVersion = minor; break; } break; } } if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) { bool ws = (vi.wProductType <= VER_NT_WORKSTATION); switch (vi.dwMajorVersion << 4 | vi.dwMinorVersion) { case 0x50: w = "2000"; break; case 0x51: w = "xp"; break; case 0x52: w = (!GetSystemMetrics(89/*SM_SERVERR2*/) ? "2003" : "2003r2"); break; case 0x60: w = (ws ? "vista" : "2008" ); break; case 0x61: w = (ws ? "win7" : "2008r2"); break; case 0x62: w = (ws ? "win8" : "2012" ); break; case 0x63: w = (ws ? "win8.1": "2012r2"); break; } } } const char * w64 = ""; #ifndef _WIN64 if (is_wow64()) w64 = "(64)"; #endif if (!w) snprintf(vptr, vlen, "-%s%u.%u%s", (vi.dwPlatformId==VER_PLATFORM_WIN32_NT ? "nt" : "??"), (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64); else if (vi.wServicePackMinor) snprintf(vptr, vlen, "-%s%s-sp%u.%u", w, w64, vi.wServicePackMajor, vi.wServicePackMinor); else if (vi.wServicePackMajor) snprintf(vptr, vlen, "-%s%s-sp%u", w, w64, vi.wServicePackMajor); else snprintf(vptr, vlen, "-%s%s", w, w64); return vstr; } #ifndef __CYGWIN__ // MSVCRT only provides ftime() which uses GetSystemTime() // This provides only ~15ms resolution by default. // Use QueryPerformanceCounter instead (~300ns). // (Cygwin provides CLOCK_MONOTONIC which has the same effect) int64_t win_smart_interface::get_timer_usec() { static int64_t freq = 0; LARGE_INTEGER t; if (freq == 0) freq = (QueryPerformanceFrequency(&t) ? t.QuadPart : -1); if (freq <= 0) return smart_interface::get_timer_usec(); if (!QueryPerformanceCounter(&t)) return -1; if (!(0 <= t.QuadPart && t.QuadPart <= (int64_t)(~(uint64_t)0 >> 1)/1000000)) return -1; return (t.QuadPart * 1000000LL) / freq; } #endif // __CYGWIN__ // Return value for device detection functions enum win_dev_type { DEV_UNKNOWN = 0, DEV_ATA, DEV_SCSI, DEV_USB }; static win_dev_type get_phy_drive_type(int drive); static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex); static win_dev_type get_log_drive_type(int drive); static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id); static const char * ata_get_def_options(void); static int is_permissive() { if (!failuretest_permissive) { pout("To continue, add one or more '-T permissive' options.\n"); return 0; } failuretest_permissive--; return 1; } // return number for drive letter, -1 on error // "[A-Za-z]:([/\\][.]?)?" => 0-25 // Accepts trailing '"' to fix broken "X:\" parameter passing from .bat files static int drive_letter(const char * s) { return ( (('A' <= s[0] && s[0] <= 'Z') || ('a' <= s[0] && s[0] <= 'z')) && s[1] == ':' && (!s[2] || ( strchr("/\\\"", s[2]) && (!s[3] || (s[3] == '.' && !s[4]))) ) ? (s[0] & 0x1f) - 1 : -1); } // Skip trailing "/dev/", do not allow "/dev/X:" static const char * skipdev(const char * s) { return (!strncmp(s, "/dev/", 5) && drive_letter(s+5) < 0 ? s+5 : s); } ata_device * win_smart_interface::get_ata_device(const char * name, const char * type) { const char * testname = skipdev(name); if (!strncmp(testname, "csmi", 4)) return new win_csmi_device(this, name, type); if (!strncmp(testname, "tw_cli", 6)) return new win_tw_cli_device(this, name, type); return new win_ata_device(this, name, type); } scsi_device * win_smart_interface::get_scsi_device(const char * name, const char * type) { return new win_scsi_device(this, name, type); } static int sdxy_to_phydrive(const char (& xy)[2+1]) { int phydrive = xy[0] - 'a'; if (xy[1]) phydrive = (phydrive + 1) * ('z' - 'a' + 1) + (xy[1] - 'a'); return phydrive; } static win_dev_type get_dev_type(const char * name, int & phydrive) { phydrive = -1; name = skipdev(name); if (!strncmp(name, "st", 2)) return DEV_SCSI; if (!strncmp(name, "nst", 3)) return DEV_SCSI; if (!strncmp(name, "tape", 4)) return DEV_SCSI; int logdrive = drive_letter(name); if (logdrive >= 0) { win_dev_type type = get_log_drive_type(logdrive); return (type != DEV_UNKNOWN ? type : DEV_SCSI); } char drive[2+1] = ""; if (sscanf(name, "sd%2[a-z]", drive) == 1) { phydrive = sdxy_to_phydrive(drive); return get_phy_drive_type(phydrive); } phydrive = -1; if (sscanf(name, "pd%d", &phydrive) == 1 && phydrive >= 0) return get_phy_drive_type(phydrive); return DEV_UNKNOWN; } smart_device * win_smart_interface::get_custom_smart_device(const char * name, const char * type) { // Areca? int disknum = -1, n1 = -1, n2 = -1; int encnum = 1; char devpath[32]; if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { if (!(1 <= disknum && disknum <= 128)) { set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); return 0; } if (!(1 <= encnum && encnum <= 8)) { set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); return 0; } name = skipdev(name); #define ARECA_MAX_CTLR_NUM 16 n1 = -1; int ctlrindex = 0; if (sscanf(name, "arcmsr%d%n", &ctlrindex, &n1) >= 1 && n1 == (int)strlen(name)) { /* 1. scan from "\\\\.\\scsi[0]:" up to "\\\\.\\scsi[ARECA_MAX_CTLR_NUM]:" and 2. map arcmsrX into "\\\\.\\scsiX" */ for (int idx = 0; idx < ARECA_MAX_CTLR_NUM; idx++) { memset(devpath, 0, sizeof(devpath)); snprintf(devpath, sizeof(devpath), "\\\\.\\scsi%d:", idx); win_areca_ata_device *arcdev = new win_areca_ata_device(this, devpath, disknum, encnum); if(arcdev->arcmsr_probe()) { if(ctlrindex-- == 0) { return arcdev; } } delete arcdev; } set_err(ENOENT, "No Areca controller found"); } else set_err(EINVAL, "Option -d areca,N/E requires device name /dev/arcmsrX"); } return 0; } std::string win_smart_interface::get_valid_custom_dev_types_str() { return "areca,N[/E]"; } smart_device * win_smart_interface::autodetect_smart_device(const char * name) { const char * testname = skipdev(name); if (str_starts_with(testname, "hd")) return new win_ata_device(this, name, ""); if (str_starts_with(testname, "tw_cli")) return new win_tw_cli_device(this, name, ""); if (str_starts_with(testname, "csmi")) return new win_csmi_device(this, name, ""); int phydrive = -1; win_dev_type type = get_dev_type(name, phydrive); if (type == DEV_ATA) return new win_ata_device(this, name, ""); if (type == DEV_SCSI) return new win_scsi_device(this, name, ""); if (type == DEV_USB) { // Get USB bridge ID unsigned short vendor_id = 0, product_id = 0; if (!(phydrive >= 0 && get_usb_id(phydrive, vendor_id, product_id))) { set_err(EINVAL, "Unable to read USB device ID"); return 0; } // Get type name for this ID const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id); if (!usbtype) return 0; // Return SAT/USB device for this type return get_sat_device(usbtype, new win_scsi_device(this, name, "")); } return 0; } // Scan for devices bool win_smart_interface::scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern /* = 0*/) { if (pattern) { set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); return false; } // Check for "[*,]pd" type bool pd = false; char type2[16+1] = ""; if (type) { int nc = -1; if (!strcmp(type, "pd")) { pd = true; type = 0; } else if (sscanf(type, "%16[^,],pd%n", type2, &nc) == 1 && nc == (int)strlen(type)) { pd = true; type = type2; } } // Set valid types bool ata, scsi, usb, csmi; if (!type) { ata = scsi = usb = csmi = true; } else { ata = scsi = usb = csmi = false; if (!strcmp(type, "ata")) ata = true; else if (!strcmp(type, "scsi")) scsi = true; else if (!strcmp(type, "usb")) usb = true; else if (!strcmp(type, "csmi")) csmi = true; else { set_err(EINVAL, "Invalid type '%s', valid arguments are: ata[,pd], scsi[,pd], usb[,pd], csmi, pd", type); return false; } } char name[20]; if (ata || scsi || usb) { // Scan up to 128 drives and 2 3ware controllers const int max_raid = 2; bool raid_seen[max_raid] = {false, false}; for (int i = 0; i < 128; i++) { if (pd) snprintf(name, sizeof(name), "/dev/pd%d", i); else if (i + 'a' <= 'z') snprintf(name, sizeof(name), "/dev/sd%c", i + 'a'); else snprintf(name, sizeof(name), "/dev/sd%c%c", i / ('z'-'a'+1) - 1 + 'a', i % ('z'-'a'+1) + 'a'); GETVERSIONINPARAMS_EX vers_ex; switch (get_phy_drive_type(i, (ata ? &vers_ex : 0))) { case DEV_ATA: // Driver supports SMART_GET_VERSION or STORAGE_QUERY_PROPERTY returned ATA/SATA if (!ata) continue; // Interpret RAID drive map if present if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) { // Skip if too many controllers or logical drive from this controller already seen if (!(vers_ex.wControllerId < max_raid && !raid_seen[vers_ex.wControllerId])) continue; raid_seen[vers_ex.wControllerId] = true; // Add physical drives int len = strlen(name); for (int pi = 0; pi < 32; pi++) { if (vers_ex.dwDeviceMapEx & (1L << pi)) { snprintf(name+len, sizeof(name)-1-len, ",%u", pi); devlist.push_back( new win_ata_device(this, name, "ata") ); } } } else { devlist.push_back( new win_ata_device(this, name, "ata") ); } break; case DEV_SCSI: // STORAGE_QUERY_PROPERTY returned SCSI/SAS/... if (!scsi) continue; devlist.push_back( new win_scsi_device(this, name, "scsi") ); break; case DEV_USB: // STORAGE_QUERY_PROPERTY returned USB if (!usb) continue; { // TODO: Use common function for this and autodetect_smart_device() // Get USB bridge ID unsigned short vendor_id = 0, product_id = 0; if (!get_usb_id(i, vendor_id, product_id)) continue; // Get type name for this ID const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id); if (!usbtype) continue; // Return SAT/USB device for this type ata_device * dev = get_sat_device(usbtype, new win_scsi_device(this, name, "")); if (!dev) continue; devlist.push_back(dev); } break; default: // Unknown type break; } } } if (csmi) { // Scan CSMI devices for (int i = 0; i <= 9; i++) { snprintf(name, sizeof(name)-1, "/dev/csmi%d,0", i); win_csmi_device test_dev(this, name, ""); if (!test_dev.open_scsi()) continue; CSMI_SAS_PHY_INFO phy_info; if (!test_dev.get_phy_info(phy_info)) continue; for (int pi = 0; pi < phy_info.bNumberOfPhys; pi++) { if (!test_dev.check_phy(phy_info, pi)) continue; snprintf(name, sizeof(name)-1, "/dev/csmi%d,%d", i, pi); devlist.push_back( new win_csmi_device(this, name, "ata") ); } } } return true; } // get examples for smartctl std::string win_smart_interface::get_app_examples(const char * appname) { if (strcmp(appname, "smartctl")) return ""; return "=================================================== SMARTCTL EXAMPLES =====\n\n" " smartctl -a /dev/sda (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/sda\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/sda (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/sda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a /dev/sda\n" " (Prints all information for disk on PhysicalDrive 0)\n" " smartctl -a /dev/pd3\n" " (Prints all information for disk on PhysicalDrive 3)\n" " smartctl -a /dev/tape1\n" " (Prints all information for SCSI tape on Tape 1)\n" " smartctl -A /dev/hdb,3\n" " (Prints Attributes for physical drive 3 on 3ware 9000 RAID)\n" " smartctl -A /dev/tw_cli/c0/p1\n" " (Prints Attributes for 3ware controller 0, port 1 using tw_cli)\n" " smartctl --all --device=areca,3/1 /dev/arcmsr0\n" " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n" " on 1st Areca RAID controller)\n" "\n" " ATA SMART access methods and ordering may be specified by modifiers\n" " following the device name: /dev/hdX:[saicm], where\n" " 's': SMART_* IOCTLs, 'a': IOCTL_ATA_PASS_THROUGH,\n" " 'i': IOCTL_IDE_PASS_THROUGH, 'f': IOCTL_STORAGE_*,\n" " 'm': IOCTL_SCSI_MINIPORT_*.\n" + strprintf( " The default on this system is /dev/sdX:%s\n", ata_get_def_options() ); } bool win_smart_interface::disable_system_auto_standby(bool disable) { if (disable) { SYSTEM_POWER_STATUS ps; if (!GetSystemPowerStatus(&ps)) return set_err(ENOSYS, "Unknown power status"); if (ps.ACLineStatus != 1) { SetThreadExecutionState(ES_CONTINUOUS); if (ps.ACLineStatus == 0) set_err(EIO, "AC offline"); else set_err(EIO, "Unknown AC line status"); return false; } } if (!SetThreadExecutionState(ES_CONTINUOUS | (disable ? ES_SYSTEM_REQUIRED : 0))) return set_err(ENOSYS); return true; } ///////////////////////////////////////////////////////////////////////////// // ATA Interface ///////////////////////////////////////////////////////////////////////////// #define SMART_CYL_LOW 0x4F #define SMART_CYL_HI 0xC2 static void print_ide_regs(const IDEREGS * r, int out) { pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, SN=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n", (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg, r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg); } static void print_ide_regs_io(const IDEREGS * ri, const IDEREGS * ro) { pout(" Input : "); print_ide_regs(ri, 0); if (ro) { pout(" Output: "); print_ide_regs(ro, 1); } } ///////////////////////////////////////////////////////////////////////////// // call SMART_GET_VERSION, return device map or -1 on error static int smart_get_version(HANDLE hdevice, GETVERSIONINPARAMS_EX * ata_version_ex = 0) { GETVERSIONINPARAMS vers; memset(&vers, 0, sizeof(vers)); const GETVERSIONINPARAMS_EX & vers_ex = (const GETVERSIONINPARAMS_EX &)vers; DWORD num_out; if (!DeviceIoControl(hdevice, SMART_GET_VERSION, NULL, 0, &vers, sizeof(vers), &num_out, NULL)) { if (ata_debugmode) pout(" SMART_GET_VERSION failed, Error=%u\n", (unsigned)GetLastError()); errno = ENOSYS; return -1; } assert(num_out == sizeof(GETVERSIONINPARAMS)); if (ata_debugmode > 1) { pout(" SMART_GET_VERSION suceeded, bytes returned: %u\n" " Vers = %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n", (unsigned)num_out, vers.bVersion, vers.bRevision, (unsigned)vers.fCapabilities, vers.bIDEDeviceMap); if (vers_ex.wIdentifier == SMART_VENDOR_3WARE) pout(" Identifier = %04x(3WARE), ControllerId=%u, DeviceMapEx = 0x%08x\n", vers_ex.wIdentifier, vers_ex.wControllerId, (unsigned)vers_ex.dwDeviceMapEx); } if (ata_version_ex) *ata_version_ex = vers_ex; // TODO: Check vers.fCapabilities here? return vers.bIDEDeviceMap; } // call SMART_* ioctl static int smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize, int port) { SENDCMDINPARAMS inpar; SENDCMDINPARAMS_EX & inpar_ex = (SENDCMDINPARAMS_EX &)inpar; unsigned char outbuf[sizeof(SENDCMDOUTPARAMS)-1 + 512]; const SENDCMDOUTPARAMS * outpar; DWORD code, num_out; unsigned int size_out; const char * name; memset(&inpar, 0, sizeof(inpar)); inpar.irDriveRegs = *regs; // Older drivers may require bits 5 and 7 set // ATA-3: bits shall be set, ATA-4 and later: bits are obsolete inpar.irDriveRegs.bDriveHeadReg |= 0xa0; // Drive number 0-3 was required on Win9x/ME only //inpar.irDriveRegs.bDriveHeadReg |= (drive & 1) << 4; //inpar.bDriveNumber = drive; if (port >= 0) { // Set RAID port inpar_ex.wIdentifier = SMART_VENDOR_3WARE; inpar_ex.bPortNumber = port; } if (datasize == 512) { code = SMART_RCV_DRIVE_DATA; name = "SMART_RCV_DRIVE_DATA"; inpar.cBufferSize = size_out = 512; } else if (datasize == 0) { code = SMART_SEND_DRIVE_COMMAND; name = "SMART_SEND_DRIVE_COMMAND"; if (regs->bFeaturesReg == ATA_SMART_STATUS) size_out = sizeof(IDEREGS); // ioctl returns new IDEREGS as data // Note: cBufferSize must be 0 on Win9x else size_out = 0; } else { errno = EINVAL; return -1; } memset(&outbuf, 0, sizeof(outbuf)); if (!DeviceIoControl(hdevice, code, &inpar, sizeof(SENDCMDINPARAMS)-1, outbuf, sizeof(SENDCMDOUTPARAMS)-1 + size_out, &num_out, NULL)) { // CAUTION: DO NOT change "regs" Parameter in this case, see win_ata_device::ata_pass_through() long err = GetLastError(); if (ata_debugmode && (err != ERROR_INVALID_PARAMETER || ata_debugmode > 1)) { pout(" %s failed, Error=%ld\n", name, err); print_ide_regs_io(regs, NULL); } errno = ( err == ERROR_INVALID_FUNCTION/*9x*/ || err == ERROR_INVALID_PARAMETER/*NT/2K/XP*/ || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // NOTE: On Win9x, inpar.irDriveRegs now contains the returned regs outpar = (const SENDCMDOUTPARAMS *)outbuf; if (outpar->DriverStatus.bDriverError) { if (ata_debugmode) { pout(" %s failed, DriverError=0x%02x, IDEError=0x%02x\n", name, outpar->DriverStatus.bDriverError, outpar->DriverStatus.bIDEError); print_ide_regs_io(regs, NULL); } errno = (!outpar->DriverStatus.bIDEError ? ENOSYS : EIO); return -1; } if (ata_debugmode > 1) { pout(" %s suceeded, bytes returned: %u (buffer %u)\n", name, (unsigned)num_out, (unsigned)outpar->cBufferSize); print_ide_regs_io(regs, (regs->bFeaturesReg == ATA_SMART_STATUS ? (const IDEREGS *)(outpar->bBuffer) : NULL)); } if (datasize) memcpy(data, outpar->bBuffer, 512); else if (regs->bFeaturesReg == ATA_SMART_STATUS) { if (nonempty(outpar->bBuffer, sizeof(IDEREGS))) memcpy(regs, outpar->bBuffer, sizeof(IDEREGS)); else { // Workaround for driver not returning regs if (ata_debugmode) pout(" WARNING: driver does not return ATA registers in output buffer!\n"); *regs = inpar.irDriveRegs; } } return 0; } ///////////////////////////////////////////////////////////////////////////// // IDE PASS THROUGH (2000, XP, undocumented) // // Based on WinATA.cpp, 2002 c't/Matthias Withopf // ftp://ftp.heise.de/pub/ct/listings/0207-218.zip static int ide_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, unsigned datasize) { if (datasize > 512) { errno = EINVAL; return -1; } unsigned int size = sizeof(ATA_PASS_THROUGH)-1 + datasize; ATA_PASS_THROUGH * buf = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); DWORD num_out; const unsigned char magic = 0xcf; if (!buf) { errno = ENOMEM; return -1; } buf->IdeReg = *regs; buf->DataBufferSize = datasize; if (datasize) buf->DataBuffer[0] = magic; if (!DeviceIoControl(hdevice, IOCTL_IDE_PASS_THROUGH, buf, size, buf, size, &num_out, NULL)) { long err = GetLastError(); if (ata_debugmode) { pout(" IOCTL_IDE_PASS_THROUGH failed, Error=%ld\n", err); print_ide_regs_io(regs, NULL); } VirtualFree(buf, 0, MEM_RELEASE); errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Check ATA status if (buf->IdeReg.bCommandReg/*Status*/ & 0x01) { if (ata_debugmode) { pout(" IOCTL_IDE_PASS_THROUGH command failed:\n"); print_ide_regs_io(regs, &buf->IdeReg); } VirtualFree(buf, 0, MEM_RELEASE); errno = EIO; return -1; } // Check and copy data if (datasize) { if ( num_out != size || (buf->DataBuffer[0] == magic && !nonempty(buf->DataBuffer+1, datasize-1))) { if (ata_debugmode) { pout(" IOCTL_IDE_PASS_THROUGH output data missing (%u, %u)\n", (unsigned)num_out, (unsigned)buf->DataBufferSize); print_ide_regs_io(regs, &buf->IdeReg); } VirtualFree(buf, 0, MEM_RELEASE); errno = EIO; return -1; } memcpy(data, buf->DataBuffer, datasize); } if (ata_debugmode > 1) { pout(" IOCTL_IDE_PASS_THROUGH suceeded, bytes returned: %u (buffer %u)\n", (unsigned)num_out, (unsigned)buf->DataBufferSize); print_ide_regs_io(regs, &buf->IdeReg); } *regs = buf->IdeReg; // Caution: VirtualFree() fails if parameter "dwSize" is nonzero VirtualFree(buf, 0, MEM_RELEASE); return 0; } ///////////////////////////////////////////////////////////////////////////// // ATA PASS THROUGH (Win2003, XP SP2) // Warning: // IOCTL_ATA_PASS_THROUGH[_DIRECT] can only handle one interrupt/DRQ data // transfer per command. Therefore, multi-sector transfers are only supported // for the READ/WRITE MULTIPLE [EXT] commands. Other commands like READ/WRITE SECTORS // or READ/WRITE LOG EXT work only with single sector transfers. // The latter are supported on Vista (only) through new ATA_FLAGS_NO_MULTIPLE. // See: // http://social.msdn.microsoft.com/Forums/en-US/storageplatformata/thread/eb408507-f221-455b-9bbb-d1069b29c4da static int ata_pass_through_ioctl(HANDLE hdevice, IDEREGS * regs, IDEREGS * prev_regs, char * data, int datasize) { const int max_sectors = 32; // TODO: Allocate dynamic buffer typedef struct { ATA_PASS_THROUGH_EX apt; ULONG Filler; UCHAR ucDataBuf[max_sectors * 512]; } ATA_PASS_THROUGH_EX_WITH_BUFFERS; const unsigned char magic = 0xcf; ATA_PASS_THROUGH_EX_WITH_BUFFERS ab; memset(&ab, 0, sizeof(ab)); ab.apt.Length = sizeof(ATA_PASS_THROUGH_EX); //ab.apt.PathId = 0; //ab.apt.TargetId = 0; //ab.apt.Lun = 0; ab.apt.TimeOutValue = 10; unsigned size = offsetof(ATA_PASS_THROUGH_EX_WITH_BUFFERS, ucDataBuf); ab.apt.DataBufferOffset = size; if (datasize > 0) { if (datasize > (int)sizeof(ab.ucDataBuf)) { errno = EINVAL; return -1; } ab.apt.AtaFlags = ATA_FLAGS_DATA_IN; ab.apt.DataTransferLength = datasize; size += datasize; ab.ucDataBuf[0] = magic; } else if (datasize < 0) { if (-datasize > (int)sizeof(ab.ucDataBuf)) { errno = EINVAL; return -1; } ab.apt.AtaFlags = ATA_FLAGS_DATA_OUT; ab.apt.DataTransferLength = -datasize; size += -datasize; memcpy(ab.ucDataBuf, data, -datasize); } else { assert(ab.apt.AtaFlags == 0); assert(ab.apt.DataTransferLength == 0); } assert(sizeof(ab.apt.CurrentTaskFile) == sizeof(IDEREGS)); IDEREGS * ctfregs = (IDEREGS *)ab.apt.CurrentTaskFile; IDEREGS * ptfregs = (IDEREGS *)ab.apt.PreviousTaskFile; *ctfregs = *regs; if (prev_regs) { *ptfregs = *prev_regs; ab.apt.AtaFlags |= ATA_FLAGS_48BIT_COMMAND; } DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_ATA_PASS_THROUGH, &ab, size, &ab, size, &num_out, NULL)) { long err = GetLastError(); if (ata_debugmode) { pout(" IOCTL_ATA_PASS_THROUGH failed, Error=%ld\n", err); print_ide_regs_io(regs, NULL); } errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Check ATA status if (ctfregs->bCommandReg/*Status*/ & (0x01/*Err*/|0x08/*DRQ*/)) { if (ata_debugmode) { pout(" IOCTL_ATA_PASS_THROUGH command failed:\n"); print_ide_regs_io(regs, ctfregs); } errno = EIO; return -1; } // Check and copy data if (datasize > 0) { if ( num_out != size || (ab.ucDataBuf[0] == magic && !nonempty(ab.ucDataBuf+1, datasize-1))) { if (ata_debugmode) { pout(" IOCTL_ATA_PASS_THROUGH output data missing (%u)\n", (unsigned)num_out); print_ide_regs_io(regs, ctfregs); } errno = EIO; return -1; } memcpy(data, ab.ucDataBuf, datasize); } if (ata_debugmode > 1) { pout(" IOCTL_ATA_PASS_THROUGH suceeded, bytes returned: %u\n", (unsigned)num_out); print_ide_regs_io(regs, ctfregs); } *regs = *ctfregs; if (prev_regs) *prev_regs = *ptfregs; return 0; } ///////////////////////////////////////////////////////////////////////////// // SMART IOCTL via SCSI MINIPORT ioctl // This function is handled by ATAPI port driver (atapi.sys) or by SCSI // miniport driver (via SCSI port driver scsiport.sys). // It can be used to skip the missing or broken handling of some SMART // command codes (e.g. READ_LOG) in the disk class driver (disk.sys) static int ata_via_scsi_miniport_smart_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize) { // Select code DWORD code = 0; const char * name = 0; if (regs->bCommandReg == ATA_IDENTIFY_DEVICE) { code = IOCTL_SCSI_MINIPORT_IDENTIFY; name = "IDENTIFY"; } else if (regs->bCommandReg == ATA_SMART_CMD) switch (regs->bFeaturesReg) { case ATA_SMART_READ_VALUES: code = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS; name = "READ_SMART_ATTRIBS"; break; case ATA_SMART_READ_THRESHOLDS: code = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS; name = "READ_SMART_THRESHOLDS"; break; case ATA_SMART_ENABLE: code = IOCTL_SCSI_MINIPORT_ENABLE_SMART; name = "ENABLE_SMART"; break; case ATA_SMART_DISABLE: code = IOCTL_SCSI_MINIPORT_DISABLE_SMART; name = "DISABLE_SMART"; break; case ATA_SMART_STATUS: code = IOCTL_SCSI_MINIPORT_RETURN_STATUS; name = "RETURN_STATUS"; break; case ATA_SMART_AUTOSAVE: code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE; name = "ENABLE_DISABLE_AUTOSAVE"; break; //case ATA_SMART_SAVE: // obsolete since ATA-6, not used by smartmontools // code = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES; name = "SAVE_ATTRIBUTE_VALUES"; break; case ATA_SMART_IMMEDIATE_OFFLINE: code = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS; name = "EXECUTE_OFFLINE_DIAGS"; break; case ATA_SMART_AUTO_OFFLINE: code = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTO_OFFLINE; name = "ENABLE_DISABLE_AUTO_OFFLINE"; break; case ATA_SMART_READ_LOG_SECTOR: code = IOCTL_SCSI_MINIPORT_READ_SMART_LOG; name = "READ_SMART_LOG"; break; case ATA_SMART_WRITE_LOG_SECTOR: code = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG; name = "WRITE_SMART_LOG"; break; } if (!code) { errno = ENOSYS; return -1; } // Set SRB struct { SRB_IO_CONTROL srbc; union { SENDCMDINPARAMS in; SENDCMDOUTPARAMS out; } params; char space[512-1]; } sb; ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(SENDCMDINPARAMS)-1+512); memset(&sb, 0, sizeof(sb)); unsigned size; if (datasize > 0) { if (datasize > (int)sizeof(sb.space)+1) { errno = EINVAL; return -1; } size = datasize; } else if (datasize < 0) { if (-datasize > (int)sizeof(sb.space)+1) { errno = EINVAL; return -1; } size = -datasize; memcpy(sb.params.in.bBuffer, data, size); } else if (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS) size = sizeof(IDEREGS); else size = 0; sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL); memcpy(sb.srbc.Signature, "SCSIDISK", 8); // atapi.sys sb.srbc.Timeout = 60; // seconds sb.srbc.ControlCode = code; //sb.srbc.ReturnCode = 0; sb.srbc.Length = sizeof(SENDCMDINPARAMS)-1 + size; sb.params.in.irDriveRegs = *regs; sb.params.in.cBufferSize = size; // Call miniport ioctl size += sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)-1; DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, &sb, size, &sb, size, &num_out, NULL)) { long err = GetLastError(); if (ata_debugmode) { pout(" IOCTL_SCSI_MINIPORT_%s failed, Error=%ld\n", name, err); print_ide_regs_io(regs, NULL); } errno = (err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED ? ENOSYS : EIO); return -1; } // Check result if (sb.srbc.ReturnCode) { if (ata_debugmode) { pout(" IOCTL_SCSI_MINIPORT_%s failed, ReturnCode=0x%08x\n", name, (unsigned)sb.srbc.ReturnCode); print_ide_regs_io(regs, NULL); } errno = EIO; return -1; } if (sb.params.out.DriverStatus.bDriverError) { if (ata_debugmode) { pout(" IOCTL_SCSI_MINIPORT_%s failed, DriverError=0x%02x, IDEError=0x%02x\n", name, sb.params.out.DriverStatus.bDriverError, sb.params.out.DriverStatus.bIDEError); print_ide_regs_io(regs, NULL); } errno = (!sb.params.out.DriverStatus.bIDEError ? ENOSYS : EIO); return -1; } if (ata_debugmode > 1) { pout(" IOCTL_SCSI_MINIPORT_%s suceeded, bytes returned: %u (buffer %u)\n", name, (unsigned)num_out, (unsigned)sb.params.out.cBufferSize); print_ide_regs_io(regs, (code == IOCTL_SCSI_MINIPORT_RETURN_STATUS ? (const IDEREGS *)(sb.params.out.bBuffer) : 0)); } if (datasize > 0) memcpy(data, sb.params.out.bBuffer, datasize); else if (datasize == 0 && code == IOCTL_SCSI_MINIPORT_RETURN_STATUS) memcpy(regs, sb.params.out.bBuffer, sizeof(IDEREGS)); return 0; } ///////////////////////////////////////////////////////////////////////////// // ATA PASS THROUGH via 3ware specific SCSI MINIPORT ioctl static int ata_via_3ware_miniport_ioctl(HANDLE hdevice, IDEREGS * regs, char * data, int datasize, int port) { struct { SRB_IO_CONTROL srbc; IDEREGS regs; UCHAR buffer[512]; } sb; ASSERT_SIZEOF(sb, sizeof(SRB_IO_CONTROL)+sizeof(IDEREGS)+512); if (!(0 <= datasize && datasize <= (int)sizeof(sb.buffer) && port >= 0)) { errno = EINVAL; return -1; } memset(&sb, 0, sizeof(sb)); strncpy((char *)sb.srbc.Signature, "<3ware>", sizeof(sb.srbc.Signature)); sb.srbc.HeaderLength = sizeof(SRB_IO_CONTROL); sb.srbc.Timeout = 60; // seconds sb.srbc.ControlCode = 0xA0000000; sb.srbc.ReturnCode = 0; sb.srbc.Length = sizeof(IDEREGS) + (datasize > 0 ? datasize : 1); sb.regs = *regs; sb.regs.bReserved = port; DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, &sb, sizeof(sb), &sb, sizeof(sb), &num_out, NULL)) { long err = GetLastError(); if (ata_debugmode) { pout(" ATA via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err); print_ide_regs_io(regs, NULL); } errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); return -1; } if (sb.srbc.ReturnCode) { if (ata_debugmode) { pout(" ATA via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)sb.srbc.ReturnCode); print_ide_regs_io(regs, NULL); } errno = EIO; return -1; } // Copy data if (datasize > 0) memcpy(data, sb.buffer, datasize); if (ata_debugmode > 1) { pout(" ATA via IOCTL_SCSI_MINIPORT suceeded, bytes returned: %u\n", (unsigned)num_out); print_ide_regs_io(regs, &sb.regs); } *regs = sb.regs; return 0; } ///////////////////////////////////////////////////////////////////////////// // 3ware specific call to update the devicemap returned by SMART_GET_VERSION. // 3DM/CLI "Rescan Controller" function does not to always update it. static int update_3ware_devicemap_ioctl(HANDLE hdevice) { SRB_IO_CONTROL srbc; memset(&srbc, 0, sizeof(srbc)); strncpy((char *)srbc.Signature, "<3ware>", sizeof(srbc.Signature)); srbc.HeaderLength = sizeof(SRB_IO_CONTROL); srbc.Timeout = 60; // seconds srbc.ControlCode = 0xCC010014; srbc.ReturnCode = 0; srbc.Length = 0; DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_SCSI_MINIPORT, &srbc, sizeof(srbc), &srbc, sizeof(srbc), &num_out, NULL)) { long err = GetLastError(); if (ata_debugmode) pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, Error=%ld\n", err); errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); return -1; } if (srbc.ReturnCode) { if (ata_debugmode) pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT failed, ReturnCode=0x%08x\n", (unsigned)srbc.ReturnCode); errno = EIO; return -1; } if (ata_debugmode > 1) pout(" UPDATE DEVICEMAP via IOCTL_SCSI_MINIPORT suceeded\n"); return 0; } ///////////////////////////////////////////////////////////////////////////// // Routines for pseudo device /dev/tw_cli/* // Parses output of 3ware "tw_cli /cx/py show all" or 3DM SMART data window // Get clipboard data static int get_clipboard(char * data, int datasize) { if (!OpenClipboard(NULL)) return -1; HANDLE h = GetClipboardData(CF_TEXT); if (!h) { CloseClipboard(); return 0; } const void * p = GlobalLock(h); int n = GlobalSize(h); if (n > datasize) n = datasize; memcpy(data, p, n); GlobalFree(h); CloseClipboard(); return n; } // Run a command, write stdout to dataout // TODO: Combine with daemon_win32.cpp:daemon_spawn() static int run_cmd(const char * cmd, char * dataout, int outsize) { // Create stdout pipe SECURITY_ATTRIBUTES sa = {sizeof(sa), 0, TRUE}; HANDLE pipe_out_w, h; if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) return -1; HANDLE self = GetCurrentProcess(); HANDLE pipe_out_r; if (!DuplicateHandle(self, h, self, &pipe_out_r, GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) { CloseHandle(pipe_out_w); return -1; } HANDLE pipe_err_w; if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w, 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) { CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); return -1; } // Create process STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = INVALID_HANDLE_VALUE; si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w; si.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION pi; if (!CreateProcess( NULL, const_cast<char *>(cmd), NULL, NULL, TRUE/*inherit*/, CREATE_NO_WINDOW/*do not create a new console window*/, NULL, NULL, &si, &pi)) { CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); return -1; } CloseHandle(pi.hThread); CloseHandle(pipe_err_w); CloseHandle(pipe_out_w); // Copy stdout to output buffer int i = 0; while (i < outsize) { DWORD num_read; if (!ReadFile(pipe_out_r, dataout+i, outsize-i, &num_read, NULL) || num_read == 0) break; i += num_read; } CloseHandle(pipe_out_r); // Wait for process WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); return i; } static const char * findstr(const char * str, const char * sub) { const char * s = strstr(str, sub); return (s ? s+strlen(sub) : ""); } static void copy_swapped(unsigned char * dest, const char * src, int destsize) { int srclen = strcspn(src, "\r\n"); int i; for (i = 0; i < destsize-1 && i < srclen-1; i+=2) { dest[i] = src[i+1]; dest[i+1] = src[i]; } if (i < destsize-1 && i < srclen) dest[i+1] = src[i]; } // TODO: This is OS independent win_tw_cli_device::win_tw_cli_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "tw_cli", req_type), m_ident_valid(false), m_smart_valid(false) { memset(&m_ident_buf, 0, sizeof(m_ident_buf)); memset(&m_smart_buf, 0, sizeof(m_smart_buf)); } bool win_tw_cli_device::is_open() const { return (m_ident_valid || m_smart_valid); } bool win_tw_cli_device::open() { m_ident_valid = m_smart_valid = false; const char * name = skipdev(get_dev_name()); // Read tw_cli or 3DM browser output into buffer char buffer[4096]; int size = -1, n1 = -1, n2 = -1; if (!strcmp(name, "tw_cli/clip")) { // read clipboard size = get_clipboard(buffer, sizeof(buffer)); } else if (!strcmp(name, "tw_cli/stdin")) { // read stdin size = fread(buffer, 1, sizeof(buffer), stdin); } else if (sscanf(name, "tw_cli/%nc%*u/p%*u%n", &n1, &n2) >= 0 && n2 == (int)strlen(name)) { // tw_cli/cx/py => read output from "tw_cli /cx/py show all" char cmd[100]; snprintf(cmd, sizeof(cmd), "tw_cli /%s show all", name+n1); if (ata_debugmode > 1) pout("%s: Run: \"%s\"\n", name, cmd); size = run_cmd(cmd, buffer, sizeof(buffer)); } else { return set_err(EINVAL); } if (ata_debugmode > 1) pout("%s: Read %d bytes\n", name, size); if (size <= 0) return set_err(ENOENT); if (size >= (int)sizeof(buffer)) return set_err(EIO); buffer[size] = 0; if (ata_debugmode > 1) pout("[\n%.100s%s\n]\n", buffer, (size>100?"...":"")); // Fake identify sector ASSERT_SIZEOF(ata_identify_device, 512); ata_identify_device * id = &m_ident_buf; memset(id, 0, sizeof(*id)); copy_swapped(id->model , findstr(buffer, " Model = " ), sizeof(id->model)); copy_swapped(id->fw_rev , findstr(buffer, " Firmware Version = "), sizeof(id->fw_rev)); copy_swapped(id->serial_no, findstr(buffer, " Serial = " ), sizeof(id->serial_no)); unsigned long nblocks = 0; // "Capacity = N.N GB (N Blocks)" sscanf(findstr(buffer, "Capacity = "), "%*[^(\r\n](%lu", &nblocks); if (nblocks) { id->words047_079[49-47] = 0x0200; // size valid id->words047_079[60-47] = (unsigned short)(nblocks ); // secs_16 id->words047_079[61-47] = (unsigned short)(nblocks>>16); // secs_32 } id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid // Parse smart data hex dump const char * s = findstr(buffer, "Drive Smart Data:"); if (!*s) s = findstr(buffer, "Drive SMART Data:"); // tw_cli from 9.5.x if (!*s) { s = findstr(buffer, "S.M.A.R.T. (Controller"); // from 3DM browser window if (*s) { const char * s1 = findstr(s, "<td class"); // html version if (*s1) s = s1; s += strcspn(s, "\r\n"); } else s = buffer; // try raw hex dump without header } unsigned char * sd = (unsigned char *)&m_smart_buf; int i = 0; for (;;) { unsigned x = ~0; int n = -1; if (!(sscanf(s, "%x %n", &x, &n) == 1 && !(x & ~0xff))) break; sd[i] = (unsigned char)x; if (!(++i < 512 && n > 0)) break; s += n; if (*s == '<') // "<br>" s += strcspn(s, "\r\n"); } if (i < 512) { if (!id->model[1]) { // No useful data found char * err = strstr(buffer, "Error:"); if (!err) err = strstr(buffer, "error :"); if (err && (err = strchr(err, ':'))) { // Show tw_cli error message err++; err[strcspn(err, "\r\n")] = 0; return set_err(EIO, "%s", err); } return set_err(EIO); } sd = 0; } m_ident_valid = true; m_smart_valid = !!sd; return true; } bool win_tw_cli_device::close() { m_ident_valid = m_smart_valid = false; return true; } int win_tw_cli_device::ata_command_interface(smart_command_set command, int /*select*/, char * data) { switch (command) { case IDENTIFY: if (!m_ident_valid) break; memcpy(data, &m_ident_buf, 512); return 0; case READ_VALUES: if (!m_smart_valid) break; memcpy(data, &m_smart_buf, 512); return 0; case ENABLE: case STATUS: case STATUS_CHECK: // Fake "good" SMART status return 0; default: break; } // Arrive here for all unsupported commands set_err(ENOSYS); return -1; } ///////////////////////////////////////////////////////////////////////////// // IOCTL_STORAGE_QUERY_PROPERTY union STORAGE_DEVICE_DESCRIPTOR_DATA { STORAGE_DEVICE_DESCRIPTOR desc; char raw[256]; }; // Get STORAGE_DEVICE_DESCRIPTOR_DATA for device. // (This works without admin rights) static int storage_query_property_ioctl(HANDLE hdevice, STORAGE_DEVICE_DESCRIPTOR_DATA * data) { STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} }; memset(data, 0, sizeof(*data)); DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) { if (ata_debugmode > 1 || scsi_debugmode > 1) pout(" IOCTL_STORAGE_QUERY_PROPERTY failed, Error=%u\n", (unsigned)GetLastError()); errno = ENOSYS; return -1; } if (ata_debugmode > 1 || scsi_debugmode > 1) { pout(" IOCTL_STORAGE_QUERY_PROPERTY returns:\n" " Vendor: \"%s\"\n" " Product: \"%s\"\n" " Revision: \"%s\"\n" " Removable: %s\n" " BusType: 0x%02x\n", (data->desc.VendorIdOffset ? data->raw+data->desc.VendorIdOffset : "(null)"), (data->desc.ProductIdOffset ? data->raw+data->desc.ProductIdOffset : "(null)"), (data->desc.ProductRevisionOffset ? data->raw+data->desc.ProductRevisionOffset : "(null)"), (data->desc.RemovableMedia? "Yes":"No"), data->desc.BusType ); } return 0; } ///////////////////////////////////////////////////////////////////////////// // IOCTL_STORAGE_PREDICT_FAILURE // Call IOCTL_STORAGE_PREDICT_FAILURE, return PredictFailure value // or -1 on error, opionally return VendorSpecific data. // (This works without admin rights) static int storage_predict_failure_ioctl(HANDLE hdevice, char * data = 0) { STORAGE_PREDICT_FAILURE pred; memset(&pred, 0, sizeof(pred)); DWORD num_out; if (!DeviceIoControl(hdevice, IOCTL_STORAGE_PREDICT_FAILURE, 0, 0, &pred, sizeof(pred), &num_out, NULL)) { if (ata_debugmode > 1) pout(" IOCTL_STORAGE_PREDICT_FAILURE failed, Error=%u\n", (unsigned)GetLastError()); errno = ENOSYS; return -1; } if (ata_debugmode > 1) { pout(" IOCTL_STORAGE_PREDICT_FAILURE returns:\n" " PredictFailure: 0x%08x\n" " VendorSpecific: 0x%02x,0x%02x,0x%02x,...,0x%02x\n", (unsigned)pred.PredictFailure, pred.VendorSpecific[0], pred.VendorSpecific[1], pred.VendorSpecific[2], pred.VendorSpecific[sizeof(pred.VendorSpecific)-1] ); } if (data) memcpy(data, pred.VendorSpecific, sizeof(pred.VendorSpecific)); return (!pred.PredictFailure ? 0 : 1); } ///////////////////////////////////////////////////////////////////////////// // Return true if Intel ICHxR RAID volume static bool is_intel_raid_volume(const STORAGE_DEVICE_DESCRIPTOR_DATA * data) { if (!(data->desc.VendorIdOffset && data->desc.ProductIdOffset)) return false; const char * vendor = data->raw + data->desc.VendorIdOffset; if (!(!strnicmp(vendor, "Intel", 5) && strspn(vendor+5, " ") == strlen(vendor+5))) return false; if (strnicmp(data->raw + data->desc.ProductIdOffset, "Raid ", 5)) return false; return true; } // get DEV_* for open handle static win_dev_type get_controller_type(HANDLE hdevice, bool admin, GETVERSIONINPARAMS_EX * ata_version_ex) { // Get BusType from device descriptor STORAGE_DEVICE_DESCRIPTOR_DATA data; if (storage_query_property_ioctl(hdevice, &data)) return DEV_UNKNOWN; // Newer BusType* values are missing in older includes switch ((int)data.desc.BusType) { case BusTypeAta: case 0x0b: // BusTypeSata if (ata_version_ex) memset(ata_version_ex, 0, sizeof(*ata_version_ex)); return DEV_ATA; case BusTypeScsi: case BusTypeRAID: // Intel ICHxR RAID volume: reports SMART_GET_VERSION but does not support SMART_* if (is_intel_raid_volume(&data)) return DEV_SCSI; // LSI/3ware RAID volume: supports SMART_* if (admin && smart_get_version(hdevice, ata_version_ex) >= 0) return DEV_ATA; return DEV_SCSI; case 0x09: // BusTypeiScsi case 0x0a: // BusTypeSas return DEV_SCSI; case BusTypeUsb: return DEV_USB; default: return DEV_UNKNOWN; } /*NOTREACHED*/ } // get DEV_* for device path static win_dev_type get_controller_type(const char * path, GETVERSIONINPARAMS_EX * ata_version_ex = 0) { bool admin = true; HANDLE h = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) { admin = false; h = CreateFileA(path, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) return DEV_UNKNOWN; } if (ata_debugmode > 1 || scsi_debugmode > 1) pout(" %s: successfully opened%s\n", path, (!admin ? " (without admin rights)" :"")); win_dev_type type = get_controller_type(h, admin, ata_version_ex); CloseHandle(h); return type; } // get DEV_* for physical drive number static win_dev_type get_phy_drive_type(int drive, GETVERSIONINPARAMS_EX * ata_version_ex) { char path[30]; snprintf(path, sizeof(path)-1, "\\\\.\\PhysicalDrive%d", drive); return get_controller_type(path, ata_version_ex); } static win_dev_type get_phy_drive_type(int drive) { return get_phy_drive_type(drive, 0); } // get DEV_* for logical drive number static win_dev_type get_log_drive_type(int drive) { char path[30]; snprintf(path, sizeof(path)-1, "\\\\.\\%c:", 'A'+drive); return get_controller_type(path); } // Build IDENTIFY information from STORAGE_DEVICE_DESCRIPTOR static int get_identify_from_device_property(HANDLE hdevice, ata_identify_device * id) { STORAGE_DEVICE_DESCRIPTOR_DATA data; if (storage_query_property_ioctl(hdevice, &data)) return -1; memset(id, 0, sizeof(*id)); // Some drivers split ATA model string into VendorId and ProductId, // others return it as ProductId only. char model[sizeof(id->model) + 1] = ""; unsigned i = 0; if (data.desc.VendorIdOffset) { for ( ;i < sizeof(model)-1 && data.raw[data.desc.VendorIdOffset+i]; i++) model[i] = data.raw[data.desc.VendorIdOffset+i]; } if (data.desc.ProductIdOffset) { while (i > 1 && model[i-2] == ' ') // Keep last blank from VendorId i--; // Ignore VendorId "ATA" if (i <= 4 && !strncmp(model, "ATA", 3) && (i == 3 || model[3] == ' ')) i = 0; for (unsigned j = 0; i < sizeof(model)-1 && data.raw[data.desc.ProductIdOffset+j]; i++, j++) model[i] = data.raw[data.desc.ProductIdOffset+j]; } while (i > 0 && model[i-1] == ' ') i--; model[i] = 0; copy_swapped(id->model, model, sizeof(id->model)); if (data.desc.ProductRevisionOffset) copy_swapped(id->fw_rev, data.raw+data.desc.ProductRevisionOffset, sizeof(id->fw_rev)); id->command_set_1 = 0x0001; id->command_set_2 = 0x4000; // SMART supported, words 82,83 valid id->cfs_enable_1 = 0x0001; id->csf_default = 0x4000; // SMART enabled, words 85,87 valid return 0; } // Get Serial Number in IDENTIFY from WMI static bool get_serial_from_wmi(int drive, ata_identify_device * id) { bool debug = (ata_debugmode > 1); wbem_services ws; if (!ws.connect()) { if (debug) pout("WMI connect failed\n"); return false; } wbem_object wo; if (!ws.query1(wo, "SELECT Model,SerialNumber FROM Win32_DiskDrive WHERE " "DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive)) return false; std::string serial = wo.get_str("SerialNumber"); if (debug) pout(" WMI:PhysicalDrive%d: \"%s\", S/N:\"%s\"\n", drive, wo.get_str("Model").c_str(), serial.c_str()); copy_swapped(id->serial_no, serial.c_str(), sizeof(id->serial_no)); return true; } ///////////////////////////////////////////////////////////////////////////// // USB ID detection using WMI // Get USB ID for a physical drive number static bool get_usb_id(int drive, unsigned short & vendor_id, unsigned short & product_id) { bool debug = (scsi_debugmode > 1); wbem_services ws; if (!ws.connect()) { if (debug) pout("WMI connect failed\n"); return false; } // Get device name wbem_object wo; if (!ws.query1(wo, "SELECT Model FROM Win32_DiskDrive WHERE DeviceID=\"\\\\\\\\.\\\\PHYSICALDRIVE%d\"", drive)) return false; std::string name = wo.get_str("Model"); if (debug) pout("PhysicalDrive%d, \"%s\":\n", drive, name.c_str()); // Get USB_CONTROLLER -> DEVICE associations wbem_enumerator we; if (!ws.query(we, "SELECT Antecedent,Dependent FROM Win32_USBControllerDevice")) return false; unsigned short usb_venid = 0, prev_usb_venid = 0; unsigned short usb_proid = 0, prev_usb_proid = 0; std::string prev_usb_ant; std::string prev_ant, ant, dep; const regular_expression regex("^.*PnPEntity\\.DeviceID=\"([^\"]*)\"", REG_EXTENDED); while (we.next(wo)) { prev_ant = ant; // Find next 'USB_CONTROLLER, DEVICE' pair ant = wo.get_str("Antecedent"); dep = wo.get_str("Dependent"); if (debug && ant != prev_ant) pout(" %s:\n", ant.c_str()); // Extract DeviceID regmatch_t match[2]; if (!(regex.execute(dep.c_str(), 2, match) && match[1].rm_so >= 0)) { if (debug) pout(" | (\"%s\")\n", dep.c_str()); continue; } std::string devid(dep.c_str()+match[1].rm_so, match[1].rm_eo-match[1].rm_so); if (str_starts_with(devid, "USB\\\\VID_")) { // USB bridge entry, save CONTROLLER, ID int nc = -1; if (!(sscanf(devid.c_str(), "USB\\\\VID_%4hx&PID_%4hx%n", &prev_usb_venid, &prev_usb_proid, &nc) == 2 && nc == 9+4+5+4)) { prev_usb_venid = prev_usb_proid = 0; } prev_usb_ant = ant; if (debug) pout(" +-> \"%s\" [0x%04x:0x%04x]\n", devid.c_str(), prev_usb_venid, prev_usb_proid); continue; } else if (str_starts_with(devid, "USBSTOR\\\\")) { // USBSTOR device found if (debug) pout(" +--> \"%s\"\n", devid.c_str()); // Retrieve name wbem_object wo2; if (!ws.query1(wo2, "SELECT Name FROM Win32_PnPEntity WHERE DeviceID=\"%s\"", devid.c_str())) continue; std::string name2 = wo2.get_str("Name"); // Continue if not name of physical disk drive if (name2 != name) { if (debug) pout(" +---> (\"%s\")\n", name2.c_str()); continue; } // Fail if previous USB bridge is associated to other controller or ID is unknown if (!(ant == prev_usb_ant && prev_usb_venid)) { if (debug) pout(" +---> \"%s\" (Error: No USB bridge found)\n", name2.c_str()); return false; } // Handle multiple devices with same name if (usb_venid) { // Fail if multiple devices with same name have different USB bridge types if (!(usb_venid == prev_usb_venid && usb_proid == prev_usb_proid)) { if (debug) pout(" +---> \"%s\" (Error: More than one USB ID found)\n", name2.c_str()); return false; } } // Found usb_venid = prev_usb_venid; usb_proid = prev_usb_proid; if (debug) pout(" +===> \"%s\" [0x%04x:0x%04x]\n", name2.c_str(), usb_venid, usb_proid); // Continue to check for duplicate names ... } else { if (debug) pout(" | \"%s\"\n", devid.c_str()); } } if (!usb_venid) return false; vendor_id = usb_venid; product_id = usb_proid; return true; } ///////////////////////////////////////////////////////////////////////////// // Call GetDevicePowerState() // returns: 1=active, 0=standby, -1=error // (This would also work for SCSI drives) static int get_device_power_state(HANDLE hdevice) { BOOL state = TRUE; if (!GetDevicePowerState(hdevice, &state)) { long err = GetLastError(); if (ata_debugmode) pout(" GetDevicePowerState() failed, Error=%ld\n", err); errno = (err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO); // TODO: This may not work as expected on transient errors, // because smartd interprets -1 as SLEEP mode regardless of errno. return -1; } if (ata_debugmode > 1) pout(" GetDevicePowerState() succeeded, state=%d\n", state); return state; } ///////////////////////////////////////////////////////////////////////////// // Get default ATA device options static const char * ata_get_def_options() { return "pasifm"; // GetDevicePowerState(), ATA_, SMART_*, IDE_PASS_THROUGH, // STORAGE_*, SCSI_MINIPORT_* } // Common routines for devices with HANDLEs win_smart_device::~win_smart_device() throw() { if (m_fh != INVALID_HANDLE_VALUE) ::CloseHandle(m_fh); } bool win_smart_device::is_open() const { return (m_fh != INVALID_HANDLE_VALUE); } bool win_smart_device::close() { if (m_fh == INVALID_HANDLE_VALUE) return true; BOOL rc = ::CloseHandle(m_fh); m_fh = INVALID_HANDLE_VALUE; return !!rc; } // ATA win_ata_device::win_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "ata", req_type), m_usr_options(false), m_admin(false), m_phydrive(-1), m_id_is_cached(false), m_is_3ware(false), m_port(-1), m_smartver_state(0) { } win_ata_device::~win_ata_device() throw() { } // Open ATA device bool win_ata_device::open() { const char * name = skipdev(get_dev_name()); int len = strlen(name); // [sh]d[a-z]([a-z])?(:[saicmfp]+)? => Physical drive 0-701, with options char drive[2+1] = "", options[8+1] = ""; int n1 = -1, n2 = -1; if ( sscanf(name, "%*[sh]d%2[a-z]%n:%6[saimfp]%n", drive, &n1, options, &n2) >= 1 && ((n1 == len && !options[0]) || n2 == len) ) { return open(sdxy_to_phydrive(drive), -1, options, -1); } // [sh]d[a-z],N(:[saicmfp3]+)? => Physical drive 0-701, RAID port N, with options drive[0] = 0; options[0] = 0; n1 = -1; n2 = -1; unsigned port = ~0; if ( sscanf(name, "%*[sh]d%2[a-z],%u%n:%7[saimfp3]%n", drive, &port, &n1, options, &n2) >= 2 && port < 32 && ((n1 == len && !options[0]) || n2 == len) ) { return open(sdxy_to_phydrive(drive), -1, options, port); } // pd<m>,N => Physical drive <m>, RAID port N int phydrive = -1; port = ~0; n1 = -1; n2 = -1; if ( sscanf(name, "pd%d%n,%u%n", &phydrive, &n1, &port, &n2) >= 1 && phydrive >= 0 && ((n1 == len && (int)port < 0) || (n2 == len && port < 32))) { return open(phydrive, -1, "", (int)port); } // [a-zA-Z]: => Physical drive behind logical drive 0-25 int logdrive = drive_letter(name); if (logdrive >= 0) { return open(-1, logdrive, "", -1); } return set_err(EINVAL); } bool win_ata_device::open(int phydrive, int logdrive, const char * options, int port) { m_phydrive = -1; char devpath[30]; if (0 <= phydrive && phydrive <= 255) snprintf(devpath, sizeof(devpath)-1, "\\\\.\\PhysicalDrive%d", (m_phydrive = phydrive)); else if (0 <= logdrive && logdrive <= 'Z'-'A') snprintf(devpath, sizeof(devpath)-1, "\\\\.\\%c:", 'A'+logdrive); else return set_err(ENOENT); // Open device HANDLE h = INVALID_HANDLE_VALUE; if (!(*options && !options[strspn(options, "fp")])) { // Open with admin rights m_admin = true; h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); } if (h == INVALID_HANDLE_VALUE) { // Open without admin rights m_admin = false; h = CreateFileA(devpath, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); } if (h == INVALID_HANDLE_VALUE) { long err = GetLastError(); if (err == ERROR_FILE_NOT_FOUND) set_err(ENOENT, "%s: not found", devpath); else if (err == ERROR_ACCESS_DENIED) set_err(EACCES, "%s: access denied", devpath); else set_err(EIO, "%s: Error=%ld", devpath, err); return false; } set_fh(h); // Warn once if admin rights are missing if (!m_admin) { static bool noadmin_warning = false; if (!noadmin_warning) { pout("Warning: Limited functionality due to missing admin rights\n"); noadmin_warning = true; } } if (ata_debugmode > 1) pout("%s: successfully opened%s\n", devpath, (!m_admin ? " (without admin rights)" :"")); m_usr_options = false; if (*options) { // Save user options m_options = options; m_usr_options = true; } else if (port >= 0) // RAID: SMART_* and SCSI_MINIPORT m_options = "s3"; else { // Set default options according to Windows version static const char * def_options = ata_get_def_options(); m_options = def_options; } // SMART_GET_VERSION may spin up disk, so delay until first real SMART_* call m_port = port; if (port < 0) return true; // 3ware RAID: Get port map GETVERSIONINPARAMS_EX vers_ex; int devmap = smart_get_version(h, &vers_ex); // 3ware RAID if vendor id present m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE); unsigned long portmap = 0; if (port >= 0 && devmap >= 0) { // 3ware RAID: check vendor id if (!m_is_3ware) { pout("SMART_GET_VERSION returns unknown Identifier = 0x%04x\n" "This is no 3ware 9000 controller or driver has no SMART support.\n", vers_ex.wIdentifier); devmap = -1; } else portmap = vers_ex.dwDeviceMapEx; } if (devmap < 0) { pout("%s: ATA driver has no SMART support\n", devpath); if (!is_permissive()) { close(); return set_err(ENOSYS); } devmap = 0x0f; } m_smartver_state = 1; { // 3ware RAID: update devicemap first if (!update_3ware_devicemap_ioctl(h)) { if ( smart_get_version(h, &vers_ex) >= 0 && vers_ex.wIdentifier == SMART_VENDOR_3WARE ) portmap = vers_ex.dwDeviceMapEx; } // Check port existence if (!(portmap & (1L << port))) { if (!is_permissive()) { close(); return set_err(ENOENT, "%s: Port %d is empty or does not exist", devpath, port); } } } return true; } ///////////////////////////////////////////////////////////////////////////// // Interface to ATA devices bool win_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { // No multi-sector support for now, see above // warning about IOCTL_ATA_PASS_THROUGH if (!ata_cmd_is_supported(in, ata_device::supports_data_out | ata_device::supports_output_regs | ata_device::supports_48bit) ) return false; // 3ware RAID: SMART DISABLE without port number disables SMART functions if ( m_is_3ware && m_port < 0 && in.in_regs.command == ATA_SMART_CMD && in.in_regs.features == ATA_SMART_DISABLE) return set_err(ENOSYS, "SMART DISABLE requires 3ware port number"); // Determine ioctl functions valid for this ATA cmd const char * valid_options = 0; switch (in.in_regs.command) { case ATA_IDENTIFY_DEVICE: case ATA_IDENTIFY_PACKET_DEVICE: // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE // and SCSI_MINIPORT_* if requested by user valid_options = (m_usr_options ? "saimf" : "saif"); break; case ATA_CHECK_POWER_MODE: // Try GetDevicePowerState() first, ATA/IDE_PASS_THROUGH may spin up disk valid_options = "pai3"; break; case ATA_SMART_CMD: switch (in.in_regs.features) { case ATA_SMART_READ_VALUES: case ATA_SMART_READ_THRESHOLDS: case ATA_SMART_AUTOSAVE: case ATA_SMART_ENABLE: case ATA_SMART_DISABLE: case ATA_SMART_AUTO_OFFLINE: // SMART_*, ATA_, IDE_, SCSI_PASS_THROUGH, STORAGE_PREDICT_FAILURE // and SCSI_MINIPORT_* if requested by user valid_options = (m_usr_options ? "saimf" : "saif"); break; case ATA_SMART_IMMEDIATE_OFFLINE: // SMART_SEND_DRIVE_COMMAND does not support ABORT_SELF_TEST valid_options = (m_usr_options || in.in_regs.lba_low != 127/*ABORT*/ ? "saim3" : "aim3"); break; case ATA_SMART_READ_LOG_SECTOR: // SMART_RCV_DRIVE_DATA does not support READ_LOG // Try SCSI_MINIPORT also to skip buggy class driver // SMART functions do not support multi sector I/O. if (in.size == 512) valid_options = (m_usr_options ? "saim3" : "aim3"); else valid_options = "a"; break; case ATA_SMART_WRITE_LOG_SECTOR: // ATA_PASS_THROUGH, SCSI_MINIPORT, others don't support DATA_OUT // but SCSI_MINIPORT_* only if requested by user and single sector. valid_options = (in.size == 512 && m_usr_options ? "am" : "a"); break; case ATA_SMART_STATUS: valid_options = (m_usr_options ? "saimf" : "saif"); break; default: // Unknown SMART command, handle below break; } break; default: // Other ATA command, handle below break; } if (!valid_options) { // No special ATA command found above, select a generic pass through ioctl. if (!( in.direction == ata_cmd_in::no_data || (in.direction == ata_cmd_in::data_in && in.size == 512)) || in.in_regs.is_48bit_cmd() ) // DATA_OUT, more than one sector, 48-bit command: ATA_PASS_THROUGH only valid_options = "a"; else // ATA/IDE_PASS_THROUGH valid_options = "ai"; } if (!m_admin) { // Restrict to IOCTL_STORAGE_* if (strchr(valid_options, 'f')) valid_options = "f"; else if (strchr(valid_options, 'p')) valid_options = "p"; else return set_err(ENOSYS, "Function requires admin rights"); } // Set IDEREGS IDEREGS regs, prev_regs; { const ata_in_regs & lo = in.in_regs; regs.bFeaturesReg = lo.features; regs.bSectorCountReg = lo.sector_count; regs.bSectorNumberReg = lo.lba_low; regs.bCylLowReg = lo.lba_mid; regs.bCylHighReg = lo.lba_high; regs.bDriveHeadReg = lo.device; regs.bCommandReg = lo.command; regs.bReserved = 0; } if (in.in_regs.is_48bit_cmd()) { const ata_in_regs & hi = in.in_regs.prev; prev_regs.bFeaturesReg = hi.features; prev_regs.bSectorCountReg = hi.sector_count; prev_regs.bSectorNumberReg = hi.lba_low; prev_regs.bCylLowReg = hi.lba_mid; prev_regs.bCylHighReg = hi.lba_high; prev_regs.bDriveHeadReg = hi.device; prev_regs.bCommandReg = hi.command; prev_regs.bReserved = 0; } // Set data direction int datasize = 0; char * data = 0; switch (in.direction) { case ata_cmd_in::no_data: break; case ata_cmd_in::data_in: datasize = (int)in.size; data = (char *)in.buffer; break; case ata_cmd_in::data_out: datasize = -(int)in.size; data = (char *)in.buffer; break; default: return set_err(EINVAL, "win_ata_device::ata_pass_through: invalid direction=%d", (int)in.direction); } // Try all valid ioctls in the order specified in m_options bool powered_up = false; bool out_regs_set = false; bool id_is_cached = false; const char * options = m_options.c_str(); for (int i = 0; ; i++) { char opt = options[i]; if (!opt) { if (in.in_regs.command == ATA_CHECK_POWER_MODE && powered_up) { // Power up reported by GetDevicePowerState() and no ioctl available // to detect the actual mode of the drive => simulate ATA result ACTIVE/IDLE. regs.bSectorCountReg = 0xff; out_regs_set = true; break; } // No IOCTL found return set_err(ENOSYS); } if (!strchr(valid_options, opt)) // Invalid for this command continue; errno = 0; assert( datasize == 0 || datasize == 512 || (datasize == -512 && strchr("am", opt)) || (datasize > 512 && opt == 'a')); int rc; switch (opt) { default: assert(0); case 's': // call SMART_GET_VERSION once for each drive if (m_smartver_state > 1) { rc = -1; errno = ENOSYS; break; } if (!m_smartver_state) { assert(m_port == -1); GETVERSIONINPARAMS_EX vers_ex; if (smart_get_version(get_fh(), &vers_ex) < 0) { if (!failuretest_permissive) { m_smartver_state = 2; rc = -1; errno = ENOSYS; break; } failuretest_permissive--; } else { // 3ware RAID if vendor id present m_is_3ware = (vers_ex.wIdentifier == SMART_VENDOR_3WARE); } m_smartver_state = 1; } rc = smart_ioctl(get_fh(), ®s, data, datasize, m_port); out_regs_set = (in.in_regs.features == ATA_SMART_STATUS); id_is_cached = (m_port < 0); // Not cached by 3ware driver break; case 'm': rc = ata_via_scsi_miniport_smart_ioctl(get_fh(), ®s, data, datasize); id_is_cached = (m_port < 0); break; case 'a': rc = ata_pass_through_ioctl(get_fh(), ®s, (in.in_regs.is_48bit_cmd() ? &prev_regs : 0), data, datasize); out_regs_set = true; break; case 'i': rc = ide_pass_through_ioctl(get_fh(), ®s, data, datasize); out_regs_set = true; break; case 'f': if (in.in_regs.command == ATA_IDENTIFY_DEVICE) { rc = get_identify_from_device_property(get_fh(), (ata_identify_device *)data); if (rc == 0 && m_phydrive >= 0) get_serial_from_wmi(m_phydrive, (ata_identify_device *)data); id_is_cached = true; } else if (in.in_regs.command == ATA_SMART_CMD) switch (in.in_regs.features) { case ATA_SMART_READ_VALUES: rc = storage_predict_failure_ioctl(get_fh(), data); if (rc > 0) rc = 0; break; case ATA_SMART_ENABLE: rc = 0; break; case ATA_SMART_STATUS: rc = storage_predict_failure_ioctl(get_fh()); if (rc == 0) { // Good SMART status out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f; } else if (rc > 0) { // Bad SMART status out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4; rc = 0; } break; default: errno = ENOSYS; rc = -1; } else { errno = ENOSYS; rc = -1; } break; case '3': rc = ata_via_3ware_miniport_ioctl(get_fh(), ®s, data, datasize, m_port); out_regs_set = true; break; case 'p': assert(in.in_regs.command == ATA_CHECK_POWER_MODE && in.size == 0); rc = get_device_power_state(get_fh()); if (rc == 0) { // Power down reported by GetDevicePowerState(), using a passthrough ioctl would // spin up the drive => simulate ATA result STANDBY. regs.bSectorCountReg = 0x00; out_regs_set = true; } else if (rc > 0) { // Power up reported by GetDevicePowerState(), but this reflects the actual mode // only if it is selected by the device driver => try a passthrough ioctl to get the // actual mode, if none available simulate ACTIVE/IDLE. powered_up = true; rc = -1; errno = ENOSYS; } break; } if (!rc) // Working ioctl found break; if (errno != ENOSYS) // Abort on I/O error return set_err(errno); out_regs_set = false; // CAUTION: *_ioctl() MUST NOT change "regs" Parameter in the ENOSYS case } // Return IDEREGS if set if (out_regs_set) { ata_out_regs & lo = out.out_regs; lo.error = regs.bFeaturesReg; lo.sector_count = regs.bSectorCountReg; lo.lba_low = regs.bSectorNumberReg; lo.lba_mid = regs.bCylLowReg; lo.lba_high = regs.bCylHighReg; lo.device = regs.bDriveHeadReg; lo.status = regs.bCommandReg; if (in.in_regs.is_48bit_cmd()) { ata_out_regs & hi = out.out_regs.prev; hi.sector_count = prev_regs.bSectorCountReg; hi.lba_low = prev_regs.bSectorNumberReg; hi.lba_mid = prev_regs.bCylLowReg; hi.lba_high = prev_regs.bCylHighReg; } } if ( in.in_regs.command == ATA_IDENTIFY_DEVICE || in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE) // Update ata_identify_is_cached() result according to ioctl used. m_id_is_cached = id_is_cached; return true; } // Return true if OS caches the ATA identify sector bool win_ata_device::ata_identify_is_cached() const { return m_id_is_cached; } ////////////////////////////////////////////////////////////////////// // csmi_ata_device bool csmi_device::get_phy_info(CSMI_SAS_PHY_INFO & phy_info) { // Get driver info to check CSMI support CSMI_SAS_DRIVER_INFO_BUFFER driver_info_buf; memset(&driver_info_buf, 0, sizeof(driver_info_buf)); if (!csmi_ioctl(CC_CSMI_SAS_GET_DRIVER_INFO, &driver_info_buf.IoctlHeader, sizeof(driver_info_buf))) return false; if (scsi_debugmode > 1) { const CSMI_SAS_DRIVER_INFO & driver_info = driver_info_buf.Information; pout("CSMI_SAS_DRIVER_INFO:\n"); pout(" Name: \"%.81s\"\n", driver_info.szName); pout(" Description: \"%.81s\"\n", driver_info.szDescription); pout(" Revision: %d.%d\n", driver_info.usMajorRevision, driver_info.usMinorRevision); } // Get Phy info CSMI_SAS_PHY_INFO_BUFFER phy_info_buf; memset(&phy_info_buf, 0, sizeof(phy_info_buf)); if (!csmi_ioctl(CC_CSMI_SAS_GET_PHY_INFO, &phy_info_buf.IoctlHeader, sizeof(phy_info_buf))) return false; phy_info = phy_info_buf.Information; if (phy_info.bNumberOfPhys > sizeof(phy_info.Phy)/sizeof(phy_info.Phy[0])) return set_err(EIO, "CSMI_SAS_PHY_INFO: Bogus NumberOfPhys=%d", phy_info.bNumberOfPhys); if (scsi_debugmode > 1) { pout("CSMI_SAS_PHY_INFO: NumberOfPhys=%d\n", phy_info.bNumberOfPhys); for (int i = 0; i < phy_info.bNumberOfPhys; i++) { const CSMI_SAS_PHY_ENTITY & pe = phy_info.Phy[i]; const CSMI_SAS_IDENTIFY & id = pe.Identify, & at = pe.Attached; pout("Phy[%d] Port: 0x%02x\n", i, pe.bPortIdentifier); pout(" Type: 0x%02x, 0x%02x\n", id.bDeviceType, at.bDeviceType); pout(" InitProto: 0x%02x, 0x%02x\n", id.bInitiatorPortProtocol, at.bInitiatorPortProtocol); pout(" TargetProto: 0x%02x, 0x%02x\n", id.bTargetPortProtocol, at.bTargetPortProtocol); pout(" PhyIdent: 0x%02x, 0x%02x\n", id.bPhyIdentifier, at.bPhyIdentifier); const unsigned char * b = id.bSASAddress; pout(" SASAddress: %02x %02x %02x %02x %02x %02x %02x %02x, ", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); b = at.bSASAddress; pout( "%02x %02x %02x %02x %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); } } return true; } bool csmi_device::check_phy(const CSMI_SAS_PHY_INFO & phy_info, unsigned phy_no) { // Check Phy presence if (phy_no >= phy_info.bNumberOfPhys) return set_err(ENOENT, "Port %u does not exist (#ports: %d)", phy_no, phy_info.bNumberOfPhys); const CSMI_SAS_PHY_ENTITY & phy_ent = phy_info.Phy[phy_no]; if (phy_ent.Attached.bDeviceType == CSMI_SAS_NO_DEVICE_ATTACHED) return set_err(ENOENT, "No device on port %u", phy_no); switch (phy_ent.Attached.bTargetPortProtocol) { case CSMI_SAS_PROTOCOL_SATA: case CSMI_SAS_PROTOCOL_STP: break; default: return set_err(ENOENT, "No SATA device on port %u (protocol: %u)", phy_no, phy_ent.Attached.bTargetPortProtocol); } return true; } bool csmi_device::select_phy(unsigned phy_no) { CSMI_SAS_PHY_INFO phy_info; if (!get_phy_info(phy_info)) return false; if (!check_phy(phy_info, phy_no)) return false; m_phy_ent = phy_info.Phy[phy_no]; return true; } bool csmi_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_supported(in, ata_device::supports_data_out | ata_device::supports_output_regs | ata_device::supports_multi_sector | ata_device::supports_48bit, "CMSI") ) return false; // Create buffer with appropriate size raw_buffer pthru_raw_buf(sizeof(CSMI_SAS_STP_PASSTHRU_BUFFER) + in.size); CSMI_SAS_STP_PASSTHRU_BUFFER * pthru_buf = (CSMI_SAS_STP_PASSTHRU_BUFFER *)pthru_raw_buf.data(); // Set addresses from Phy info CSMI_SAS_STP_PASSTHRU & pthru = pthru_buf->Parameters; const CSMI_SAS_PHY_ENTITY & phy_ent = get_phy_ent(); pthru.bPhyIdentifier = phy_ent.Identify.bPhyIdentifier; pthru.bPortIdentifier = phy_ent.bPortIdentifier; memcpy(pthru.bDestinationSASAddress, phy_ent.Attached.bSASAddress, sizeof(pthru.bDestinationSASAddress)); pthru.bConnectionRate = CSMI_SAS_LINK_RATE_NEGOTIATED; // Set transfer mode switch (in.direction) { case ata_cmd_in::no_data: pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_UNSPECIFIED; break; case ata_cmd_in::data_in: pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_READ; pthru.uDataLength = in.size; break; case ata_cmd_in::data_out: pthru.uFlags = CSMI_SAS_STP_PIO | CSMI_SAS_STP_WRITE; pthru.uDataLength = in.size; memcpy(pthru_buf->bDataBuffer, in.buffer, in.size); break; default: return set_err(EINVAL, "csmi_ata_device::ata_pass_through: invalid direction=%d", (int)in.direction); } // Set host-to-device FIS { unsigned char * fis = pthru.bCommandFIS; const ata_in_regs & lo = in.in_regs; const ata_in_regs & hi = in.in_regs.prev; fis[ 0] = 0x27; // Type: host-to-device FIS fis[ 1] = 0x80; // Bit7: Update command register fis[ 2] = lo.command; fis[ 3] = lo.features; fis[ 4] = lo.lba_low; fis[ 5] = lo.lba_mid; fis[ 6] = lo.lba_high; fis[ 7] = lo.device; fis[ 8] = hi.lba_low; fis[ 9] = hi.lba_mid; fis[10] = hi.lba_high; fis[11] = hi.features; fis[12] = lo.sector_count; fis[13] = hi.sector_count; } // Call ioctl if (!csmi_ioctl(CC_CSMI_SAS_STP_PASSTHRU, &pthru_buf->IoctlHeader, pthru_raw_buf.size())) { return false; } // Get device-to-host FIS { const unsigned char * fis = pthru_buf->Status.bStatusFIS; ata_out_regs & lo = out.out_regs; lo.status = fis[ 2]; lo.error = fis[ 3]; lo.lba_low = fis[ 4]; lo.lba_mid = fis[ 5]; lo.lba_high = fis[ 6]; lo.device = fis[ 7]; lo.sector_count = fis[12]; if (in.in_regs.is_48bit_cmd()) { ata_out_regs & hi = out.out_regs.prev; hi.lba_low = fis[ 8]; hi.lba_mid = fis[ 9]; hi.lba_high = fis[10]; hi.sector_count = fis[13]; } } // Get data if (in.direction == ata_cmd_in::data_in) // TODO: Check ptru_buf->Status.uDataBytes memcpy(in.buffer, pthru_buf->bDataBuffer, in.size); return true; } ////////////////////////////////////////////////////////////////////// // win_csmi_device win_csmi_device::win_csmi_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "ata", req_type), m_fh(INVALID_HANDLE_VALUE), m_phy_no(0) { } win_csmi_device::~win_csmi_device() throw() { if (m_fh != INVALID_HANDLE_VALUE) CloseHandle(m_fh); } bool win_csmi_device::is_open() const { return (m_fh != INVALID_HANDLE_VALUE); } bool win_csmi_device::close() { if (m_fh == INVALID_HANDLE_VALUE) return true; BOOL rc = CloseHandle(m_fh); m_fh = INVALID_HANDLE_VALUE; return !!rc; } bool win_csmi_device::open_scsi() { // Parse name unsigned contr_no = ~0, phy_no = ~0; int nc = -1; const char * name = skipdev(get_dev_name()); if (!( sscanf(name, "csmi%u,%u%n", &contr_no, &phy_no, &nc) >= 0 && nc == (int)strlen(name) && contr_no <= 9 && phy_no < 32) ) return set_err(EINVAL); // Open controller handle char devpath[30]; snprintf(devpath, sizeof(devpath)-1, "\\\\.\\Scsi%u:", contr_no); HANDLE h = CreateFileA(devpath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, (SECURITY_ATTRIBUTES *)0, OPEN_EXISTING, 0, 0); if (h == INVALID_HANDLE_VALUE) { long err = GetLastError(); if (err == ERROR_FILE_NOT_FOUND) set_err(ENOENT, "%s: not found", devpath); else if (err == ERROR_ACCESS_DENIED) set_err(EACCES, "%s: access denied", devpath); else set_err(EIO, "%s: Error=%ld", devpath, err); return false; } if (scsi_debugmode > 1) pout(" %s: successfully opened\n", devpath); m_fh = h; m_phy_no = phy_no; return true; } bool win_csmi_device::open() { if (!open_scsi()) return false; // Get Phy info for this drive if (!select_phy(m_phy_no)) { close(); return false; } return true; } bool win_csmi_device::csmi_ioctl(unsigned code, IOCTL_HEADER * csmi_buffer, unsigned csmi_bufsiz) { // Determine signature const char * sig; switch (code) { case CC_CSMI_SAS_GET_DRIVER_INFO: sig = CSMI_ALL_SIGNATURE; break; case CC_CSMI_SAS_GET_PHY_INFO: case CC_CSMI_SAS_STP_PASSTHRU: sig = CSMI_SAS_SIGNATURE; break; default: return set_err(ENOSYS, "Unknown CSMI code=%u", code); } // Set header csmi_buffer->HeaderLength = sizeof(IOCTL_HEADER); strncpy((char *)csmi_buffer->Signature, sig, sizeof(csmi_buffer->Signature)); csmi_buffer->Timeout = CSMI_SAS_TIMEOUT; csmi_buffer->ControlCode = code; csmi_buffer->ReturnCode = 0; csmi_buffer->Length = csmi_bufsiz - sizeof(IOCTL_HEADER); // Call function DWORD num_out = 0; if (!DeviceIoControl(m_fh, IOCTL_SCSI_MINIPORT, csmi_buffer, csmi_bufsiz, csmi_buffer, csmi_bufsiz, &num_out, (OVERLAPPED*)0)) { long err = GetLastError(); if (scsi_debugmode) pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, Error=%ld\n", code, err); if ( err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_DEV_NOT_EXIST) return set_err(ENOSYS, "CSMI is not supported (Error=%ld)", err); else return set_err(EIO, "CSMI(%u) failed with Error=%ld", code, err); } // Check result if (csmi_buffer->ReturnCode) { if (scsi_debugmode) { pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) failed, ReturnCode=%u\n", code, (unsigned)csmi_buffer->ReturnCode); } return set_err(EIO, "CSMI(%u) failed with ReturnCode=%u", code, (unsigned)csmi_buffer->ReturnCode); } if (scsi_debugmode > 1) pout(" IOCTL_SCSI_MINIPORT(CC_CSMI_%u) succeeded, bytes returned: %u\n", code, (unsigned)num_out); return true; } ///////////////////////////////////////////////////////////////////////////// // SPT Interface (for SCSI devices and ATA devices behind SATLs) // Only supported in NT and later ///////////////////////////////////////////////////////////////////////////// win_scsi_device::win_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "scsi", req_type) { } bool win_scsi_device::open() { const char * name = skipdev(get_dev_name()); int len = strlen(name); // sd[a-z]([a-z])?,N => Physical drive 0-701, RAID port N char drive[2+1] = ""; int sub_addr = -1; int n1 = -1; int n2 = -1; if ( sscanf(name, "sd%2[a-z]%n,%d%n", drive, &n1, &sub_addr, &n2) >= 1 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0)) ) { return open(sdxy_to_phydrive(drive), -1, -1, sub_addr); } // pd<m>,N => Physical drive <m>, RAID port N int pd_num = -1; sub_addr = -1; n1 = -1; n2 = -1; if ( sscanf(name, "pd%d%n,%d%n", &pd_num, &n1, &sub_addr, &n2) >= 1 && pd_num >= 0 && ((n1 == len && sub_addr == -1) || (n2 == len && sub_addr >= 0))) { return open(pd_num, -1, -1, sub_addr); } // [a-zA-Z]: => Physical drive behind logical drive 0-25 int logdrive = drive_letter(name); if (logdrive >= 0) { return open(-1, logdrive, -1, -1); } // n?st<m> => tape drive <m> (same names used in Cygwin's /dev emulation) int tape_num = -1; n1 = -1; if (sscanf(name, "st%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { return open(-1, -1, tape_num, -1); } tape_num = -1; n1 = -1; if (sscanf(name, "nst%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { return open(-1, -1, tape_num, -1); } // tape<m> => tape drive <m> tape_num = -1; n1 = -1; if (sscanf(name, "tape%d%n", &tape_num, &n1) == 1 && tape_num >= 0 && n1 == len) { return open(-1, -1, tape_num, -1); } return set_err(EINVAL); } bool win_scsi_device::open(int pd_num, int ld_num, int tape_num, int /*sub_addr*/) { char b[128]; b[sizeof(b) - 1] = '\0'; if (pd_num >= 0) snprintf(b, sizeof(b) - 1, "\\\\.\\PhysicalDrive%d", pd_num); else if (ld_num >= 0) snprintf(b, sizeof(b) - 1, "\\\\.\\%c:", 'A' + ld_num); else if (tape_num >= 0) snprintf(b, sizeof(b) - 1, "\\\\.\\TAPE%d", tape_num); else { set_err(EINVAL); return false; } // Open device HANDLE h = CreateFileA(b, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); if (h == INVALID_HANDLE_VALUE) { set_err(ENODEV, "%s: Open failed, Error=%u", b, (unsigned)GetLastError()); return false; } set_fh(h); return true; } typedef struct { SCSI_PASS_THROUGH_DIRECT spt; ULONG Filler; UCHAR ucSenseBuf[64]; } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; // Issue command via IOCTL_SCSI_PASS_THROUGH instead of *_DIRECT. // Used if DataTransferLength not supported by *_DIRECT. static long scsi_pass_through_indirect(HANDLE h, SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER * sbd) { struct SCSI_PASS_THROUGH_WITH_BUFFERS { SCSI_PASS_THROUGH spt; ULONG Filler; UCHAR ucSenseBuf[sizeof(sbd->ucSenseBuf)]; UCHAR ucDataBuf[512]; }; SCSI_PASS_THROUGH_WITH_BUFFERS sb; memset(&sb, 0, sizeof(sb)); // DATA_OUT not implemented yet if (!( sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sbd->spt.DataTransferLength <= sizeof(sb.ucDataBuf))) return ERROR_INVALID_PARAMETER; sb.spt.Length = sizeof(sb.spt); sb.spt.CdbLength = sbd->spt.CdbLength; memcpy(sb.spt.Cdb, sbd->spt.Cdb, sizeof(sb.spt.Cdb)); sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); sb.spt.DataIn = sbd->spt.DataIn; sb.spt.DataTransferLength = sbd->spt.DataTransferLength; sb.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf); sb.spt.TimeOutValue = sbd->spt.TimeOutValue; DWORD num_out; if (!DeviceIoControl(h, IOCTL_SCSI_PASS_THROUGH, &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) return GetLastError(); sbd->spt.ScsiStatus = sb.spt.ScsiStatus; if (sb.spt.ScsiStatus & SCSI_STATUS_CHECK_CONDITION) memcpy(sbd->ucSenseBuf, sb.ucSenseBuf, sizeof(sbd->ucSenseBuf)); sbd->spt.DataTransferLength = sb.spt.DataTransferLength; if (sbd->spt.DataIn == SCSI_IOCTL_DATA_IN && sb.spt.DataTransferLength > 0) memcpy(sbd->spt.DataBuffer, sb.ucDataBuf, sb.spt.DataTransferLength); return 0; } // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c bool win_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop) { int report = scsi_debugmode; // TODO if (report > 0) { int k, j; const unsigned char * ucp = iop->cmnd; const char * np; char buff[256]; const int sz = (int)sizeof(buff); np = scsi_get_opcode_name(ucp[0]); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " "data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); pout("%s", buff); } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) { set_err(EINVAL, "cmnd_len too large"); return false; } memset(&sb, 0, sizeof(sb)); sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); sb.spt.CdbLength = iop->cmnd_len; memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len); sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60); bool direct = true; switch (iop->dxfer_dir) { case DXFER_NONE: sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; break; case DXFER_FROM_DEVICE: sb.spt.DataIn = SCSI_IOCTL_DATA_IN; sb.spt.DataTransferLength = iop->dxfer_len; sb.spt.DataBuffer = iop->dxferp; // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte // transfers (needed for SMART STATUS check of JMicron USB bridges) if (sb.spt.DataTransferLength == 1) direct = false; break; case DXFER_TO_DEVICE: sb.spt.DataIn = SCSI_IOCTL_DATA_OUT; sb.spt.DataTransferLength = iop->dxfer_len; sb.spt.DataBuffer = iop->dxferp; break; default: set_err(EINVAL, "bad dxfer_dir"); return false; } long err = 0; if (direct) { DWORD num_out; if (!DeviceIoControl(get_fh(), IOCTL_SCSI_PASS_THROUGH_DIRECT, &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) err = GetLastError(); } else err = scsi_pass_through_indirect(get_fh(), &sb); if (err) return set_err((err == ERROR_INVALID_FUNCTION ? ENOSYS : EIO), "IOCTL_SCSI_PASS_THROUGH%s failed, Error=%ld", (direct ? "_DIRECT" : ""), err); iop->scsi_status = sb.spt.ScsiStatus; if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) { int slen = sb.ucSenseBuf[7] + 8; if (slen > (int)sizeof(sb.ucSenseBuf)) slen = sizeof(sb.ucSenseBuf); if (slen > (int)iop->max_sense_len) slen = iop->max_sense_len; memcpy(iop->sensep, sb.ucSenseBuf, slen); iop->resp_sense_len = slen; if (report) { if (report > 1) { pout(" >>> Sense buffer, len=%d:\n", slen); dStrHex(iop->sensep, slen , 1); } if ((iop->sensep[0] & 0x7f) > 0x71) pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[1] & 0xf, iop->sensep[2], iop->sensep[3]); else pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[2] & 0xf, iop->sensep[12], iop->sensep[13]); } } else iop->resp_sense_len = 0; if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0)) iop->resid = iop->dxfer_len - sb.spt.DataTransferLength; else iop->resid = 0; if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } return true; } // Interface to SPT SCSI devices. See scsicmds.h and os_linux.c static long scsi_pass_through_direct(HANDLE fd, UCHAR targetid, struct scsi_cmnd_io * iop) { int report = scsi_debugmode; // TODO if (report > 0) { int k, j; const unsigned char * ucp = iop->cmnd; const char * np; char buff[256]; const int sz = (int)sizeof(buff); np = scsi_get_opcode_name(ucp[0]); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " "data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); pout("%s", buff); } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sb; if (iop->cmnd_len > (int)sizeof(sb.spt.Cdb)) { return EINVAL; } memset(&sb, 0, sizeof(sb)); sb.spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); //sb.spt.PathId = 0; sb.spt.TargetId = targetid; //sb.spt.Lun = 0; sb.spt.CdbLength = iop->cmnd_len; memcpy(sb.spt.Cdb, iop->cmnd, iop->cmnd_len); sb.spt.SenseInfoLength = sizeof(sb.ucSenseBuf); sb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf); sb.spt.TimeOutValue = (iop->timeout ? iop->timeout : 60); bool direct = true; switch (iop->dxfer_dir) { case DXFER_NONE: sb.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; break; case DXFER_FROM_DEVICE: sb.spt.DataIn = SCSI_IOCTL_DATA_IN; sb.spt.DataTransferLength = iop->dxfer_len; sb.spt.DataBuffer = iop->dxferp; // IOCTL_SCSI_PASS_THROUGH_DIRECT does not support single byte // transfers (needed for SMART STATUS check of JMicron USB bridges) if (sb.spt.DataTransferLength == 1) direct = false; break; case DXFER_TO_DEVICE: sb.spt.DataIn = SCSI_IOCTL_DATA_OUT; sb.spt.DataTransferLength = iop->dxfer_len; sb.spt.DataBuffer = iop->dxferp; break; default: return EINVAL; } long err = 0; if (direct) { DWORD num_out; if (!DeviceIoControl(fd, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sb, sizeof(sb), &sb, sizeof(sb), &num_out, 0)) err = GetLastError(); } else err = scsi_pass_through_indirect(fd, &sb); if (err) { return err; } iop->scsi_status = sb.spt.ScsiStatus; if (SCSI_STATUS_CHECK_CONDITION & iop->scsi_status) { int slen = sb.ucSenseBuf[7] + 8; if (slen > (int)sizeof(sb.ucSenseBuf)) slen = sizeof(sb.ucSenseBuf); if (slen > (int)iop->max_sense_len) slen = iop->max_sense_len; memcpy(iop->sensep, sb.ucSenseBuf, slen); iop->resp_sense_len = slen; if (report) { if (report > 1) { pout(" >>> Sense buffer, len=%d:\n", slen); dStrHex(iop->sensep, slen , 1); } if ((iop->sensep[0] & 0x7f) > 0x71) pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[1] & 0xf, iop->sensep[2], iop->sensep[3]); else pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[2] & 0xf, iop->sensep[12], iop->sensep[13]); } } else iop->resp_sense_len = 0; if ((iop->dxfer_len > 0) && (sb.spt.DataTransferLength > 0)) iop->resid = iop->dxfer_len - sb.spt.DataTransferLength; else iop->resid = 0; if ((iop->dxfer_dir == DXFER_FROM_DEVICE) && (report > 1)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } return 0; } // Areca RAID Controller(SAS Device) win_areca_scsi_device::win_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca") { set_fh(INVALID_HANDLE_VALUE); set_disknum(disknum); set_encnum(encnum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } bool win_areca_scsi_device::open() { HANDLE hFh; if( is_open() ) { return true; } hFh = CreateFile( get_dev_name(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if(hFh == INVALID_HANDLE_VALUE) { return false; } set_fh(hFh); return true; } smart_device * win_areca_scsi_device::autodetect_open() { return this; } int win_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) { int ioctlreturn = 0; ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop); if ( ioctlreturn || iop->scsi_status ) { ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop); if ( ioctlreturn || iop->scsi_status ) { // errors found return -1; } } return ioctlreturn; } bool win_areca_scsi_device::arcmsr_lock() { #define SYNCOBJNAME "Global\\SynIoctlMutex" int ctlrnum = -1; char mutexstr[64]; if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1) return set_err(EINVAL, "unable to parse device name"); snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum); m_mutex = CreateMutex(NULL, FALSE, mutexstr); if ( m_mutex == NULL ) { return set_err(EIO, "CreateMutex failed"); } // atomic access to driver WaitForSingleObject(m_mutex, INFINITE); return true; } bool win_areca_scsi_device::arcmsr_unlock() { if( m_mutex != NULL) { ReleaseMutex(m_mutex); CloseHandle(m_mutex); } return true; } // Areca RAID Controller(SATA Disk) win_areca_ata_device::win_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca") { set_fh(INVALID_HANDLE_VALUE); set_disknum(disknum); set_encnum(encnum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } bool win_areca_ata_device::open() { HANDLE hFh; if( is_open() ) { return true; } hFh = CreateFile( get_dev_name(), GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if(hFh == INVALID_HANDLE_VALUE) { return false; } set_fh(hFh); return true; } smart_device * win_areca_ata_device::autodetect_open() { int is_ata = 1; // autodetect device type is_ata = arcmsr_get_dev_type(); if(is_ata < 0) { set_err(EIO); return this; } if(is_ata == 1) { // SATA device return this; } // SAS device smart_device_auto_ptr newdev(new win_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum())); close(); delete this; newdev->open(); // TODO: Can possibly pass open fd return newdev.release(); } int win_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) { int ioctlreturn = 0; ioctlreturn = scsi_pass_through_direct(get_fh(), 16, iop); if ( ioctlreturn || iop->scsi_status ) { ioctlreturn = scsi_pass_through_direct(get_fh(), 127, iop); if ( ioctlreturn || iop->scsi_status ) { // errors found return -1; } } return ioctlreturn; } bool win_areca_ata_device::arcmsr_lock() { #define SYNCOBJNAME "Global\\SynIoctlMutex" int ctlrnum = -1; char mutexstr[64]; if (sscanf(get_dev_name(), "\\\\.\\scsi%d:", &ctlrnum) < 1) return set_err(EINVAL, "unable to parse device name"); snprintf(mutexstr, sizeof(mutexstr), "%s%d", SYNCOBJNAME, ctlrnum); m_mutex = CreateMutex(NULL, FALSE, mutexstr); if ( m_mutex == NULL ) { return set_err(EIO, "CreateMutex failed"); } // atomic access to driver WaitForSingleObject(m_mutex, INFINITE); return true; } bool win_areca_ata_device::arcmsr_unlock() { if( m_mutex != NULL) { ReleaseMutex(m_mutex); CloseHandle(m_mutex); } return true; } ////////////////////////////////////////////////////////////////////////////////////////////////// } // namespace ///////////////////////////////////////////////////////////////////////////// // Initialize platform interface and register with smi() void smart_interface::init() { { // Remove "." from DLL search path if supported // to prevent DLL preloading attacks BOOL (WINAPI * SetDllDirectoryA_p)(LPCSTR) = (BOOL (WINAPI *)(LPCSTR)) GetProcAddress(GetModuleHandleA("kernel32.dll"), "SetDllDirectoryA"); if (SetDllDirectoryA_p) SetDllDirectoryA_p(""); } static os_win32::win_smart_interface the_win_interface; smart_interface::set(&the_win_interface); } #ifndef __CYGWIN__ // Get exe directory // (prototype in utiliy.h) std::string get_exe_dir() { char path[MAX_PATH]; // Get path of this exe if (!GetModuleFileNameA(GetModuleHandleA(0), path, sizeof(path))) throw std::runtime_error("GetModuleFileName() failed"); // Replace backslash by slash int sl = -1; for (int i = 0; path[i]; i++) if (path[i] == '\\') { path[i] = '/'; sl = i; } // Remove filename if (sl >= 0) path[sl] = 0; return path; } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/������������������������������������������������������������0000755�0000000�0000000�00000000000�12212065524�016523� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/runcmdu.exe.manifest����������������������������������������0000644�0000000�0000000�00000000746�11646550747�022537� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" name="runcmdu.exe" type="win32" /> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> </assembly> ��������������������������smartmontools-6.2+svn3841.orig/os_win32/syslog_win32.cpp��������������������������������������������0000644�0000000�0000000�00000024017�12002076410�021566� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/syslog_win32.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ // Win32 Emulation of syslog() for smartd // Writes to windows event log on NT4/2000/XP // (Register syslogevt.exe as event message file) // If facility is set to LOG_LOCAL[0-7], log is written to // file "<ident>.log", stdout, stderr, "<ident>[1-5].log". #include "syslog.h" #include <stdlib.h> #include <stdio.h> #include <time.h> #include <errno.h> #include <process.h> // getpid() #define WIN32_LEAN_AND_MEAN #include <windows.h> // RegisterEventSourceA(), ReportEventA(), ... const char *syslog_win32_cpp_cvsid = "$Id: syslog_win32.cpp 3575 2012-07-19 21:32:56Z chrfranke $" SYSLOG_H_CVSID; #ifdef _MSC_VER // MSVC #define snprintf _snprintf #define vsnprintf _vsnprintf #endif #define ARGUSED(x) ((void)(x)) #ifndef _MT //MT runtime not necessary, because thread uses no unsafe lib functions //#error Program must be linked with multithreaded runtime library #endif #ifdef TESTEVT // Redirect event log to stdout for testing static BOOL Test_ReportEventA(HANDLE h, WORD type, WORD cat, DWORD id, PSID usid, WORD nstrings, WORD datasize, LPCTSTR * strings, LPVOID data) { int i; printf("%u %lu:%s", type, id, nstrings != 1?"\n":""); for (i = 0; i < nstrings; i++) printf(" \"%s\"\n", strings[i]); fflush(stdout); return TRUE; } HANDLE Test_RegisterEventSourceA(LPCTSTR server, LPCTSTR source) { return (HANDLE)42; } #define ReportEventA Test_ReportEventA #define RegisterEventSourceA Test_RegisterEventSourceA #endif // TESTEVT // Event message ids, // should be identical to MSG_SYSLOG* in "syslogevt.h" // (generated by "mc" from "syslogevt.mc") #define MSG_SYSLOG 0x00000000L #define MSG_SYSLOG_01 0x00000001L // ... #define MSG_SYSLOG_10 0x0000000AL static char sl_ident[100]; static char sl_logpath[sizeof(sl_ident) + sizeof("0.log")-1]; static FILE * sl_logfile; static char sl_pidstr[16]; static HANDLE sl_hevtsrc; // Ring buffer for event log output via thread #define MAXLINES 10 #define LINELEN 200 static HANDLE evt_hthread; static char evt_lines[MAXLINES][LINELEN+1]; static int evt_priorities[MAXLINES]; static volatile int evt_timeout; static int evt_index_in, evt_index_out; static HANDLE evt_wait_in, evt_wait_out; // Map syslog priority to event type static WORD pri2evtype(int priority) { switch (priority) { default: case LOG_EMERG: case LOG_ALERT: case LOG_CRIT: case LOG_ERR: return EVENTLOG_ERROR_TYPE; case LOG_WARNING: return EVENTLOG_WARNING_TYPE; case LOG_NOTICE: case LOG_INFO: case LOG_DEBUG: return EVENTLOG_INFORMATION_TYPE; } } // Map syslog priority to string static const char * pri2text(int priority) { switch (priority) { case LOG_EMERG: return "EMERG"; case LOG_ALERT: return "ALERT"; case LOG_CRIT: return "CRIT"; default: case LOG_ERR: return "ERROR"; case LOG_WARNING: return "Warn"; case LOG_NOTICE: return "Note"; case LOG_INFO: return "Info"; case LOG_DEBUG: return "Debug"; } } // Output cnt events from ring buffer static void report_events(int cnt) { const char * msgs[3+MAXLINES]; int i, pri; if (cnt <= 0) return; if (cnt > MAXLINES) cnt = MAXLINES; pri = evt_priorities[evt_index_out]; msgs[0] = sl_ident; msgs[1] = sl_pidstr; msgs[2] = pri2text(pri); for (i = 0; i < cnt; i++) { //assert(evt_priorities[evt_index_out] == pri); msgs[3+i] = evt_lines[evt_index_out]; if (++evt_index_out >= MAXLINES) evt_index_out = 0; } ReportEventA(sl_hevtsrc, pri2evtype(pri), // type 0, MSG_SYSLOG+cnt, // category, message id NULL, // no security id (WORD)(3+cnt), 0, // 3+cnt strings, ... msgs, NULL); // ... , no data } // Thread to combine several syslog lines into one event log entry static ULONG WINAPI event_logger_thread(LPVOID arg) { int cnt; ARGUSED(arg); cnt = 0; for (;;) { // Wait for first line ... int prior, i, rest; if (cnt == 0) { if (WaitForSingleObject(evt_wait_out, (evt_timeout? INFINITE : 0)) != WAIT_OBJECT_0) break; cnt = 1; } // ... wait some time for more lines with same prior i = evt_index_out; prior = evt_priorities[i]; rest = 0; while (cnt < MAXLINES) { long timeout = evt_timeout * ((1000L * (MAXLINES-cnt+1))/MAXLINES); if (WaitForSingleObject(evt_wait_out, timeout) != WAIT_OBJECT_0) break; if (++i >= MAXLINES) i = 0; if (evt_priorities[i] != prior) { rest = 1; break; } cnt++; } // Output all in one event log entry report_events(cnt); // Signal space if (!ReleaseSemaphore(evt_wait_in, cnt, NULL)) break; cnt = rest; } return 0; } static void on_exit_event_logger(void) { // Output lines immediate if exiting evt_timeout = 0; // Wait for thread to finish WaitForSingleObject(evt_hthread, 1000L); CloseHandle(evt_hthread); #if 0 if (sl_hevtsrc) { DeregisterEventSource(sl_hevtsrc); sl_hevtsrc = 0; } #else // Leave event message source open to prevent losing messages during shutdown #endif } static int start_event_logger() { DWORD tid; evt_timeout = 1; if ( !(evt_wait_in = CreateSemaphore(NULL, MAXLINES, MAXLINES, NULL)) || !(evt_wait_out = CreateSemaphore(NULL, 0, MAXLINES, NULL))) { fprintf(stderr,"CreateSemaphore failed, Error=%ld\n", GetLastError()); return -1; } if (!(evt_hthread = CreateThread(NULL, 0, event_logger_thread, NULL, 0, &tid))) { fprintf(stderr,"CreateThread failed, Error=%ld\n", GetLastError()); return -1; } atexit(on_exit_event_logger); return 0; } // Write lines to event log ring buffer static void write_event_log(int priority, const char * lines) { int cnt = 0; int i; for (i = 0; lines[i]; i++) { int len = 0; while (lines[i+len] && lines[i+len] != '\n') len++; ; if (len > 0) { // Wait for space if (WaitForSingleObject(evt_wait_in, INFINITE) != WAIT_OBJECT_0) return; // Copy line evt_priorities[evt_index_in] = priority; memcpy(evt_lines[evt_index_in], lines+i, (len < LINELEN ? len : LINELEN)); if (len < LINELEN) evt_lines[evt_index_in][len] = 0; if (++evt_index_in >= MAXLINES) evt_index_in = 0; // Signal avail if ring buffer full if (++cnt >= MAXLINES) { ReleaseSemaphore(evt_wait_out, cnt, NULL); cnt = 0; } i += len; } if (!lines[i]) break; } // Signal avail if (cnt > 0) ReleaseSemaphore(evt_wait_out, cnt, NULL); Sleep(1); } // Write lines to logfile static void write_logfile(FILE * f, int priority, const char * lines) { time_t now; char stamp[sizeof("2004-04-04 10:00:00")+13]; int i; now = time((time_t*)0); if (!strftime(stamp, sizeof(stamp)-1, "%Y-%m-%d %H:%M:%S", localtime(&now))) strcpy(stamp,"?"); for (i = 0; lines[i]; i++) { int len = 0; while (lines[i+len] && lines[i+len] != '\n') len++; if (len > 0) { fprintf(f, "%s %s[%s]: %-5s: ", stamp, sl_ident, sl_pidstr, pri2text(priority)); fwrite(lines+i, len, 1, f); fputc('\n', f); i += len; } if (!lines[i]) break; } } void openlog(const char *ident, int logopt, int facility) { int pid; if (sl_logpath[0] || sl_logfile || sl_hevtsrc) return; // Already open strncpy(sl_ident, ident, sizeof(sl_ident)-1); // logopt==LOG_PID assumed ARGUSED(logopt); pid = getpid(); if (snprintf(sl_pidstr, sizeof(sl_pidstr)-1, (pid >= 0 ? "%d" : "0x%X"), pid) < 0) strcpy(sl_pidstr,"?"); if (facility == LOG_LOCAL0) // "ident.log" strcat(strcpy(sl_logpath, sl_ident), ".log"); else if (facility == LOG_LOCAL1) // stdout sl_logfile = stdout; else if (facility == LOG_LOCAL2) // stderr sl_logfile = stderr; else if (LOG_LOCAL2 < facility && facility <= LOG_LOCAL7) { // "ident[1-5].log" snprintf(sl_logpath, sizeof(sl_logpath)-1, "%s%d.log", sl_ident, LOG_FAC(facility)-LOG_FAC(LOG_LOCAL2)); } else // Assume LOG_DAEMON, use event log if possible, else "ident.log" if (!(sl_hevtsrc = RegisterEventSourceA(NULL/*localhost*/, sl_ident))) { // Cannot open => Use logfile long err = GetLastError(); strcat(strcpy(sl_logpath, sl_ident), ".log"); fprintf(stderr, "%s: Cannot register event source (Error=%ld), writing to %s\n", sl_ident, err, sl_logpath); } else { // Start event log thread start_event_logger(); } //assert(sl_logpath[0] || sl_logfile || sl_hevtsrc); } void closelog() { } void vsyslog(int priority, const char * message, va_list args) { char buffer[1000]; // Translation of %m to error text not supported yet if (strstr(message, "%m")) message = "Internal error: \"%%m\" in log message"; // Format message if (vsnprintf(buffer, sizeof(buffer)-1, message, args) < 0) strcpy(buffer, "Internal Error: buffer overflow"); if (sl_hevtsrc) { // Write to event log write_event_log(priority, buffer); } else if (sl_logfile) { // Write to stdout/err write_logfile(sl_logfile, priority, buffer); fflush(sl_logfile); } else if (sl_logpath[0]) { // Append to logfile FILE * f; if (!(f = fopen(sl_logpath, "a"))) return; write_logfile(f, priority, buffer); fclose(f); } } #ifdef TEST // Test program void syslog(int priority, const char *message, ...) { va_list args; va_start(args, message); vsyslog(priority, message, args); va_end(args); } int main(int argc, char* argv[]) { int i; openlog(argc < 2 ? "test" : argv[1], LOG_PID, (argc < 3 ? LOG_DAEMON : LOG_LOCAL1)); syslog(LOG_INFO, "Info\n"); syslog(LOG_WARNING, "Warning %d\n\n", 42); syslog(LOG_ERR, "Error %s", "Fatal"); for (i = 0; i < 100; i++) { char buf[LINELEN]; if (i % 13 == 0) Sleep(1000L); sprintf(buf, "Log Line %d\n", i); syslog(i % 17 ? LOG_INFO : LOG_ERR, buf); } closelog(); return 0; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/daemon_win32.h����������������������������������������������0000644�0000000�0000000�00000003704�12007523734�021171� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/daemon_win32.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef DAEMON_WIN32_H #define DAEMON_WIN32_H #define DAEMON_WIN32_H_CVSID "$Id: daemon_win32.h 3584 2012-08-05 17:05:32Z chrfranke $" #include <signal.h> // Additional non-ANSI signals #define SIGHUP (NSIG+1) #define SIGUSR1 (NSIG+2) #define SIGUSR2 (NSIG+3) // Options for Windows service typedef struct daemon_winsvc_options_s { const char * cmd_opt; // argv[1] option for services // For service "install" command only: const char * svcname; // Service name const char * dispname; // Service display name const char * descript; // Service description } daemon_winsvc_options; // This function must be called from main() int daemon_main(const char * ident, const daemon_winsvc_options * svc_opts, int (*main_func)(int, char **), int argc, char **argv ); // exit(code) returned by a service extern int daemon_winsvc_exitcode; // Simulate signal() void (*daemon_signal(int sig, void (*func)(int)))(int); const char * daemon_strsignal(int sig); // Simulate sleep() void daemon_sleep(int seconds); // Disable/Enable console void daemon_disable_console(void); int daemon_enable_console(const char * title); // Detach from console int daemon_detach(const char * ident); // Spawn a process and redirect stdio int daemon_spawn(const char * cmd, const char * inpbuf, int inpsize, char * outbuf, int outsize ); #endif // DAEMON_WIN32_H ������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/wmiquery.cpp������������������������������������������������0000644�0000000�0000000�00000012263�12123643645�021124� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/wmiquery.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2011-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "config.h" #define WINVER 0x0400 #define _WIN32_WINNT WINVER #include "wmiquery.h" #include <stdio.h> const char * wmiquery_cpp_cvsid = "$Id: wmiquery.cpp 3802 2013-03-24 18:36:21Z chrfranke $" WMIQUERY_H_CVSID; ///////////////////////////////////////////////////////////////////////////// // com_bstr com_bstr::com_bstr(const char * str) : m_bstr(0) { int sz = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, (LPWSTR)0, 0); if (sz <= 0) return; m_bstr = SysAllocStringLen((OLECHAR*)0, sz-1); if (!m_bstr) return; // throw std::bad_alloc MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, m_bstr, sz); } bool com_bstr::to_str(const BSTR & bstr, std::string & str) { if (!bstr) return false; int sz = WideCharToMultiByte(CP_ACP, 0, bstr, -1, (LPSTR)0, 0, (LPCSTR)0, (LPBOOL)0); if (sz <= 0) return false; char * buf = new char[sz]; WideCharToMultiByte(CP_ACP, 0, bstr, -1, buf, sz, (LPCSTR)0, (LPBOOL)0); str = buf; delete [] buf; return true; } ///////////////////////////////////////////////////////////////////////////// // wbem_object std::string wbem_object::get_str(const char * name) /*const*/ { std::string s; if (!m_intf) return s; VARIANT var; VariantInit(&var); if (m_intf->Get(com_bstr(name), 0L, &var, (CIMTYPE*)0, (LPLONG)0) /* != WBEM_S_NO_ERROR */) return s; if (var.vt == VT_BSTR) com_bstr::to_str(var.bstrVal, s); VariantClear(&var); return s; } ///////////////////////////////////////////////////////////////////////////// // wbem_enumerator bool wbem_enumerator::next(wbem_object & obj) { if (!m_intf) return false; ULONG n = 0; HRESULT rc = m_intf->Next(5000 /*5s*/, 1 /*count*/, obj.m_intf.replace(), &n); if (FAILED(rc) || n != 1) return false; return true; } ///////////////////////////////////////////////////////////////////////////// // wbem_services const CLSID xCLSID_WbemLocator = {0x4590f811, 0x1d3a, 0x11d0, {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}}; const IID xIID_IWbemLocator = {0xdc12a687, 0x737f, 0x11cf, {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}}; bool wbem_services::connect() { // Init COM during first call. static HRESULT init_rc = -1; static bool init_tried = false; if (!init_tried) { init_tried = true; init_rc = CoInitialize((LPVOID)0); } if (!(init_rc == S_OK || init_rc == S_FALSE)) return false; /// Create locator. com_intf_ptr<IWbemLocator> locator; HRESULT rc = CoCreateInstance(xCLSID_WbemLocator, (LPUNKNOWN)0, CLSCTX_INPROC_SERVER, xIID_IWbemLocator, (LPVOID*)locator.replace()); if (FAILED(rc)) return false; // Set timeout flag if supported. long flags = 0; OSVERSIONINFOA ver; ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA(&ver) && ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ( ver.dwMajorVersion >= 6 // Vista || (ver.dwMajorVersion == 5 && ver.dwMinorVersion >= 1))) // XP flags = WBEM_FLAG_CONNECT_USE_MAX_WAIT; // return in 2min or less // Connect to local server. rc = locator->ConnectServer(com_bstr("\\\\.\\root\\cimv2"), (BSTR)0, (BSTR)0, (BSTR)0, // User, Password, Locale flags, (BSTR)0, (IWbemContext*)0, m_intf.replace()); if (FAILED(rc)) return false; // Set authentication information, rc = CoSetProxyBlanket(m_intf.get(), RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, (OLECHAR*)0, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, (RPC_AUTH_IDENTITY_HANDLE*)0, EOAC_NONE); if (FAILED(rc)) { m_intf.reset(); return false; } return true; } bool wbem_services::vquery(wbem_enumerator & result, const char * qstr, va_list args) /*const*/ { if (!m_intf) return false; char qline[1024]; vsnprintf(qline, sizeof(qline), qstr, args); qline[sizeof(qline)-1] = 0; HRESULT rc = m_intf->ExecQuery( com_bstr("WQL"), com_bstr(qline), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, (IWbemContext*)0, result.m_intf.replace()); if (FAILED(rc)) return false; return true; } bool wbem_services::vquery1(wbem_object & obj, const char * qstr, va_list args) /*const*/ { wbem_enumerator result; if (!vquery(result, qstr, args)) return false; if (!result.next(obj)) return false; wbem_object peek; if (result.next(peek)) return false; return true; } bool wbem_services::query(wbem_enumerator & result, const char * qstr, ...) /*const*/ { va_list args; va_start(args, qstr); bool ok = vquery(result, qstr, args); va_end(args); return ok; } bool wbem_services::query1(wbem_object & obj, const char * qstr, ...) /*const*/ { va_list args; va_start(args, qstr); bool ok = vquery1(obj, qstr, args); va_end(args); return ok; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/wtssendmsg.c������������������������������������������������0000644�0000000�0000000�00000007243�12054173447�021103� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * WTSSendMessage() command line tool * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #define WINVER 0x0500 #define _WIN32_WINNT WINVER char svnid[] = "$Id: wtssendmsg.c 3714 2012-11-24 16:34:47Z chrfranke $"; #include <stdio.h> #include <string.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <wtsapi32.h> static int usage() { printf("wtssendmsg $Revision: 3714 $ - Display a message box on client desktops\n" "Copyright (C) 2012 Christian Franke, smartmontools.org\n\n" "Usage: wtssendmsg [-cas] [-v] [\"Caption\"] \"Message\"|-\n" " wtssendmsg -v\n\n" " -c Console session [default]\n" " -a Active sessions\n" " -s Connected sessions\n" " -v List sessions\n" ); return 1; } int main(int argc, const char **argv) { int mode = 0, verbose = 0, status = 0, i; const char * message = 0, * caption = ""; char msgbuf[1024]; WTS_SESSION_INFOA * sessions; DWORD count; for (i = 1; i < argc && argv[i][0] == '-' && argv[i][1]; i++) { int j; for (j = 1; argv[i][j]; j++) switch (argv[i][j]) { case 'c': mode = 0; break; case 'a': mode = 1; break; case 's': mode = 2; break; case 'v': verbose = 1; break; default: return usage(); } } if (i < argc) { if (i+1 < argc) caption = argv[i++]; message = argv[i++]; if (i < argc) return usage(); if (!strcmp(message, "-")) { // Read message from stdin i = fread(msgbuf, 1, sizeof(msgbuf)-1, stdin); if (i < 0) { perror("stdin"); return 1; } msgbuf[i] = 0; message = msgbuf; } } else { if (!verbose) return usage(); } // Get session list if (!WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &count)) { fprintf(stderr, "WTSEnumerateSessions() failed\n"); return 1; } for (i = 0; i < (int)count; i++) { if (verbose) { printf("Session %d (\"%s\", State=%d)%s", i, sessions[i].pWinStationName, sessions[i].State, (!message ? "\n" : ": ")); if (!message) continue; // List sessions only fflush(stdout); } if ( !strcmpi(sessions[i].pWinStationName, "Console") || (mode >= 1 && sessions[i].State == WTSActive) || (mode >= 2 && sessions[i].State == WTSConnected)) { // Send Message, don't wait for OK button DWORD result; if (WTSSendMessageA(WTS_CURRENT_SERVER_HANDLE, sessions[i].SessionId, (char *)caption, strlen(caption), (char *)message, strlen(message), MB_OK|MB_ICONEXCLAMATION, 0 /*Timeout*/, &result, FALSE /*!Wait*/)) { if (verbose) printf("message sent\n"); } else { status = 1; if (verbose) printf("WTSSendMessage() failed with error=%d\n", (int)GetLastError()); else fprintf(stderr, "Session %d (\"%s\", State=%d): WTSSendMessage() failed with error=%d\n", i, sessions[i].pWinStationName, sessions[i].State, (int)GetLastError()); } } else { if (verbose) printf("ignored\n"); } } WTSFreeMemory(sessions); return status; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/installer.nsi�����������������������������������������������0000644�0000000�0000000�00000070230�12101043146�021226� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������; ; smartmontools install NSIS script ; ; Home page of code is: http://smartmontools.sourceforge.net ; ; Copyright (C) 2006-13 Christian Franke <smartmontools-support@lists.sourceforge.net> ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; You should have received a copy of the GNU General Public License ; (for example COPYING); If not, see <http://www.gnu.org/licenses/>. ; ; $Id: installer.nsi 3759 2013-01-26 21:11:02Z chrfranke $ ; ;-------------------------------------------------------------------- ; Command line arguments: ; makensis -DINPDIR=<input-dir> -DINPDIR64=<input-dir-64-bit> \ ; -DOUTFILE=<output-file> -DVERSTR=<version-string> installer.nsi !ifndef INPDIR !define INPDIR "." !endif !ifndef OUTFILE !define OUTFILE "smartmontools.win32-setup.exe" !endif ;-------------------------------------------------------------------- ; General Name "smartmontools" OutFile "${OUTFILE}" SetCompressor /solid lzma XPStyle on InstallColors /windows ; Set in .onInit ;InstallDir "$PROGRAMFILES\smartmontools" ;InstallDirRegKey HKLM "Software\smartmontools" "Install_Dir" Var EDITOR !ifdef INPDIR64 Var X64 Var INSTDIR32 Var INSTDIR64 !endif LicenseData "${INPDIR}\doc\COPYING.txt" !include "FileFunc.nsh" !include "Sections.nsh" !insertmacro GetParameters !insertmacro GetOptions RequestExecutionLevel admin ;-------------------------------------------------------------------- ; Pages Page license Page components !ifdef INPDIR64 Page directory CheckX64 !else Page directory !endif Page instfiles UninstPage uninstConfirm UninstPage instfiles InstType "Full" InstType "Extract files only" InstType "Drive menu" ;-------------------------------------------------------------------- ; Sections !ifdef INPDIR64 Section "64-bit version" X64_SECTION ; Handled in Function CheckX64 SectionEnd !endif SectionGroup "!Program files" !macro FileExe path option !ifdef INPDIR64 ; Use dummy SetOutPath to control archive location of executables StrCmp $X64 "" +5 Goto +2 SetOutPath "$INSTDIR\bin64" File ${option} '${INPDIR64}\${path}' GoTo +4 Goto +2 SetOutPath "$INSTDIR\bin" File ${option} '${INPDIR}\${path}' !else File ${option} '${INPDIR}\${path}' !endif !macroend Section "smartctl" SMARTCTL_SECTION SectionIn 1 2 SetOutPath "$INSTDIR\bin" !insertmacro FileExe "bin\smartctl.exe" "" SectionEnd Section "smartd" SMARTD_SECTION SectionIn 1 2 SetOutPath "$INSTDIR\bin" ; Stop service ? StrCpy $1 "" IfFileExists "$INSTDIR\bin\smartd.exe" 0 nosrv ReadRegStr $0 HKLM "System\CurrentControlSet\Services\smartd" "ImagePath" StrCmp $0 "" nosrv ExecWait "net stop smartd" $1 nosrv: !insertmacro FileExe "bin\smartd.exe" "" IfFileExists "$INSTDIR\bin\smartd.conf" 0 +2 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Replace existing configuration file$\n$INSTDIR\bin\smartd.conf ?" /SD IDNO IDYES 0 IDNO +2 File "${INPDIR}\doc\smartd.conf" File "${INPDIR}\bin\smartd_warning.cmd" !insertmacro FileExe "bin\wtssendmsg.exe" "" ; Restart service ? StrCmp $1 "0" 0 +3 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Restart smartd service ?" /SD IDNO IDYES 0 IDNO +2 ExecWait "net start smartd" SectionEnd Section "smartctl-nc (GSmartControl)" SMARTCTL_NC_SECTION SectionIn 1 2 SetOutPath "$INSTDIR\bin" !insertmacro FileExe "bin\smartctl-nc.exe" "" SectionEnd Section "drivedb.h (Drive Database)" DRIVEDB_SECTION SectionIn 1 2 SetOutPath "$INSTDIR\bin" File "${INPDIR}\bin\drivedb.h" File "${INPDIR}\bin\update-smart-drivedb.exe" SectionEnd SectionGroupEnd Section "!Documentation" DOC_SECTION SectionIn 1 2 SetOutPath "$INSTDIR\doc" File "${INPDIR}\doc\AUTHORS.txt" File "${INPDIR}\doc\ChangeLog.txt" File "${INPDIR}\doc\ChangeLog-5.0-6.0.txt" File "${INPDIR}\doc\COPYING.txt" File "${INPDIR}\doc\INSTALL.txt" File "${INPDIR}\doc\NEWS.txt" File "${INPDIR}\doc\README.txt" File "${INPDIR}\doc\TODO.txt" File "${INPDIR}\doc\WARNINGS.txt" !ifdef INPDIR64 StrCmp $X64 "" +3 File "${INPDIR64}\doc\checksums64.txt" GoTo +2 File "${INPDIR}\doc\checksums32.txt" !else File "${INPDIR}\doc\checksums??.txt" !endif File "${INPDIR}\doc\smartctl.8.html" File "${INPDIR}\doc\smartctl.8.txt" File "${INPDIR}\doc\smartd.8.html" File "${INPDIR}\doc\smartd.8.txt" File "${INPDIR}\doc\smartd.conf" File "${INPDIR}\doc\smartd.conf.5.html" File "${INPDIR}\doc\smartd.conf.5.txt" SectionEnd Section "Uninstaller" UNINST_SECTION SectionIn 1 AddSize 40 CreateDirectory "$INSTDIR" ; Save installation location WriteRegStr HKLM "Software\smartmontools" "Install_Dir" "$INSTDIR" ; Write uninstall keys and program WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "DisplayName" "smartmontools" !ifdef VERSTR WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "DisplayVersion" "${VERSTR}" !endif ;WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "Publisher" "smartmontools" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "UninstallString" '"$INSTDIR\uninst-smartmontools.exe"' ;WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLInfoAbout" "http://smartmontools.sourceforge.net/" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "HelpLink" "http://smartmontools.sourceforge.net/" ;WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLUpdateInfo" "http://sourceforge.net/project/showfiles.php?group_id=64297" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "URLUpdateInfo" "http://smartmontools-win32.dyndns.org/" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "NoModify" 1 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" "NoRepair" 1 WriteUninstaller "uninst-smartmontools.exe" SectionEnd Section "Start Menu Shortcuts" MENU_SECTION SectionIn 1 SetShellVarContext all CreateDirectory "$SMPROGRAMS\smartmontools" !macro CreateAdminShortCut link target args CreateShortCut '${link}' '${target}' '${args}' push '${link}' Call ShellLinkSetRunAs !macroend ; runcmdu IfFileExists "$INSTDIR\bin\smartctl.exe" 0 +2 IfFileExists "$INSTDIR\bin\smartd.exe" 0 noruncmd SetOutPath "$INSTDIR\bin" !insertmacro FileExe "bin\runcmdu.exe" "" File "${INPDIR}\bin\runcmdu.exe.manifest" noruncmd: ; smartctl IfFileExists "$INSTDIR\bin\smartctl.exe" 0 noctl SetOutPath "$INSTDIR\bin" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl (Admin CMD).lnk" "$WINDIR\system32\cmd.exe" '/k PATH=$INSTDIR\bin;%PATH%&cd /d "$INSTDIR\bin"' CreateDirectory "$SMPROGRAMS\smartmontools\smartctl Examples" FileOpen $0 "$SMPROGRAMS\smartmontools\smartctl Examples\!Read this first!.txt" "w" FileWrite $0 "All the example commands in this directory$\r$\napply to the first drive (sda).$\r$\n" FileClose $0 !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\All info (-x).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -x sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Identify drive (-i).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -i sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\SMART attributes (-A -f brief).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -A -f brief sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\SMART capabilities (-c).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -c sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\SMART health status (-H).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -H sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\SMART error log (-l error).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -l error sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\SMART selftest log (-l selftest).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -l selftest sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Start long selftest (-t long).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -t long sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Start offline test (-t offline).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -t offline sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Start short selftest (-t short).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -t short sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Stop(Abort) selftest (-X).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -X sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Turn SMART off (-s off).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -s off sda" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartctl Examples\Turn SMART on (-s on).lnk" "$INSTDIR\bin\runcmdu.exe" "smartctl -s on sda" noctl: ; smartd IfFileExists "$INSTDIR\bin\smartd.exe" 0 nod SetOutPath "$INSTDIR\bin" CreateDirectory "$SMPROGRAMS\smartmontools\smartd Examples" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Daemon start, smartd.log.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd -l local0" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Daemon start, eventlog.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Daemon stop.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd stop" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Do all tests once (-q onecheck).lnk" "$INSTDIR\bin\runcmdu.exe" "smartd -q onecheck" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Debug mode (-d).lnk" "$INSTDIR\bin\runcmdu.exe" "smartd -d" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\smartd.conf (edit).lnk" "$EDITOR" "$INSTDIR\bin\smartd.conf" CreateShortCut "$SMPROGRAMS\smartmontools\smartd Examples\smartd.conf (view).lnk" "$EDITOR" "$INSTDIR\bin\smartd.conf" CreateShortCut "$SMPROGRAMS\smartmontools\smartd Examples\smartd.log (view).lnk" "$EDITOR" "$INSTDIR\bin\smartd.log" ; smartd service !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service install, eventlog, 30min.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd install" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service install, smartd.log, 10min.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd install -l local0 -i 600" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service install, smartd.log, 30min.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd install -l local0" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service remove.lnk" "$INSTDIR\bin\runcmdu.exe" "smartd remove" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service start.lnk" "$INSTDIR\bin\runcmdu.exe" "net start smartd" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\smartd Examples\Service stop.lnk" "$INSTDIR\bin\runcmdu.exe" "net stop smartd" nod: ; Documentation IfFileExists "$INSTDIR\doc\README.TXT" 0 nodoc SetOutPath "$INSTDIR\doc" CreateDirectory "$SMPROGRAMS\smartmontools\Documentation" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartctl manual page (html).lnk" "$INSTDIR\doc\smartctl.8.html" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd manual page (html).lnk" "$INSTDIR\doc\smartd.8.html" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf manual page (html).lnk" "$INSTDIR\doc\smartd.conf.5.html" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartctl manual page (txt).lnk" "$INSTDIR\doc\smartctl.8.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd manual page (txt).lnk" "$INSTDIR\doc\smartd.8.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf manual page (txt).lnk" "$INSTDIR\doc\smartd.conf.5.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\smartd.conf sample.lnk" "$EDITOR" "$INSTDIR\doc\smartd.conf" IfFileExists "$INSTDIR\bin\drivedb.h" 0 nodb CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb.h (view).lnk" "$EDITOR" "$INSTDIR\bin\drivedb.h" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\Documentation\drivedb-add.h (create, edit).lnk" "$EDITOR" "$INSTDIR\bin\drivedb-add.h" nodb: CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\ChangeLog.lnk" "$INSTDIR\doc\ChangeLog.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\COPYING.lnk" "$INSTDIR\doc\COPYING.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\NEWS.lnk" "$INSTDIR\doc\NEWS.txt" CreateShortCut "$SMPROGRAMS\smartmontools\Documentation\Windows version download page.lnk" "http://smartmontools-win32.dyndns.org/smartmontools/" nodoc: ; Homepage CreateShortCut "$SMPROGRAMS\smartmontools\smartmontools Home Page.lnk" "http://smartmontools.sourceforge.net/" ; drivedb.h update IfFileExists "$INSTDIR\bin\update-smart-drivedb.exe" 0 noupdb SetOutPath "$INSTDIR\bin" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\drivedb.h update.lnk" "$INSTDIR\bin\update-smart-drivedb.exe" "" noupdb: ; Uninstall IfFileExists "$INSTDIR\uninst-smartmontools.exe" 0 noinst SetOutPath "$INSTDIR" !insertmacro CreateAdminShortCut "$SMPROGRAMS\smartmontools\Uninstall smartmontools.lnk" "$INSTDIR\uninst-smartmontools.exe" "" noinst: SectionEnd Section "Add install dir to PATH" PATH_SECTION SectionIn 1 Push "$INSTDIR\bin" Call AddToPath SectionEnd SectionGroup "Add smartctl to drive menu" !macro DriveMenuRemove DetailPrint "Remove drive menu entries" DeleteRegKey HKCR "Drive\shell\smartctl0" DeleteRegKey HKCR "Drive\shell\smartctl1" DeleteRegKey HKCR "Drive\shell\smartctl2" DeleteRegKey HKCR "Drive\shell\smartctl3" DeleteRegKey HKCR "Drive\shell\smartctl4" DeleteRegKey HKCR "Drive\shell\smartctl5" !macroend Section "Remove existing entries first" DRIVE_REMOVE_SECTION SectionIn 3 !insertmacro DriveMenuRemove SectionEnd !macro DriveSection id name args Section 'smartctl ${args} ...' DRIVE_${id}_SECTION SectionIn 3 Call CheckRunCmdA DetailPrint 'Add drive menu entry "${name}": smartctl ${args} ...' WriteRegStr HKCR "Drive\shell\smartctl${id}" "" "${name}" WriteRegStr HKCR "Drive\shell\smartctl${id}\command" "" '"$INSTDIR\bin\runcmda.exe" "$INSTDIR\bin\smartctl.exe" ${args} %L' SectionEnd !macroend !insertmacro DriveSection 0 "SMART all info" "-x" !insertmacro DriveSection 1 "SMART status" "-Hc" !insertmacro DriveSection 2 "SMART attributes" "-A -f brief" !insertmacro DriveSection 3 "SMART short selftest" "-t short" !insertmacro DriveSection 4 "SMART long selftest" "-t long" !insertmacro DriveSection 5 "SMART continue selective selftest" '-t "selective,cont"' SectionGroupEnd ;-------------------------------------------------------------------- Section "Uninstall" ; Stop & remove service IfFileExists "$INSTDIR\bin\smartd.exe" 0 nosrv ReadRegStr $0 HKLM "System\CurrentControlSet\Services\smartd" "ImagePath" StrCmp $0 "" nosrv ExecWait "net stop smartd" MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Remove smartd service ?" /SD IDNO IDYES 0 IDNO nosrv ExecWait "$INSTDIR\bin\smartd.exe remove" nosrv: ; Remove installer registry keys DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\smartmontools" DeleteRegKey HKLM "Software\smartmontools" ; Remove conf file ? IfFileExists "$INSTDIR\bin\smartd.conf" 0 noconf ; Assume unchanged if timestamp is equal to sample file GetFileTime "$INSTDIR\bin\smartd.conf" $0 $1 GetFileTime "$INSTDIR\doc\smartd.conf" $2 $3 StrCmp "$0:$1" "$2:$3" +2 0 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete configuration file$\n$INSTDIR\bin\smartd.conf ?" /SD IDNO IDYES 0 IDNO noconf Delete "$INSTDIR\bin\smartd.conf" noconf: ; Remove log file ? IfFileExists "$INSTDIR\bin\smartd.log" 0 +3 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete log file$\n$INSTDIR\bin\smartd.log ?" /SD IDNO IDYES 0 IDNO +2 Delete "$INSTDIR\bin\smartd.log" ; Remove drivedb-add file ? IfFileExists "$INSTDIR\bin\drivedb-add.h" 0 +3 MessageBox MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2 "Delete local drive database file$\n$INSTDIR\bin\drivedb-add.h ?" /SD IDNO IDYES 0 IDNO +2 Delete "$INSTDIR\bin\drivedb-add.h" ; Remove files Delete "$INSTDIR\bin\smartctl.exe" Delete "$INSTDIR\bin\smartctl-nc.exe" Delete "$INSTDIR\bin\smartd.exe" Delete "$INSTDIR\bin\smartd_warning.cmd" ; TODO: Check for modifications? Delete "$INSTDIR\bin\drivedb.h" Delete "$INSTDIR\bin\drivedb.h.error" Delete "$INSTDIR\bin\drivedb.h.lastcheck" Delete "$INSTDIR\bin\drivedb.h.old" Delete "$INSTDIR\bin\update-smart-drivedb.exe" Delete "$INSTDIR\bin\smartctl-run.bat" Delete "$INSTDIR\bin\smartd-run.bat" Delete "$INSTDIR\bin\net-run.bat" Delete "$INSTDIR\bin\runcmda.exe" Delete "$INSTDIR\bin\runcmda.exe.manifest" Delete "$INSTDIR\bin\runcmdu.exe" Delete "$INSTDIR\bin\runcmdu.exe.manifest" Delete "$INSTDIR\bin\wtssendmsg.exe" Delete "$INSTDIR\doc\AUTHORS.txt" Delete "$INSTDIR\doc\ChangeLog.txt" Delete "$INSTDIR\doc\ChangeLog-5.0-6.0.txt" Delete "$INSTDIR\doc\COPYING.txt" Delete "$INSTDIR\doc\INSTALL.txt" Delete "$INSTDIR\doc\NEWS.txt" Delete "$INSTDIR\doc\README.txt" Delete "$INSTDIR\doc\TODO.txt" Delete "$INSTDIR\doc\WARNINGS.txt" Delete "$INSTDIR\doc\checksums*.txt" Delete "$INSTDIR\doc\smartctl.8.html" Delete "$INSTDIR\doc\smartctl.8.txt" Delete "$INSTDIR\doc\smartd.8.html" Delete "$INSTDIR\doc\smartd.8.txt" Delete "$INSTDIR\doc\smartd.conf" Delete "$INSTDIR\doc\smartd.conf.5.html" Delete "$INSTDIR\doc\smartd.conf.5.txt" Delete "$INSTDIR\uninst-smartmontools.exe" ; Remove shortcuts SetShellVarContext all Delete "$SMPROGRAMS\smartmontools\*.*" Delete "$SMPROGRAMS\smartmontools\Documentation\*.*" Delete "$SMPROGRAMS\smartmontools\smartctl Examples\*.*" Delete "$SMPROGRAMS\smartmontools\smartd Examples\*.*" ; Remove folders RMDir "$SMPROGRAMS\smartmontools\Documentation" RMDir "$SMPROGRAMS\smartmontools\smartctl Examples" RMDir "$SMPROGRAMS\smartmontools\smartd Examples" RMDir "$SMPROGRAMS\smartmontools" RMDir "$INSTDIR\bin" RMDir "$INSTDIR\doc" RMDir "$INSTDIR" ; Remove install dir from PATH Push "$INSTDIR\bin" Call un.RemoveFromPath ; Remove drive menu registry entries !insertmacro DriveMenuRemove ; Check for still existing entries IfFileExists "$INSTDIR\bin\smartd.exe" 0 +3 MessageBox MB_OK|MB_ICONEXCLAMATION "$INSTDIR\bin\smartd.exe could not be removed.$\nsmartd is possibly still running." /SD IDOK Goto +3 IfFileExists "$INSTDIR" 0 +2 MessageBox MB_OK "Note: $INSTDIR could not be removed." /SD IDOK IfFileExists "$SMPROGRAMS\smartmontools" 0 +2 MessageBox MB_OK "Note: $SMPROGRAMS\smartmontools could not be removed." /SD IDOK SectionEnd ;-------------------------------------------------------------------- ; Functions !macro AdjustSectionSize section SectionGetSize ${section} $0 IntOp $0 $0 / 2 SectionSetSize ${section} $0 !macroend Function .onInit ; Set default install directories StrCmp $INSTDIR "" 0 endinst ; /D=PATH option specified ? ReadRegStr $INSTDIR HKLM "Software\smartmontools" "Install_Dir" StrCmp $INSTDIR "" 0 endinst ; Already installed ? StrCpy $INSTDIR "$PROGRAMFILES\smartmontools" !ifdef INPDIR64 StrCpy $INSTDIR32 $INSTDIR StrCpy $INSTDIR64 "$PROGRAMFILES64\smartmontools" !endif endinst: !ifdef INPDIR64 ; Sizes of binary sections include 32-bit and 64-bit executables !insertmacro AdjustSectionSize ${SMARTCTL_SECTION} !insertmacro AdjustSectionSize ${SMARTD_SECTION} !insertmacro AdjustSectionSize ${SMARTCTL_NC_SECTION} !endif ; Use Notepad++ if installed StrCpy $EDITOR "$PROGRAMFILES\Notepad++\notepad++.exe" IfFileExists "$EDITOR" +2 0 StrCpy $EDITOR "notepad.exe" Call ParseCmdLine FunctionEnd ; Check x64 section and update INSTDIR accordingly !ifdef INPDIR64 Function CheckX64 SectionGetFlags ${X64_SECTION} $0 IntOp $0 $0 & ${SF_SELECTED} IntCmp $0 ${SF_SELECTED} x64 StrCpy $X64 "" StrCmp $INSTDIR32 "" +3 StrCpy $INSTDIR $INSTDIR32 StrCpy $INSTDIR32 "" Goto done x64: StrCpy $X64 "t" StrCmp $INSTDIR64 "" +3 StrCpy $INSTDIR $INSTDIR64 StrCpy $INSTDIR64 "" done: FunctionEnd !endif ; Command line parsing !macro CheckCmdLineOption name section StrCpy $allopts "$allopts,${name}" Push ",$opts," Push ",${name}," Call StrStr Pop $0 StrCmp $0 "" 0 sel_${name} !insertmacro UnselectSection ${section} Goto done_${name} sel_${name}: !insertmacro SelectSection ${section} StrCpy $nomatch "" done_${name}: !macroend Function ParseCmdLine ; get /SO option Var /global opts ${GetParameters} $R0 ${GetOptions} $R0 "/SO" $opts IfErrors 0 +2 Return Var /global allopts StrCpy $allopts "" Var /global nomatch StrCpy $nomatch "t" ; turn sections on or off !ifdef INPDIR64 !insertmacro CheckCmdLineOption "x64" ${X64_SECTION} Call CheckX64 StrCmp $opts "x64" 0 +2 Return ; leave sections unchanged if only "x64" is specified !endif !insertmacro CheckCmdLineOption "smartctl" ${SMARTCTL_SECTION} !insertmacro CheckCmdLineOption "smartd" ${SMARTD_SECTION} !insertmacro CheckCmdLineOption "smartctlnc" ${SMARTCTL_NC_SECTION} !insertmacro CheckCmdLineOption "drivedb" ${DRIVEDB_SECTION} !insertmacro CheckCmdLineOption "doc" ${DOC_SECTION} !insertmacro CheckCmdLineOption "uninst" ${UNINST_SECTION} !insertmacro CheckCmdLineOption "menu" ${MENU_SECTION} !insertmacro CheckCmdLineOption "path" ${PATH_SECTION} !insertmacro CheckCmdLineOption "driveremove" ${DRIVE_REMOVE_SECTION} !insertmacro CheckCmdLineOption "drive0" ${DRIVE_0_SECTION} !insertmacro CheckCmdLineOption "drive1" ${DRIVE_1_SECTION} !insertmacro CheckCmdLineOption "drive2" ${DRIVE_2_SECTION} !insertmacro CheckCmdLineOption "drive3" ${DRIVE_3_SECTION} !insertmacro CheckCmdLineOption "drive4" ${DRIVE_4_SECTION} !insertmacro CheckCmdLineOption "drive5" ${DRIVE_5_SECTION} StrCmp $opts "-" done StrCmp $nomatch "" done StrCpy $0 "$allopts,-" "" 1 MessageBox MB_OK "Usage: smartmontools-VERSION.win32-setup [/S] [/SO component,...] [/D=INSTDIR]$\n$\ncomponents:$\n $0" Abort done: FunctionEnd ; Install runcmda.exe if missing Function CheckRunCmdA IfFileExists "$INSTDIR\bin\runcmda.exe" done 0 SetOutPath "$INSTDIR\bin" !insertmacro FileExe "bin\runcmda.exe" "" File "${INPDIR}\bin\runcmda.exe.manifest" done: FunctionEnd ;-------------------------------------------------------------------- ; Path functions ; ; Based on example from: ; http://nsis.sourceforge.net/Path_Manipulation ; !include "WinMessages.nsh" ; Registry Entry for environment (NT4,2000,XP) ; All users: ;!define Environ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' ; Current user only: !define Environ 'HKCU "Environment"' ; AddToPath - Appends dir to PATH ; (does not work on Win9x/ME) ; ; Usage: ; Push "dir" ; Call AddToPath Function AddToPath Exch $0 Push $1 Push $2 Push $3 ReadRegStr $1 ${Environ} "PATH" Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" 0 done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" 0 done DetailPrint "Add to PATH: $0" StrCpy $2 $1 1 -1 StrCmp $2 ";" 0 +2 StrCpy $1 $1 -1 ; remove trailing ';' StrCmp $1 "" +2 ; no leading ';' StrCpy $0 "$1;$0" WriteRegExpandStr ${Environ} "PATH" $0 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 done: Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Removes dir from PATH ; ; Usage: ; Push "dir" ; Call RemoveFromPath Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 ReadRegStr $1 ${Environ} "PATH" StrCpy $5 $1 1 -1 StrCmp $5 ";" +2 StrCpy $1 "$1;" ; ensure trailing ';' Push $1 Push "$0;" Call un.StrStr Pop $2 ; pos of our dir StrCmp $2 "" done DetailPrint "Remove from PATH: $0" StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove StrCpy $3 "$5$6" StrCpy $5 $3 1 -1 StrCmp $5 ";" 0 +2 StrCpy $3 $3 -1 ; remove trailing ';' WriteRegExpandStr ${Environ} "PATH" $3 SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; StrStr - find substring in a string ; ; Usage: ; Push "this is some string" ; Push "some" ; Call StrStr ; Pop $0 ; "some string" !macro StrStr un Function ${un}StrStr Exch $R1 ; $R1=substring, stack=[old$R1,string,...] Exch ; stack=[string,old$R1,...] Exch $R2 ; $R2=string, stack=[old$R2,old$R1,...] Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=substring, $R2=string, $R3=strlen(substring) ; $R4=count, $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 ; $R1=old$R1, stack=[result,...] FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." ;-------------------------------------------------------------------- ; Set Run As Administrator flag in shortcut ; ; Slightly modified version from: ; http://nsis.sourceforge.net/IShellLink_Set_RunAs_flag ; !include "LogicLib.nsh" !define IPersistFile {0000010b-0000-0000-c000-000000000046} !define CLSID_ShellLink {00021401-0000-0000-C000-000000000046} !define IID_IShellLinkA {000214EE-0000-0000-C000-000000000046} !define IID_IShellLinkW {000214F9-0000-0000-C000-000000000046} !define IShellLinkDataList {45e2b4ae-b1c3-11d0-b92f-00a0c90312e1} !ifdef NSIS_UNICODE !define IID_IShellLink ${IID_IShellLinkW} !else !define IID_IShellLink ${IID_IShellLinkA} !endif Function ShellLinkSetRunAs ; Set archive location of $PLUGINSDIR Goto +2 SetOutPath "$INSTDIR" System::Store S ; push $0-$9, $R0-$R9 pop $9 ; $0 = CoCreateInstance(CLSID_ShellLink, 0, CLSCTX_INPROC_SERVER, IID_IShellLink, &$1) System::Call "ole32::CoCreateInstance(g'${CLSID_ShellLink}',i0,i1,g'${IID_IShellLink}',*i.r1)i.r0" ${If} $0 = 0 System::Call "$1->0(g'${IPersistFile}',*i.r2)i.r0" ; $0 = $1->QueryInterface(IPersistFile, &$2) ${If} $0 = 0 System::Call "$2->5(w '$9',i 0)i.r0" ; $0 = $2->Load($9, STGM_READ) ${If} $0 = 0 System::Call "$1->0(g'${IShellLinkDataList}',*i.r3)i.r0" ; $0 = $1->QueryInterface(IShellLinkDataList, &$3) ${If} $0 = 0 System::Call "$3->6(*i.r4)i.r0"; $0 = $3->GetFlags(&$4) ${If} $0 = 0 System::Call "$3->7(i $4|0x2000)i.r0" ; $0 = $3->SetFlags($4|SLDF_RUNAS_USER) ${If} $0 = 0 System::Call "$2->6(w '$9',i1)i.r0" ; $2->Save($9, TRUE) ${EndIf} ${EndIf} System::Call "$3->2()" ; $3->Release() ${EndIf} System::Call "$2->2()" ; $2->Release() ${EndIf} ${EndIf} System::Call "$1->2()" ; $1->Release() ${EndIf} ${If} $0 <> 0 DetailPrint "Set RunAsAdmin: $9 failed ($0)" ${Else} DetailPrint "Set RunAsAdmin: $9" ${EndIf} System::Store L ; push $0-$9, $R0-$R9 FunctionEnd ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/wbemcli_small.h���������������������������������������������0000644�0000000�0000000�00000020264�11515641643�021521� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/wbemcli_small.h * * Home page of code is: http://smartmontools.sourceforge.net * * This file was extracted from wbemcli.h of the w64 mingw-runtime package * (http://mingw-w64.sourceforge.net/). See original copyright below. */ /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef __REQUIRED_RPCNDR_H_VERSION__ #define __REQUIRED_RPCNDR_H_VERSION__ 475 #endif #include "rpc.h" #include "rpcndr.h" #ifndef __RPCNDR_H_VERSION__ #error This stub requires an updated version of <rpcndr.h> #endif #include "windows.h" #include "ole2.h" #ifndef __wbemcli_h__ #define __wbemcli_h__ #if !defined(__cplusplus) || defined(CINTERFACE) #error C++ interfaces only #endif typedef struct IWbemQualifierSet IWbemQualifierSet; typedef struct IWbemObjectSink IWbemObjectSink; typedef struct IEnumWbemClassObject IEnumWbemClassObject; typedef struct IWbemCallResult IWbemCallResult; typedef struct IWbemContext IWbemContext; extern "C" { typedef enum tag_WBEM_GENERIC_FLAG_TYPE { WBEM_FLAG_RETURN_IMMEDIATELY = 0x10,WBEM_FLAG_RETURN_WBEM_COMPLETE = 0,WBEM_FLAG_BIDIRECTIONAL = 0,WBEM_FLAG_FORWARD_ONLY = 0x20, WBEM_FLAG_NO_ERROR_OBJECT = 0x40,WBEM_FLAG_RETURN_ERROR_OBJECT = 0,WBEM_FLAG_SEND_STATUS = 0x80,WBEM_FLAG_DONT_SEND_STATUS = 0, WBEM_FLAG_ENSURE_LOCATABLE = 0x100,WBEM_FLAG_DIRECT_READ = 0x200,WBEM_FLAG_SEND_ONLY_SELECTED = 0,WBEM_RETURN_WHEN_COMPLETE = 0, WBEM_RETURN_IMMEDIATELY = 0x10,WBEM_MASK_RESERVED_FLAGS = 0x1f000,WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x20000, WBEM_FLAG_STRONG_VALIDATION = 0x100000 } WBEM_GENERIC_FLAG_TYPE; typedef long CIMTYPE; struct IWbemClassObject : public IUnknown { public: virtual HRESULT WINAPI GetQualifierSet(IWbemQualifierSet **ppQualSet) = 0; virtual HRESULT WINAPI Get(LPCWSTR wszName,long lFlags,VARIANT *pVal,CIMTYPE *pType,long *plFlavor) = 0; virtual HRESULT WINAPI Put(LPCWSTR wszName,long lFlags,VARIANT *pVal,CIMTYPE Type) = 0; virtual HRESULT WINAPI Delete(LPCWSTR wszName) = 0; virtual HRESULT WINAPI GetNames(LPCWSTR wszQualifierName,long lFlags,VARIANT *pQualifierVal,SAFEARRAY **pNames) = 0; virtual HRESULT WINAPI BeginEnumeration(long lEnumFlags) = 0; virtual HRESULT WINAPI Next(long lFlags,BSTR *strName,VARIANT *pVal,CIMTYPE *pType,long *plFlavor) = 0; virtual HRESULT WINAPI EndEnumeration(void) = 0; virtual HRESULT WINAPI GetPropertyQualifierSet(LPCWSTR wszProperty,IWbemQualifierSet **ppQualSet) = 0; virtual HRESULT WINAPI Clone(IWbemClassObject **ppCopy) = 0; virtual HRESULT WINAPI GetObjectText(long lFlags,BSTR *pstrObjectText) = 0; virtual HRESULT WINAPI SpawnDerivedClass(long lFlags,IWbemClassObject **ppNewClass) = 0; virtual HRESULT WINAPI SpawnInstance(long lFlags,IWbemClassObject **ppNewInstance) = 0; virtual HRESULT WINAPI CompareTo(long lFlags,IWbemClassObject *pCompareTo) = 0; virtual HRESULT WINAPI GetPropertyOrigin(LPCWSTR wszName,BSTR *pstrClassName) = 0; virtual HRESULT WINAPI InheritsFrom(LPCWSTR strAncestor) = 0; virtual HRESULT WINAPI GetMethod(LPCWSTR wszName,long lFlags,IWbemClassObject **ppInSignature,IWbemClassObject **ppOutSignature) = 0; virtual HRESULT WINAPI PutMethod(LPCWSTR wszName,long lFlags,IWbemClassObject *pInSignature,IWbemClassObject *pOutSignature) = 0; virtual HRESULT WINAPI DeleteMethod(LPCWSTR wszName) = 0; virtual HRESULT WINAPI BeginMethodEnumeration(long lEnumFlags) = 0; virtual HRESULT WINAPI NextMethod(long lFlags,BSTR *pstrName,IWbemClassObject **ppInSignature,IWbemClassObject **ppOutSignature) = 0; virtual HRESULT WINAPI EndMethodEnumeration(void) = 0; virtual HRESULT WINAPI GetMethodQualifierSet(LPCWSTR wszMethod,IWbemQualifierSet **ppQualSet) = 0; virtual HRESULT WINAPI GetMethodOrigin(LPCWSTR wszMethodName,BSTR *pstrClassName) = 0; }; struct IWbemServices : public IUnknown { public: virtual HRESULT WINAPI OpenNamespace(const BSTR strNamespace,long lFlags,IWbemContext *pCtx,IWbemServices **ppWorkingNamespace,IWbemCallResult **ppResult) = 0; virtual HRESULT WINAPI CancelAsyncCall(IWbemObjectSink *pSink) = 0; virtual HRESULT WINAPI QueryObjectSink(long lFlags,IWbemObjectSink **ppResponseHandler) = 0; virtual HRESULT WINAPI GetObject(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemClassObject **ppObject,IWbemCallResult **ppCallResult) = 0; virtual HRESULT WINAPI GetObjectAsync(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI PutClass(IWbemClassObject *pObject,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0; virtual HRESULT WINAPI PutClassAsync(IWbemClassObject *pObject,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI DeleteClass(const BSTR strClass,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0; virtual HRESULT WINAPI DeleteClassAsync(const BSTR strClass,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI CreateClassEnum(const BSTR strSuperclass,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0; virtual HRESULT WINAPI CreateClassEnumAsync(const BSTR strSuperclass,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI PutInstance(IWbemClassObject *pInst,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0; virtual HRESULT WINAPI PutInstanceAsync(IWbemClassObject *pInst,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI DeleteInstance(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemCallResult **ppCallResult) = 0; virtual HRESULT WINAPI DeleteInstanceAsync(const BSTR strObjectPath,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI CreateInstanceEnum(const BSTR strFilter,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0; virtual HRESULT WINAPI CreateInstanceEnumAsync(const BSTR strFilter,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI ExecQuery(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0; virtual HRESULT WINAPI ExecQueryAsync(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI ExecNotificationQuery(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IEnumWbemClassObject **ppEnum) = 0; virtual HRESULT WINAPI ExecNotificationQueryAsync(const BSTR strQueryLanguage,const BSTR strQuery,long lFlags,IWbemContext *pCtx,IWbemObjectSink *pResponseHandler) = 0; virtual HRESULT WINAPI ExecMethod(const BSTR strObjectPath,const BSTR strMethodName,long lFlags,IWbemContext *pCtx,IWbemClassObject *pInParams,IWbemClassObject **ppOutParams,IWbemCallResult **ppCallResult) = 0; virtual HRESULT WINAPI ExecMethodAsync(const BSTR strObjectPath,const BSTR strMethodName,long lFlags,IWbemContext *pCtx,IWbemClassObject *pInParams,IWbemObjectSink *pResponseHandler) = 0; }; EXTERN_C const IID IID_IWbemLocator; struct IWbemLocator : public IUnknown { public: virtual HRESULT WINAPI ConnectServer(const BSTR strNetworkResource,const BSTR strUser,const BSTR strPassword,const BSTR strLocale,long lSecurityFlags,const BSTR strAuthority,IWbemContext *pCtx,IWbemServices **ppNamespace) = 0; }; struct IEnumWbemClassObject : public IUnknown { public: virtual HRESULT WINAPI Reset(void) = 0; virtual HRESULT WINAPI Next(long lTimeout,ULONG uCount,IWbemClassObject **apObjects,ULONG *puReturned) = 0; virtual HRESULT WINAPI NextAsync(ULONG uCount,IWbemObjectSink *pSink) = 0; virtual HRESULT WINAPI Clone(IEnumWbemClassObject **ppEnum) = 0; virtual HRESULT WINAPI Skip(long lTimeout,ULONG nCount) = 0; }; EXTERN_C const CLSID CLSID_WbemLocator; typedef enum tag_WBEM_CONNECT_OPTIONS { WBEM_FLAG_CONNECT_REPOSITORY_ONLY = 0x40,WBEM_FLAG_CONNECT_USE_MAX_WAIT = 0x80,WBEM_FLAG_CONNECT_PROVIDERS = 0x100 } WBEM_CONNECT_OPTIONS; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/syslog.h����������������������������������������������������0000644�0000000�0000000�00000003353�12062413436�020222� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/syslog.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef SYSLOG_H #define SYSLOG_H #define SYSLOG_H_CVSID "$Id: syslog.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #include <stdarg.h> #ifdef __cplusplus extern "C" { #endif /* EVENTLOG_ERROR_TYPE: */ #define LOG_EMERG 0 #define LOG_ALERT 1 #define LOG_CRIT 2 #define LOG_ERR 3 /* EVENTLOG_WARNING_TYPE: */ #define LOG_WARNING 4 /* EVENTLOG_INFORMATION_TYPE: */ #define LOG_NOTICE 5 #define LOG_INFO 6 #define LOG_DEBUG 7 /* event log: */ #define LOG_DAEMON ( 3<<3) /* ident.log: */ #define LOG_LOCAL0 (16<<3) /* ident1-7.log: */ #define LOG_LOCAL1 (17<<3) #define LOG_LOCAL2 (18<<3) #define LOG_LOCAL3 (19<<3) #define LOG_LOCAL4 (20<<3) #define LOG_LOCAL5 (21<<3) #define LOG_LOCAL6 (22<<3) #define LOG_LOCAL7 (23<<3) #define LOG_FACMASK 0x03f8 #define LOG_FAC(f) (((f) & LOG_FACMASK) >> 3) #define LOG_PID 0x01 void openlog(const char * ident, int option, int facility); void closelog(void); void vsyslog(int priority, const char * message, va_list args); #ifdef __cplusplus } #endif #endif /* SYSLOG_H */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/update-smart-drivedb.nsi������������������������������������0000644�0000000�0000000�00000006765�12154143617�023304� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������; ; smartmontools drive database update NSIS script ; ; Home page of code is: http://smartmontools.sourceforge.net ; ; Copyright (C) 2011-13 Christian Franke <smartmontools-support@lists.sourceforge.net> ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; You should have received a copy of the GNU General Public License ; (for example COPYING); If not, see <http://www.gnu.org/licenses/>. ; ; $Id: update-smart-drivedb.nsi 3815 2013-06-06 17:31:59Z chrfranke $ ; ;-------------------------------------------------------------------- ; Command line arguments: ; makensis -DBRANCH=<svn-branch-name> update-smart-drivedb.nsi !include "FileFunc.nsh" Name "update-smart-drivedb" Caption "Update smartmontools drivedb.h" OutFile "update-smart-drivedb.exe" SetCompressor /solid lzma XPStyle on InstallColors /windows Page instfiles Section "" SetOutPath $INSTDIR !ifdef BRANCH StrCpy $0 "branches/${BRANCH}" Push $0 Call Download IfErrors 0 endload !endif StrCpy $0 "trunk" Push $0 Call Download IfErrors 0 endload MessageBox MB_OK "Download failed" /SD IDOK Abort "Download failed" endload: ; Check syntax Delete "drivedb.h.error" IfFileExists "smartctl-nc.exe" 0 endsyntax ExecWait '.\smartctl-nc.exe -B drivedb.h.new -P showall' $1 StrCmp $1 "0" endsyntax Rename "drivedb.h.new" "drivedb.h.error" MessageBox MB_OK "drivedb.h.error: rejected by smartctl, probably no longer compatible" /SD IDOK Abort "drivedb.h.error: rejected by smartctl, probably no longer compatible" endsyntax: ; Keep old file if identical Delete "drivedb.h.lastcheck" IfFileExists "drivedb.h" 0 endcomp Call Cmp IfErrors changed 0 DetailPrint "drivedb.h is already up to date" MessageBox MB_OK "$INSTDIR\drivedb.h is already up to date" /SD IDOK Delete "drivedb.h.new" DetailPrint "Create file: drivedb.h.lastcheck" FileOpen $1 "drivedb.h.lastcheck" w FileClose $1 Return changed: Delete "drivedb.h.old" Rename "drivedb.h" "drivedb.h.old" endcomp: Rename "drivedb.h.new" "drivedb.h" MessageBox MB_OK "$INSTDIR\drivedb.h updated from $0" /SD IDOK SectionEnd Function .onInit ; Install in same directory ${GetExePath} $INSTDIR FunctionEnd ; Download from branch or trunk on stack, SetErrors on error Function Download Pop $R0 DetailPrint "Download from $R0" ; SVN repository read-only URL ; (SF code browser does not return ContentLength required for NSISdl::download) StrCpy $R1 "http://svn.code.sf.net/p/smartmontools/code/$R0/smartmontools/drivedb.h" DetailPrint "($R1)" NSISdl::download $R1 "drivedb.h.new" Pop $R0 DetailPrint "Download: $R0" ClearErrors StrCmp $R0 "success" 0 err ; File must start with comment FileOpen $R0 "drivedb.h.new" r FileReadByte $R0 $R1 FileClose $R0 ClearErrors StrCmp $R1 "47" 0 +2 Return DetailPrint "drivedb.h.new: syntax error ($R1)" err: Delete "drivedb.h.new" SetErrors FunctionEnd ; Compare drivedb.h drivedb.h.new, SetErrors if different ; TODO: ignore differences in Id string Function Cmp ClearErrors FileOpen $R0 "drivedb.h" r FileOpen $R1 "drivedb.h.new" r readloop: FileRead $R0 $R2 FileRead $R1 $R3 StrCmp $R2 $R3 0 +2 IfErrors 0 readloop FileClose $R0 FileClose $R1 ClearErrors StrCmp $R2 $R3 0 +2 Return SetErrors FunctionEnd �����������smartmontools-6.2+svn3841.orig/os_win32/daemon_win32.cpp��������������������������������������������0000644�0000000�0000000�00000077627�12172534011�021534� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/daemon_win32.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #define WINVER 0x0600 #define _WIN32_WINNT WINVER #include "daemon_win32.h" const char * daemon_win32_cpp_cvsid = "$Id: daemon_win32.cpp 3834 2013-07-20 16:17:13Z chrfranke $" DAEMON_WIN32_H_CVSID; #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <io.h> #define WIN32_LEAN_AND_MEAN #include <windows.h> #ifdef _DEBUG #include <crtdbg.h> #endif #ifndef SERVICE_CONFIG_DELAYED_AUTO_START_INFO // Missing in older MinGW headers #define SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3 #endif ///////////////////////////////////////////////////////////////////////////// // Prevent spawning of child process if debugging #ifdef _DEBUG #define debugging() IsDebuggerPresent() #else #define debugging() FALSE #endif #define EVT_NAME_LEN 260 // Internal events (must be > SIGUSRn) #define EVT_RUNNING 100 // Exists when running, signaled on creation #define EVT_DETACHED 101 // Signaled when child detaches from console #define EVT_RESTART 102 // Signaled when child should restart static void make_name(char * name, int sig) { int i; if (!GetModuleFileNameA(NULL, name, EVT_NAME_LEN-10)) strcpy(name, "DaemonEvent"); for (i = 0; name[i]; i++) { char c = name[i]; if (!( ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) name[i] = '_'; } sprintf(name+strlen(name), "-%d", sig); } static HANDLE create_event(int sig, BOOL initial, BOOL errmsg, BOOL * exists) { char name[EVT_NAME_LEN]; HANDLE h; if (sig >= 0) make_name(name, sig); else name[0] = 0; if (exists) *exists = FALSE; if (!(h = CreateEventA(NULL, FALSE, initial, (name[0] ? name : NULL)))) { if (errmsg) fprintf(stderr, "CreateEvent(.,\"%s\"): Error=%ld\n", name, GetLastError()); return 0; } if (GetLastError() == ERROR_ALREADY_EXISTS) { if (!exists) { if (errmsg) fprintf(stderr, "CreateEvent(.,\"%s\"): Exists\n", name); CloseHandle(h); return 0; } *exists = TRUE; } return h; } static HANDLE open_event(int sig) { char name[EVT_NAME_LEN]; make_name(name, sig); return OpenEventA(EVENT_MODIFY_STATE, FALSE, name); } static int event_exists(int sig) { char name[EVT_NAME_LEN]; HANDLE h; make_name(name, sig); if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) return 0; CloseHandle(h); return 1; } static int sig_event(int sig) { char name[EVT_NAME_LEN]; HANDLE h; make_name(name, sig); if (!(h = OpenEventA(EVENT_MODIFY_STATE, FALSE, name))) { make_name(name, EVT_RUNNING); if (!(h = OpenEvent(EVENT_MODIFY_STATE, FALSE, name))) return -1; CloseHandle(h); return 0; } SetEvent(h); CloseHandle(h); return 1; } static void daemon_help(FILE * f, const char * ident, const char * message) { fprintf(f, "%s: %s.\n" "Use \"%s status|stop|reload|restart|sigusr1|sigusr2\" to control daemon.\n", ident, message, ident); fflush(f); } ///////////////////////////////////////////////////////////////////////////// // Parent Process static BOOL WINAPI parent_console_handler(DWORD event) { switch (event) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: return TRUE; // Ignore } return FALSE; // continue with next handler ... } static int parent_main(HANDLE rev) { HANDLE dev; HANDLE ht[2]; char * cmdline; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD rc, exitcode; // Ignore ^C, ^BREAK in parent SetConsoleCtrlHandler(parent_console_handler, TRUE/*add*/); // Create event used by child to signal daemon_detach() if (!(dev = create_event(EVT_DETACHED, FALSE/*not signaled*/, TRUE, NULL/*must not exist*/))) { CloseHandle(rev); return 101; } // Restart process with same args cmdline = GetCommandLineA(); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); if (!CreateProcessA( NULL, cmdline, NULL, NULL, TRUE/*inherit*/, 0, NULL, NULL, &si, &pi)) { fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); CloseHandle(rev); CloseHandle(dev); return 101; } CloseHandle(pi.hThread); // Wait for daemon_detach() or exit() ht[0] = dev; ht[1] = pi.hProcess; rc = WaitForMultipleObjects(2, ht, FALSE/*or*/, INFINITE); if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+2)) { fprintf(stderr, "WaitForMultipleObjects returns %lX\n", rc); TerminateProcess(pi.hProcess, 200); } CloseHandle(rev); CloseHandle(dev); // Get exit code if (!GetExitCodeProcess(pi.hProcess, &exitcode)) exitcode = 201; else if (exitcode == STILL_ACTIVE) // detach()ed, assume OK exitcode = 0; CloseHandle(pi.hProcess); return exitcode; } ///////////////////////////////////////////////////////////////////////////// // Child Process static int svc_mode; // Running as service? static int svc_paused; // Service paused? static void service_report_status(int state, int waithint); // Tables of signal handler and corresponding events typedef void (*sigfunc_t)(int); #define MAX_SIG_HANDLERS 8 static int num_sig_handlers = 0; static sigfunc_t sig_handlers[MAX_SIG_HANDLERS]; static int sig_numbers[MAX_SIG_HANDLERS]; static HANDLE sig_events[MAX_SIG_HANDLERS]; static HANDLE sighup_handle, sigint_handle, sigbreak_handle; static HANDLE sigterm_handle, sigusr1_handle; static HANDLE running_event; static int reopen_stdin, reopen_stdout, reopen_stderr; // Handler for windows console events static BOOL WINAPI child_console_handler(DWORD event) { // Caution: runs in a new thread // TODO: Guard with a mutex HANDLE h = 0; switch (event) { case CTRL_C_EVENT: // <CONTROL-C> (SIGINT) h = sigint_handle; break; case CTRL_BREAK_EVENT: // <CONTROL-Break> (SIGBREAK/SIGQUIT) case CTRL_CLOSE_EVENT: // User closed console or abort via task manager h = sigbreak_handle; break; case CTRL_LOGOFF_EVENT: // Logout/Shutdown (SIGTERM) case CTRL_SHUTDOWN_EVENT: h = sigterm_handle; break; } if (!h) return FALSE; // continue with next handler // Signal event if (!SetEvent(h)) return FALSE; return TRUE; } static void child_exit(void) { int i; char * cmdline; HANDLE rst; STARTUPINFO si; PROCESS_INFORMATION pi; for (i = 0; i < num_sig_handlers; i++) CloseHandle(sig_events[i]); num_sig_handlers = 0; CloseHandle(running_event); running_event = 0; // Restart? if (!(rst = open_event(EVT_RESTART))) return; // No => normal exit // Yes => Signal exit and restart process Sleep(500); SetEvent(rst); CloseHandle(rst); Sleep(500); cmdline = GetCommandLineA(); memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; if (!CreateProcessA( NULL, cmdline, NULL, NULL, TRUE/*inherit*/, 0, NULL, NULL, &si, &pi)) { fprintf(stderr, "CreateProcess(.,\"%s\",.) failed, Error=%ld\n", cmdline, GetLastError()); } CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } static int child_main(HANDLE hev,int (*main_func)(int, char **), int argc, char **argv) { // Keep EVT_RUNNING open until exit running_event = hev; // Install console handler SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); // Install restart handler atexit(child_exit); // Continue in main_func() to do the real work return main_func(argc, argv); } // Simulate signal() sigfunc_t daemon_signal(int sig, sigfunc_t func) { int i; HANDLE h; if (func == SIG_DFL || func == SIG_IGN) return func; // TODO for (i = 0; i < num_sig_handlers; i++) { if (sig_numbers[i] == sig) { sigfunc_t old = sig_handlers[i]; sig_handlers[i] = func; return old; } } if (num_sig_handlers >= MAX_SIG_HANDLERS) return SIG_ERR; if (!(h = create_event((!svc_mode ? sig : -1), FALSE, TRUE, NULL))) return SIG_ERR; sig_events[num_sig_handlers] = h; sig_numbers[num_sig_handlers] = sig; sig_handlers[num_sig_handlers] = func; switch (sig) { case SIGHUP: sighup_handle = h; break; case SIGINT: sigint_handle = h; break; case SIGTERM: sigterm_handle = h; break; case SIGBREAK: sigbreak_handle = h; break; case SIGUSR1: sigusr1_handle = h; break; } num_sig_handlers++; return SIG_DFL; } // strsignal() const char * daemon_strsignal(int sig) { switch (sig) { case SIGHUP: return "SIGHUP"; case SIGINT: return "SIGINT"; case SIGTERM: return "SIGTERM"; case SIGBREAK:return "SIGBREAK"; case SIGUSR1: return "SIGUSR1"; case SIGUSR2: return "SIGUSR2"; default: return "*UNKNOWN*"; } } // Simulate sleep() void daemon_sleep(int seconds) { do { if (num_sig_handlers <= 0) { Sleep(seconds*1000L); } else { // Wait for any signal or timeout DWORD rc = WaitForMultipleObjects(num_sig_handlers, sig_events, FALSE/*OR*/, seconds*1000L); if (rc != WAIT_TIMEOUT) { if (!(/*WAIT_OBJECT_0(0) <= rc && */ rc < WAIT_OBJECT_0+(unsigned)num_sig_handlers)) { fprintf(stderr,"WaitForMultipleObjects returns %lu\n", rc); Sleep(seconds*1000L); return; } // Call Handler sig_handlers[rc-WAIT_OBJECT_0](sig_numbers[rc-WAIT_OBJECT_0]); break; } } } while (svc_paused); } // Disable/Enable console void daemon_disable_console() { SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); reopen_stdin = reopen_stdout = reopen_stderr = 0; if (isatty(fileno(stdin))) { fclose(stdin); reopen_stdin = 1; } if (isatty(fileno(stdout))) { fclose(stdout); reopen_stdout = 1; } if (isatty(fileno(stderr))) { fclose(stderr); reopen_stderr = 1; } FreeConsole(); SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); } int daemon_enable_console(const char * title) { BOOL ok; SetConsoleCtrlHandler(child_console_handler, FALSE/*remove*/); ok = AllocConsole(); SetConsoleCtrlHandler(child_console_handler, TRUE/*add*/); if (!ok) return -1; if (title) SetConsoleTitleA(title); if (reopen_stdin) freopen("conin$", "r", stdin); if (reopen_stdout) freopen("conout$", "w", stdout); if (reopen_stderr) freopen("conout$", "w", stderr); reopen_stdin = reopen_stdout = reopen_stderr = 0; return 0; } // Detach daemon from console & parent int daemon_detach(const char * ident) { if (!svc_mode) { if (ident) { // Print help FILE * f = ( isatty(fileno(stdout)) ? stdout : isatty(fileno(stderr)) ? stderr : NULL); if (f) daemon_help(f, ident, "now detaches from console into background mode"); } // Signal detach to parent if (sig_event(EVT_DETACHED) != 1) { if (!debugging()) return -1; } daemon_disable_console(); } else { // Signal end of initialization to service control manager service_report_status(SERVICE_RUNNING, 0); reopen_stdin = reopen_stdout = reopen_stderr = 1; } return 0; } ///////////////////////////////////////////////////////////////////////////// // Spawn a command and redirect <inpbuf >outbuf // return command's exitcode or -1 on error int daemon_spawn(const char * cmd, const char * inpbuf, int inpsize, char * outbuf, int outsize ) { HANDLE self = GetCurrentProcess(); // Create stdin pipe with inheritable read side SECURITY_ATTRIBUTES sa; memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; HANDLE pipe_inp_r, pipe_inp_w, h; if (!CreatePipe(&pipe_inp_r, &h, &sa/*inherit*/, inpsize*2+13)) return -1; if (!DuplicateHandle(self, h, self, &pipe_inp_w, 0, FALSE/*!inherit*/, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) { CloseHandle(pipe_inp_r); return -1; } // Create stdout pipe with inheritable write side memset(&sa, 0, sizeof(sa)); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; HANDLE pipe_out_w; if (!CreatePipe(&h, &pipe_out_w, &sa/*inherit*/, outsize)) { CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } HANDLE pipe_out_r; if (!DuplicateHandle(self, h, self, &pipe_out_r, GENERIC_READ, FALSE/*!inherit*/, DUPLICATE_CLOSE_SOURCE)) { CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } // Create stderr handle as dup of stdout write side HANDLE pipe_err_w; if (!DuplicateHandle(self, pipe_out_w, self, &pipe_err_w, 0, TRUE/*inherit*/, DUPLICATE_SAME_ACCESS)) { CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } // Create process with pipes as stdio STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.hStdInput = pipe_inp_r; si.hStdOutput = pipe_out_w; si.hStdError = pipe_err_w; si.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION pi; if (!CreateProcessA( NULL, (char*)cmd, NULL, NULL, TRUE/*inherit*/, CREATE_NO_WINDOW, // DETACHED_PROCESS does not work NULL, NULL, &si, &pi)) { CloseHandle(pipe_err_w); CloseHandle(pipe_out_r); CloseHandle(pipe_out_w); CloseHandle(pipe_inp_r); CloseHandle(pipe_inp_w); return -1; } CloseHandle(pi.hThread); // Close inherited handles CloseHandle(pipe_inp_r); CloseHandle(pipe_out_w); CloseHandle(pipe_err_w); // Copy inpbuf to stdin // convert \n => \r\n DWORD num_io; int i; for (i = 0; i < inpsize; ) { int len = 0; while (i+len < inpsize && inpbuf[i+len] != '\n') len++; if (len > 0) WriteFile(pipe_inp_w, inpbuf+i, len, &num_io, NULL); i += len; if (i < inpsize) { WriteFile(pipe_inp_w, "\r\n", 2, &num_io, NULL); i++; } } CloseHandle(pipe_inp_w); // Copy stdout to output buffer until full, rest to /dev/null // convert \r\n => \n for (i = 0; ; ) { char buf[256]; if (!ReadFile(pipe_out_r, buf, sizeof(buf), &num_io, NULL) || num_io == 0) break; for (int j = 0; i < outsize-1 && j < (int)num_io; j++) { if (buf[j] != '\r') outbuf[i++] = buf[j]; } } outbuf[i] = 0; CloseHandle(pipe_out_r); // Wait for process exitcode DWORD exitcode = 42; WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); CloseHandle(pi.hProcess); return exitcode; } ///////////////////////////////////////////////////////////////////////////// // Initd Functions static int wait_signaled(HANDLE h, int seconds) { int i; for (i = 0; ; ) { if (WaitForSingleObject(h, 1000L) == WAIT_OBJECT_0) return 0; if (++i >= seconds) return -1; fputchar('.'); fflush(stdout); } } static int wait_evt_running(int seconds, int exists) { int i; if (event_exists(EVT_RUNNING) == exists) return 0; for (i = 0; ; ) { Sleep(1000); if (event_exists(EVT_RUNNING) == exists) return 0; if (++i >= seconds) return -1; fputchar('.'); fflush(stdout); } } static int is_initd_command(char * s) { if (!strcmp(s, "status")) return EVT_RUNNING; if (!strcmp(s, "stop")) return SIGTERM; if (!strcmp(s, "reload")) return SIGHUP; if (!strcmp(s, "sigusr1")) return SIGUSR1; if (!strcmp(s, "sigusr2")) return SIGUSR2; if (!strcmp(s, "restart")) return EVT_RESTART; return -1; } static int initd_main(const char * ident, int argc, char **argv) { int rc; if (argc < 2) return -1; if ((rc = is_initd_command(argv[1])) < 0) return -1; if (argc != 2) { printf("%s: no arguments allowed for command %s\n", ident, argv[1]); return 1; } switch (rc) { default: case EVT_RUNNING: printf("Checking for %s:", ident); fflush(stdout); rc = event_exists(EVT_RUNNING); puts(rc ? " running" : " not running"); return (rc ? 0 : 1); case SIGTERM: printf("Stopping %s:", ident); fflush(stdout); rc = sig_event(SIGTERM); if (rc <= 0) { puts(rc < 0 ? " not running" : " error"); return (rc < 0 ? 0 : 1); } rc = wait_evt_running(10, 0); puts(!rc ? " done" : " timeout"); return (!rc ? 0 : 1); case SIGHUP: printf("Reloading %s:", ident); fflush(stdout); rc = sig_event(SIGHUP); puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); return (rc > 0 ? 0 : 1); case SIGUSR1: case SIGUSR2: printf("Sending SIGUSR%d to %s:", (rc-SIGUSR1+1), ident); fflush(stdout); rc = sig_event(rc); puts(rc > 0 ? " done" : rc == 0 ? " error" : " not running"); return (rc > 0 ? 0 : 1); case EVT_RESTART: { HANDLE rst; printf("Stopping %s:", ident); fflush(stdout); if (event_exists(EVT_DETACHED)) { puts(" not detached, cannot restart"); return 1; } if (!(rst = create_event(EVT_RESTART, FALSE, FALSE, NULL))) { puts(" error"); return 1; } rc = sig_event(SIGTERM); if (rc <= 0) { puts(rc < 0 ? " not running" : " error"); CloseHandle(rst); return 1; } rc = wait_signaled(rst, 10); CloseHandle(rst); if (rc) { puts(" timeout"); return 1; } puts(" done"); Sleep(100); printf("Starting %s:", ident); fflush(stdout); rc = wait_evt_running(10, 1); puts(!rc ? " done" : " error"); return (!rc ? 0 : 1); } } } ///////////////////////////////////////////////////////////////////////////// // Windows Service Functions int daemon_winsvc_exitcode; // Set by app to exit(code) static SERVICE_STATUS_HANDLE svc_handle; static SERVICE_STATUS svc_status; // Report status to SCM static void service_report_status(int state, int seconds) { // TODO: Avoid race static DWORD checkpoint = 1; svc_status.dwCurrentState = state; svc_status.dwWaitHint = seconds*1000; switch (state) { default: svc_status.dwCheckPoint = checkpoint++; break; case SERVICE_RUNNING: case SERVICE_STOPPED: svc_status.dwCheckPoint = 0; } switch (state) { case SERVICE_START_PENDING: case SERVICE_STOP_PENDING: svc_status.dwControlsAccepted = 0; break; default: svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN| SERVICE_ACCEPT_PAUSE_CONTINUE|SERVICE_ACCEPT_PARAMCHANGE; break; } SetServiceStatus(svc_handle, &svc_status); } // Control the service, called by SCM static void WINAPI service_control(DWORD ctrlcode) { switch (ctrlcode) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: service_report_status(SERVICE_STOP_PENDING, 30); svc_paused = 0; SetEvent(sigterm_handle); break; case SERVICE_CONTROL_PARAMCHANGE: // Win2000/XP service_report_status(svc_status.dwCurrentState, 0); svc_paused = 0; SetEvent(sighup_handle); // reload break; case SERVICE_CONTROL_PAUSE: service_report_status(SERVICE_PAUSED, 0); svc_paused = 1; break; case SERVICE_CONTROL_CONTINUE: service_report_status(SERVICE_RUNNING, 0); { int was_paused = svc_paused; svc_paused = 0; SetEvent(was_paused ? sighup_handle : sigusr1_handle); // reload:recheck } break; case SERVICE_CONTROL_INTERROGATE: default: // unknown service_report_status(svc_status.dwCurrentState, 0); break; } } // Exit handler for service static void service_exit(void) { // Close signal events int i; for (i = 0; i < num_sig_handlers; i++) CloseHandle(sig_events[i]); num_sig_handlers = 0; // Set exitcode if (daemon_winsvc_exitcode) { svc_status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; svc_status.dwServiceSpecificExitCode = daemon_winsvc_exitcode; } // Report stopped service_report_status(SERVICE_STOPPED, 0); } // Variables for passing main(argc, argv) from daemon_main to service_main() static int (*svc_main_func)(int, char **); static int svc_main_argc; static char ** svc_main_argv; // Main function for service, called by service dispatcher static void WINAPI service_main(DWORD /*argc*/, LPSTR * argv) { char path[MAX_PATH], *p; // Register control handler svc_handle = RegisterServiceCtrlHandler(argv[0], service_control); // Init service status svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; service_report_status(SERVICE_START_PENDING, 10); // Service started in \windows\system32, change to .exe directory if (GetModuleFileNameA(NULL, path, sizeof(path)) && (p = strrchr(path, '\\'))) { *p = 0; SetCurrentDirectoryA(path); } // Install exit handler atexit(service_exit); // Do the real work, service status later updated by daemon_detach() daemon_winsvc_exitcode = svc_main_func(svc_main_argc, svc_main_argv); exit(daemon_winsvc_exitcode); // ... continued in service_exit() } ///////////////////////////////////////////////////////////////////////////// // Windows Service Admin Functions // Make registry key name for event message file static bool make_evtkey(char * buf, unsigned size, const char * ident) { static const char prefix[] = "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\"; const unsigned pfxlen = sizeof(prefix)-1; unsigned idlen = strlen(ident); if (pfxlen + idlen >= size) { printf(" Buffer overflow\n"); return false; } memcpy(buf, prefix, pfxlen); memcpy(buf+pfxlen, ident, idlen+1); return true; } // Install this exe as event message file static void inst_evtmsg(const char * ident) { printf("Installing event message file for %s:", ident); fflush(stdout); char mypath[MAX_PATH]; if (!GetModuleFileNameA((HMODULE)0, mypath, sizeof(mypath))) { printf(" unknown program path, Error=%ld\n", GetLastError()); return; } char subkey[MAX_PATH]; if (!make_evtkey(subkey, sizeof(subkey), ident)) return; HKEY hk; LONG err = RegCreateKeyExA(HKEY_LOCAL_MACHINE, subkey, 0, (char *)0, 0, KEY_ALL_ACCESS, (SECURITY_ATTRIBUTES *)0, &hk, (DWORD *)0); if (err != ERROR_SUCCESS) { printf(" RegCreateKeyEx failed, error=%ld\n", err); return; } err = RegSetValueExA(hk, "EventMessageFile", 0, REG_SZ, (const BYTE *)mypath, strlen(mypath)+1); if (err == ERROR_SUCCESS) { DWORD val = EVENTLOG_INFORMATION_TYPE |EVENTLOG_WARNING_TYPE |EVENTLOG_ERROR_TYPE; err = RegSetValueExA(hk, "TypesSupported", 0, REG_DWORD, (const BYTE *)&val, sizeof(val)); } if (err != ERROR_SUCCESS) printf(" RegSetValueEx failed, error=%ld\n", err); RegCloseKey(hk); puts(" done"); } // Uninstall event message file static void uninst_evtmsg(const char * ident) { printf("Removing event message file for %s:", ident); fflush(stdout); char subkey[MAX_PATH]; if (!make_evtkey(subkey, sizeof(subkey), ident)) return; LONG err = RegDeleteKeyA(HKEY_LOCAL_MACHINE, subkey); if (err != ERROR_SUCCESS && err != ERROR_FILE_NOT_FOUND) { printf(" RegDeleteKey failed, error=%ld\n", err); return; } puts(" done"); } // Service install/remove commands static int svcadm_main(const char * ident, const daemon_winsvc_options * svc_opts, int argc, char **argv ) { int remove; long err; SC_HANDLE hm, hs; if (argc < 2) return -1; if (!strcmp(argv[1], "install")) remove = 0; else if (!strcmp(argv[1], "remove")) { if (argc != 2) { printf("%s: no arguments allowed for command remove\n", ident); return 1; } remove = 1; } else return -1; printf("%s service %s:", (!remove?"Installing":"Removing"), ident); fflush(stdout); // Open SCM if (!(hm = OpenSCManager(NULL/*local*/, NULL/*default*/, SC_MANAGER_ALL_ACCESS))) { if ((err = GetLastError()) == ERROR_ACCESS_DENIED) puts(" access to SCManager denied"); else printf(" cannot open SCManager, Error=%ld\n", err); return 1; } if (!remove) { char path[MAX_PATH+100]; int i; // Get program path if (!GetModuleFileNameA(NULL, path, MAX_PATH)) { printf(" unknown program path, Error=%ld\n", GetLastError()); CloseServiceHandle(hm); return 1; } // Add quotes if necessary if (strchr(path, ' ')) { i = strlen(path); path[i+1] = '"'; path[i+2] = 0; while (--i >= 0) path[i+1] = path[i]; path[0] = '"'; } // Append options strcat(path, " "); strcat(path, svc_opts->cmd_opt); for (i = 2; i < argc; i++) { const char * s = argv[i]; if (strlen(path)+1+1+strlen(s)+1 >= sizeof(path)) break; // Add quotes if necessary if (strchr(s, ' ') && !strchr(s, '"')) { strcat(path, " \""); strcat(path, s); strcat(path, "\""); } else { strcat(path, " "); strcat(path, s); } } // Create if (!(hs = CreateService(hm, svc_opts->svcname, svc_opts->dispname, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, path, NULL/*no load ordering*/, NULL/*no tag id*/, ""/*no depedencies*/, NULL/*local system account*/, NULL/*no pw*/))) { if ((err = GetLastError()) == ERROR_SERVICE_EXISTS) puts(" the service is already installed"); else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) puts(" service is still running and marked for deletion\n" "Stop the service and retry install"); else printf(" failed, Error=%ld\n", err); CloseServiceHandle(hm); return 1; } // Set optional description if (svc_opts->descript) { SERVICE_DESCRIPTIONA sd = { const_cast<char *>(svc_opts->descript) }; ChangeServiceConfig2A(hs, SERVICE_CONFIG_DESCRIPTION, &sd); } // Enable delayed auto start if supported OSVERSIONINFOA ver; ver.dwOSVersionInfoSize = sizeof(ver); if ( GetVersionExA(&ver) && ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 6 /* Vista */ ) { SERVICE_DELAYED_AUTO_START_INFO sdasi = { TRUE }; ChangeServiceConfig2A(hs, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &sdasi); } } else { // Open if (!(hs = OpenService(hm, svc_opts->svcname, SERVICE_ALL_ACCESS))) { puts(" not found"); CloseServiceHandle(hm); return 1; } // TODO: Stop service if running // Remove if (!DeleteService(hs)) { if ((err = GetLastError()) == ERROR_SERVICE_MARKED_FOR_DELETE) puts(" service is still running and marked for deletion\n" "Stop the service to remove it"); else printf(" failed, Error=%ld\n", err); CloseServiceHandle(hs); CloseServiceHandle(hm); return 1; } } puts(" done"); CloseServiceHandle(hs); CloseServiceHandle(hm); // Install/Remove event message file registry entry if (!remove) { inst_evtmsg(ident); } else { uninst_evtmsg(ident); } return 0; } ///////////////////////////////////////////////////////////////////////////// // Main Function // This function must be called from main() // main_func is the function doing the real work int daemon_main(const char * ident, const daemon_winsvc_options * svc_opts, int (*main_func)(int, char **), int argc, char **argv ) { int rc; #ifdef _DEBUG // Enable Debug heap checks _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) |_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_LEAK_CHECK_DF); #endif // Check for [status|stop|reload|restart|sigusr1|sigusr2] parameters if ((rc = initd_main(ident, argc, argv)) >= 0) return rc; // Check for [install|remove] parameters if (svc_opts && (rc = svcadm_main(ident, svc_opts, argc, argv)) >= 0) return rc; // Run as service if svc_opts.cmd_opt is given as first(!) argument svc_mode = (svc_opts && argc >= 2 && !strcmp(argv[1], svc_opts->cmd_opt)); if (!svc_mode) { // Daemon: Try to simulate a Unix-like daemon HANDLE rev; BOOL exists; // Create main event to detect process type: // 1. new: parent process => start child and wait for detach() or exit() of child. // 2. exists && signaled: child process => do the real work, signal detach() to parent // 3. exists && !signaled: already running => exit() if (!(rev = create_event(EVT_RUNNING, TRUE/*signaled*/, TRUE, &exists))) return 100; if (!exists && !debugging()) { // Event new => parent process return parent_main(rev); } if (WaitForSingleObject(rev, 0) == WAIT_OBJECT_0) { // Event was signaled => In child process return child_main(rev, main_func, argc, argv); } // Event no longer signaled => Already running! daemon_help(stdout, ident, "already running"); CloseHandle(rev); return 1; } else { // Service: Start service_main() via SCM SERVICE_TABLE_ENTRY service_table[] = { { (char*)svc_opts->svcname, service_main }, { NULL, NULL } }; svc_main_func = main_func; svc_main_argc = argc; svc_main_argv = argv; if (!StartServiceCtrlDispatcher(service_table)) { printf("%s: cannot dispatch service, Error=%ld\n" "Option \"%s\" cannot be used to start %s as a service from console.\n" "Use \"%s install ...\" to install the service\n" "and \"net start %s\" to start it.\n", ident, GetLastError(), svc_opts->cmd_opt, ident, ident, ident); #ifdef _DEBUG if (debugging()) service_main(argc, argv); #endif return 100; } Sleep(1000); ExitThread(0); // Do not redo exit() processing /*NOTREACHED*/ return 0; } } ///////////////////////////////////////////////////////////////////////////// // Test Program #ifdef TEST static volatile sig_atomic_t caughtsig = 0; static void sig_handler(int sig) { caughtsig = sig; } static void test_exit(void) { printf("Main exit\n"); } int test_main(int argc, char **argv) { int i; int debug = 0; char * cmd = 0; printf("PID=%ld\n", GetCurrentProcessId()); for (i = 0; i < argc; i++) { printf("%d: \"%s\"\n", i, argv[i]); if (!strcmp(argv[i],"-d")) debug = 1; } if (argc > 1 && argv[argc-1][0] != '-') cmd = argv[argc-1]; daemon_signal(SIGINT, sig_handler); daemon_signal(SIGBREAK, sig_handler); daemon_signal(SIGTERM, sig_handler); daemon_signal(SIGHUP, sig_handler); daemon_signal(SIGUSR1, sig_handler); daemon_signal(SIGUSR2, sig_handler); atexit(test_exit); if (!debug) { printf("Preparing to detach...\n"); Sleep(2000); daemon_detach("test"); printf("Detached!\n"); } for (;;) { daemon_sleep(1); printf("."); fflush(stdout); if (caughtsig) { if (caughtsig == SIGUSR2) { debug ^= 1; if (debug) daemon_enable_console("Daemon[Debug]"); else daemon_disable_console(); } else if (caughtsig == SIGUSR1 && cmd) { char inpbuf[200], outbuf[1000]; int rc; strcpy(inpbuf, "Hello\nWorld!\n"); rc = daemon_spawn(cmd, inpbuf, strlen(inpbuf), outbuf, sizeof(outbuf)); if (!debug) daemon_enable_console("Command output"); printf("\"%s\" returns %d\n", cmd, rc); if (rc >= 0) printf("output:\n%s.\n", outbuf); fflush(stdout); if (!debug) { Sleep(10000); daemon_disable_console(); } } printf("[PID=%ld: Signal=%d]", GetCurrentProcessId(), caughtsig); fflush(stdout); if (caughtsig == SIGTERM || caughtsig == SIGBREAK) break; caughtsig = 0; } } printf("\nExiting on signal %d\n", caughtsig); return 0; } int main(int argc, char **argv) { static const daemon_winsvc_options svc_opts = { "-s", "test", "Test Service", "Service to test daemon_win32.c Module" }; return daemon_main("testd", &svc_opts, test_main, argc, argv); } #endif ���������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/�������������������������������������������������������0000755�0000000�0000000�00000000000�12212065524�017274� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/smartctl.vcxproj���������������������������������������0000644�0000000�0000000�00000041247�12101000543�022535� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release|Win32"> <Configuration>Release</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{3AFEDCDD-D289-4543-A91D-EFBA6C710247}</ProjectGuid> <RootNamespace>smartctl</RootNamespace> <Keyword>Win32Proj</Keyword> <ProjectName>smartctl</ProjectName> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> <WholeProgramOptimization>true</WholeProgramOptimization> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup> <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\$(ProjectName).tmp\</IntDir> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\$(ProjectName).tmp\</IntDir> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>.;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_DEBUG;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <PrecompiledHeader> </PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DisableSpecificWarnings>4250</DisableSpecificWarnings> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <TargetMachine>MachineX86</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <AdditionalIncludeDirectories>.;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>NDEBUG;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <PrecompiledHeader> </PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DisableSpecificWarnings>4250</DisableSpecificWarnings> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <OptimizeReferences>true</OptimizeReferences> <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineX86</TargetMachine> </Link> </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\ataidentify.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" /> <ClCompile Include="..\daemon_win32.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\syslog_win32.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\wmiquery.cpp" /> <ClCompile Include="..\..\regex\regcomp.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\regex\regex.c" /> <ClCompile Include="..\..\regex\regex_internal.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\regex\regexec.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\getopt\getopt.c" /> <ClCompile Include="..\..\getopt\getopt1.c" /> <ClCompile Include="..\..\atacmdnames.cpp" /> <ClCompile Include="..\..\atacmds.cpp" /> <ClCompile Include="..\..\ataprint.cpp" /> <ClCompile Include="..\..\cciss.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\dev_ata_cmd_set.cpp" /> <ClCompile Include="..\..\dev_interface.cpp" /> <ClCompile Include="..\..\dev_legacy.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\knowndrives.cpp" /> <ClCompile Include="..\..\os_darwin.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_freebsd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_generic.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_linux.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_netbsd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_openbsd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_os2.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_qnxnto.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_solaris.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_win32.cpp" /> <ClCompile Include="..\..\scsiata.cpp" /> <ClCompile Include="..\..\scsicmds.cpp" /> <ClCompile Include="..\..\scsiprint.cpp" /> <ClCompile Include="..\..\smartctl.cpp" /> <ClCompile Include="..\..\smartd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\utility.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\ataidentify.h" /> <ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="config.h" /> <ClInclude Include="svnversion.h" /> <CustomBuildStep Include="..\daemon_win32.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\syslog.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <ClInclude Include="..\wbemcli_small.h" /> <ClInclude Include="..\wmiquery.h" /> <ClInclude Include="..\..\regex\regex.h" /> <ClInclude Include="..\..\regex\regex_internal.h" /> <ClInclude Include="..\..\getopt\getopt.h" /> <ClInclude Include="..\..\atacmdnames.h" /> <ClInclude Include="..\..\atacmds.h" /> <ClInclude Include="..\..\ataprint.h" /> <CustomBuildStep Include="..\..\cciss.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <ClInclude Include="..\..\cissio_freebsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClInclude> <ClInclude Include="..\..\csmisas.h" /> <ClInclude Include="..\..\dev_ata_cmd_set.h" /> <ClInclude Include="..\..\dev_interface.h" /> <ClInclude Include="..\..\dev_tunnelled.h" /> <ClInclude Include="..\..\drivedb.h" /> <ClInclude Include="..\..\int64.h" /> <ClInclude Include="..\..\knowndrives.h" /> <CustomBuildStep Include="..\..\megaraid.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_darwin.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_freebsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_generic.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_linux.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_netbsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_openbsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_os2.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_qnxnto.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_solaris.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <ClInclude Include="..\..\scsicmds.h" /> <ClInclude Include="..\..\scsiprint.h" /> <ClInclude Include="..\..\smartctl.h" /> <ClInclude Include="..\..\utility.h" /> </ItemGroup> <ItemGroup> <None Include="..\..\smartd_warning.sh.in" /> <None Include="..\installer.nsi" /> <None Include="..\smartctl_res.rc.in" /> <None Include="..\smartd_res.rc.in" /> <None Include="..\smartd_warning.cmd" /> <None Include="..\syslogevt.mc" /> <None Include="..\update-smart-drivedb.nsi" /> <None Include="..\..\AUTHORS" /> <None Include="..\..\autogen.sh" /> <None Include="..\..\ChangeLog" /> <None Include="..\..\config.h.in" /> <None Include="..\..\configure.ac" /> <None Include="..\..\do_release" /> <None Include="..\..\Doxyfile" /> <None Include="..\..\INSTALL" /> <None Include="..\..\Makefile.am" /> <None Include="..\..\NEWS" /> <None Include="..\..\README" /> <None Include="..\..\smartctl.8.in" /> <None Include="..\..\smartd.8.in" /> <None Include="..\..\smartd.conf.5.in" /> <None Include="..\..\smartd.initd.in" /> <None Include="..\..\TODO" /> <None Include="..\..\update-smart-drivedb.in" /> <None Include="..\..\WARNINGS" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="smartctl_res.rc" /> <ResourceCompile Include="smartd_res.rc"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ResourceCompile> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/wtssendmsg.vcxproj�������������������������������������0000644�0000000�0000000�00000007766�12054173447�023137� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release|Win32"> <Configuration>Release</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> </ItemGroup> <ItemGroup> <ClCompile Include="..\wtssendmsg.c" /> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{0B6B7D19-07AE-41DD-B70E-2F74362A4EC0}</ProjectGuid> <Keyword>Win32Proj</Keyword> <RootNamespace>wtssendmsg</RootNamespace> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <LinkIncremental>true</LinkIncremental> <IntDir>$(Configuration)\$(ProjectName).tmp\</IntDir> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <LinkIncremental>false</LinkIncremental> <IntDir>$(Configuration)\$(ProjectName).tmp\</IntDir> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>_DEBUG;_CRT_NONSTDC_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> <AdditionalDependencies>wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>NDEBUG;_CRT_NONSTDC_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> <AdditionalDependencies>wtsapi32.lib;%(AdditionalDependencies)</AdditionalDependencies> </Link> </ItemDefinitionGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project>����������smartmontools-6.2+svn3841.orig/os_win32/vc10/smartmontools.sln��������������������������������������0000644�0000000�0000000�00000004237�12101043146�022732� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� Microsoft Visual Studio Solution File, Format Version 11.00 # Visual C++ Express 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "smartctl", "smartctl.vcxproj", "{3AFEDCDD-D289-4543-A91D-EFBA6C710247}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "smartd", "smartd.vcxproj", "{C0762191-C2AC-40B6-A2EB-F1658BBDC4C6}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runcmd", "runcmd.vcxproj", "{11A4B619-D97B-499F-AF17-CF9F80BF70E8}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wtssendmsg", "wtssendmsg.vcxproj", "{0B6B7D19-07AE-41DD-B70E-2F74362A4EC0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {3AFEDCDD-D289-4543-A91D-EFBA6C710247}.Debug|Win32.ActiveCfg = Debug|Win32 {3AFEDCDD-D289-4543-A91D-EFBA6C710247}.Debug|Win32.Build.0 = Debug|Win32 {3AFEDCDD-D289-4543-A91D-EFBA6C710247}.Release|Win32.ActiveCfg = Release|Win32 {3AFEDCDD-D289-4543-A91D-EFBA6C710247}.Release|Win32.Build.0 = Release|Win32 {C0762191-C2AC-40B6-A2EB-F1658BBDC4C6}.Debug|Win32.ActiveCfg = Debug|Win32 {C0762191-C2AC-40B6-A2EB-F1658BBDC4C6}.Debug|Win32.Build.0 = Debug|Win32 {C0762191-C2AC-40B6-A2EB-F1658BBDC4C6}.Release|Win32.ActiveCfg = Release|Win32 {C0762191-C2AC-40B6-A2EB-F1658BBDC4C6}.Release|Win32.Build.0 = Release|Win32 {11A4B619-D97B-499F-AF17-CF9F80BF70E8}.Debug|Win32.ActiveCfg = Debug|Win32 {11A4B619-D97B-499F-AF17-CF9F80BF70E8}.Debug|Win32.Build.0 = Debug|Win32 {11A4B619-D97B-499F-AF17-CF9F80BF70E8}.Release|Win32.ActiveCfg = Release|Win32 {11A4B619-D97B-499F-AF17-CF9F80BF70E8}.Release|Win32.Build.0 = Release|Win32 {0B6B7D19-07AE-41DD-B70E-2F74362A4EC0}.Debug|Win32.ActiveCfg = Debug|Win32 {0B6B7D19-07AE-41DD-B70E-2F74362A4EC0}.Debug|Win32.Build.0 = Debug|Win32 {0B6B7D19-07AE-41DD-B70E-2F74362A4EC0}.Release|Win32.ActiveCfg = Release|Win32 {0B6B7D19-07AE-41DD-B70E-2F74362A4EC0}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/runcmd.vcxproj�����������������������������������������0000644�0000000�0000000�00000007614�12053764771�022226� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release|Win32"> <Configuration>Release</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{11A4B619-D97B-499F-AF17-CF9F80BF70E8}</ProjectGuid> <Keyword>Win32Proj</Keyword> <RootNamespace>runcmd</RootNamespace> <ProjectName>runcmd</ProjectName> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>true</UseDebugLibraries> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <UseDebugLibraries>false</UseDebugLibraries> <WholeProgramOptimization>true</WholeProgramOptimization> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <LinkIncremental>true</LinkIncremental> <IntDir>$(Configuration)\$(ProjectName).tmp\</IntDir> <TargetName>$(ProjectName)u</TargetName> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <LinkIncremental>false</LinkIncremental> <IntDir>$(Configuration)\$(ProjectName).tmp\</IntDir> <TargetName>$(ProjectName)u</TargetName> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> <Optimization>Disabled</Optimization> <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <WarningLevel>Level3</WarningLevel> <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> </ClCompile> <Link> <SubSystem>Console</SubSystem> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> <OptimizeReferences>true</OptimizeReferences> </Link> </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\runcmd.c" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project>��������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/smartd.vcxproj�����������������������������������������0000644�0000000�0000000�00000044717�12101000543�022203� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup Label="ProjectConfigurations"> <ProjectConfiguration Include="Debug|Win32"> <Configuration>Debug</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> <ProjectConfiguration Include="Release|Win32"> <Configuration>Release</Configuration> <Platform>Win32</Platform> </ProjectConfiguration> </ItemGroup> <PropertyGroup Label="Globals"> <ProjectGuid>{C0762191-C2AC-40B6-A2EB-F1658BBDC4C6}</ProjectGuid> <RootNamespace>smartd</RootNamespace> <Keyword>Win32Proj</Keyword> <ProjectName>smartd</ProjectName> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> <WholeProgramOptimization>true</WholeProgramOptimization> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <ConfigurationType>Application</ConfigurationType> <CharacterSet>MultiByte</CharacterSet> </PropertyGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <ImportGroup Label="ExtensionSettings"> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> </ImportGroup> <PropertyGroup Label="UserMacros" /> <PropertyGroup> <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion> <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\$(ProjectName).tmp\</IntDir> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental> <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Configuration)\$(ProjectName).tmp\</IntDir> <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental> </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <Optimization>Disabled</Optimization> <AdditionalIncludeDirectories>.;..;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>_DEBUG;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <MinimalRebuild>true</MinimalRebuild> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> <PrecompiledHeader> </PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DisableSpecificWarnings>4250</DisableSpecificWarnings> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <TargetMachine>MachineX86</TargetMachine> </Link> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <AdditionalIncludeDirectories>.;..;..\..\getopt;..\..\regex;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <PreprocessorDefinitions>NDEBUG;HAVE_CONFIG_H;_USE_32BIT_TIME_T;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> <PrecompiledHeader> </PrecompiledHeader> <WarningLevel>Level3</WarningLevel> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DisableSpecificWarnings>4250</DisableSpecificWarnings> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <SubSystem>Console</SubSystem> <OptimizeReferences>true</OptimizeReferences> <EnableCOMDATFolding>true</EnableCOMDATFolding> <TargetMachine>MachineX86</TargetMachine> </Link> </ItemDefinitionGroup> <ItemGroup> <ClCompile Include="..\..\ataidentify.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\dev_areca.cpp" /> <ClCompile Include="..\daemon_win32.cpp" /> <ClCompile Include="..\syslog_win32.cpp" /> <ClCompile Include="..\wmiquery.cpp" /> <ClCompile Include="..\..\regex\regcomp.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\regex\regex.c" /> <ClCompile Include="..\..\regex\regex_internal.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\regex\regexec.c"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\getopt\getopt.c" /> <ClCompile Include="..\..\getopt\getopt1.c" /> <ClCompile Include="..\..\atacmdnames.cpp" /> <ClCompile Include="..\..\atacmds.cpp" /> <ClCompile Include="..\..\ataprint.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\cciss.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\dev_ata_cmd_set.cpp" /> <ClCompile Include="..\..\dev_interface.cpp" /> <ClCompile Include="..\..\dev_legacy.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\knowndrives.cpp" /> <ClCompile Include="..\..\os_darwin.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_freebsd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_generic.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_linux.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_netbsd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_openbsd.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_os2.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_qnxnto.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_solaris.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\os_win32.cpp" /> <ClCompile Include="..\..\scsiata.cpp" /> <ClCompile Include="..\..\scsicmds.cpp" /> <ClCompile Include="..\..\scsiprint.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\smartctl.cpp"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClCompile> <ClCompile Include="..\..\smartd.cpp" /> <ClCompile Include="..\..\utility.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\..\ataidentify.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClInclude> <ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="..\daemon_win32.h" /> <ClInclude Include="..\syslog.h" /> <ClInclude Include="..\wbemcli_small.h" /> <ClInclude Include="..\wmiquery.h" /> <ClInclude Include="..\..\regex\regex.h" /> <ClInclude Include="..\..\regex\regex_internal.h" /> <ClInclude Include="..\..\getopt\getopt.h" /> <ClInclude Include="..\..\atacmdnames.h" /> <ClInclude Include="..\..\atacmds.h" /> <ClInclude Include="config.h" /> <ClInclude Include="svnversion.h" /> <CustomBuildStep Include="..\..\ataprint.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\cciss.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <ClInclude Include="..\..\cissio_freebsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ClInclude> <ClInclude Include="..\..\csmisas.h" /> <ClInclude Include="..\..\dev_ata_cmd_set.h" /> <ClInclude Include="..\..\dev_interface.h" /> <ClInclude Include="..\..\dev_tunnelled.h" /> <ClInclude Include="..\..\drivedb.h" /> <ClInclude Include="..\..\int64.h" /> <ClInclude Include="..\..\knowndrives.h" /> <CustomBuildStep Include="..\..\megaraid.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_darwin.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_freebsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_generic.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_linux.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_netbsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_openbsd.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_os2.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_qnxnto.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\os_solaris.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <ClInclude Include="..\..\scsicmds.h" /> <CustomBuildStep Include="..\..\scsiprint.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <CustomBuildStep Include="..\..\smartctl.h"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </CustomBuildStep> <ClInclude Include="..\..\utility.h" /> </ItemGroup> <ItemGroup> <None Include="..\..\smartd_warning.sh.in" /> <None Include="..\installer.nsi" /> <None Include="..\smartctl_res.rc.in" /> <None Include="..\smartd_res.rc.in" /> <None Include="..\smartd_warning.cmd" /> <CustomBuild Include="..\syslogevt.mc"> <FileType>Document</FileType> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc -r $(IntDir) ..\syslogevt.mc</Command> <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc -r $(IntDir) ..\syslogevt.mc</Message> <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)syslogevt.rc;$(IntDir)msg00001.bin;syslogevt.h;%(Outputs)</Outputs> <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc -r $(IntDir) ..\syslogevt.mc</Command> <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc -r $(IntDir) ..\syslogevt.mc</Message> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)syslogevt.rc;$(IntDir)msg00001.bin;syslogevt.h;%(Outputs)</Outputs> </CustomBuild> <None Include="..\update-smart-drivedb.nsi" /> <None Include="..\..\AUTHORS" /> <None Include="..\..\autogen.sh" /> <None Include="..\..\ChangeLog" /> <None Include="..\..\config.h.in" /> <None Include="..\..\configure.ac" /> <None Include="..\..\do_release" /> <None Include="..\..\Doxyfile" /> <None Include="..\..\INSTALL" /> <None Include="..\..\Makefile.am" /> <None Include="..\..\NEWS" /> <None Include="..\..\README" /> <None Include="..\..\smartctl.8.in" /> <None Include="..\..\smartd.8.in" /> <None Include="..\..\smartd.conf.5.in" /> <None Include="..\..\smartd.initd.in" /> <None Include="..\..\TODO" /> <None Include="..\..\update-smart-drivedb.in" /> <None Include="..\..\WARNINGS" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="smartctl_res.rc"> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> </ResourceCompile> <ResourceCompile Include="smartd_res.rc"> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)</AdditionalIncludeDirectories> </ResourceCompile> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> </Project>�������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/smartctl.vcxproj.filters�������������������������������0000644�0000000�0000000�00000014401�12101000543�024174� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="os_win32"> <UniqueIdentifier>{9321e988-dd03-496d-9933-7c8b235a46bf}</UniqueIdentifier> </Filter> <Filter Include="regex"> <UniqueIdentifier>{bfbfd4ea-fae3-45ec-9cfb-c5424218c47c}</UniqueIdentifier> </Filter> <Filter Include="getopt"> <UniqueIdentifier>{8ff0bf5f-c96e-45c3-bcb4-7450cecfa0d4}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="..\daemon_win32.cpp"> <Filter>os_win32</Filter> </ClCompile> <ClCompile Include="..\syslog_win32.cpp"> <Filter>os_win32</Filter> </ClCompile> <ClCompile Include="..\wmiquery.cpp"> <Filter>os_win32</Filter> </ClCompile> <ClCompile Include="..\..\regex\regcomp.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\regex\regex.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\regex\regex_internal.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\regex\regexec.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\getopt\getopt.c"> <Filter>getopt</Filter> </ClCompile> <ClCompile Include="..\..\getopt\getopt1.c"> <Filter>getopt</Filter> </ClCompile> <ClCompile Include="..\..\atacmdnames.cpp" /> <ClCompile Include="..\..\atacmds.cpp" /> <ClCompile Include="..\..\ataprint.cpp" /> <ClCompile Include="..\..\cciss.cpp" /> <ClCompile Include="..\..\dev_ata_cmd_set.cpp" /> <ClCompile Include="..\..\dev_interface.cpp" /> <ClCompile Include="..\..\dev_legacy.cpp" /> <ClCompile Include="..\..\knowndrives.cpp" /> <ClCompile Include="..\..\os_darwin.cpp" /> <ClCompile Include="..\..\os_freebsd.cpp" /> <ClCompile Include="..\..\os_generic.cpp" /> <ClCompile Include="..\..\os_linux.cpp" /> <ClCompile Include="..\..\os_netbsd.cpp" /> <ClCompile Include="..\..\os_openbsd.cpp" /> <ClCompile Include="..\..\os_os2.cpp" /> <ClCompile Include="..\..\os_qnxnto.cpp" /> <ClCompile Include="..\..\os_solaris.cpp" /> <ClCompile Include="..\..\os_win32.cpp" /> <ClCompile Include="..\..\scsiata.cpp" /> <ClCompile Include="..\..\scsicmds.cpp" /> <ClCompile Include="..\..\scsiprint.cpp" /> <ClCompile Include="..\..\smartctl.cpp" /> <ClCompile Include="..\..\smartd.cpp" /> <ClCompile Include="..\..\utility.cpp" /> <ClCompile Include="..\..\ataidentify.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\wbemcli_small.h"> <Filter>os_win32</Filter> </ClInclude> <ClInclude Include="..\wmiquery.h"> <Filter>os_win32</Filter> </ClInclude> <ClInclude Include="..\..\regex\regex.h"> <Filter>regex</Filter> </ClInclude> <ClInclude Include="..\..\regex\regex_internal.h"> <Filter>regex</Filter> </ClInclude> <ClInclude Include="..\..\getopt\getopt.h"> <Filter>getopt</Filter> </ClInclude> <ClInclude Include="..\..\atacmdnames.h" /> <ClInclude Include="..\..\atacmds.h" /> <ClInclude Include="..\..\ataprint.h" /> <ClInclude Include="..\..\cissio_freebsd.h" /> <ClInclude Include="..\..\csmisas.h" /> <ClInclude Include="..\..\dev_ata_cmd_set.h" /> <ClInclude Include="..\..\dev_interface.h" /> <ClInclude Include="..\..\dev_tunnelled.h" /> <ClInclude Include="..\..\drivedb.h" /> <ClInclude Include="..\..\int64.h" /> <ClInclude Include="..\..\knowndrives.h" /> <ClInclude Include="..\..\scsicmds.h" /> <ClInclude Include="..\..\scsiprint.h" /> <ClInclude Include="..\..\smartctl.h" /> <ClInclude Include="..\..\utility.h" /> <ClInclude Include="..\..\ataidentify.h" /> <ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="config.h" /> <ClInclude Include="svnversion.h" /> </ItemGroup> <ItemGroup> <None Include="..\installer.nsi"> <Filter>os_win32</Filter> </None> <None Include="..\update-smart-drivedb.nsi"> <Filter>os_win32</Filter> </None> <None Include="..\..\AUTHORS" /> <None Include="..\..\autogen.sh" /> <None Include="..\..\ChangeLog" /> <None Include="..\..\config.h.in" /> <None Include="..\..\configure.ac" /> <None Include="..\..\do_release" /> <None Include="..\..\Doxyfile" /> <None Include="..\..\INSTALL" /> <None Include="..\..\Makefile.am" /> <None Include="..\..\NEWS" /> <None Include="..\..\README" /> <None Include="..\..\smartctl.8.in" /> <None Include="..\..\smartd.8.in" /> <None Include="..\..\smartd.conf.5.in" /> <None Include="..\..\smartd.initd.in" /> <None Include="..\..\TODO" /> <None Include="..\..\update-smart-drivedb.in" /> <None Include="..\..\WARNINGS" /> <None Include="..\smartd_warning.cmd"> <Filter>os_win32</Filter> </None> <None Include="..\..\smartd_warning.sh.in" /> <None Include="..\smartctl_res.rc.in"> <Filter>os_win32</Filter> </None> <None Include="..\smartd_res.rc.in"> <Filter>os_win32</Filter> </None> <None Include="..\syslogevt.mc"> <Filter>os_win32</Filter> </None> </ItemGroup> <ItemGroup> <CustomBuildStep Include="..\daemon_win32.h"> <Filter>os_win32</Filter> </CustomBuildStep> <CustomBuildStep Include="..\syslog.h"> <Filter>os_win32</Filter> </CustomBuildStep> <CustomBuildStep Include="..\..\cciss.h" /> <CustomBuildStep Include="..\..\megaraid.h" /> <CustomBuildStep Include="..\..\os_darwin.h" /> <CustomBuildStep Include="..\..\os_freebsd.h" /> <CustomBuildStep Include="..\..\os_generic.h" /> <CustomBuildStep Include="..\..\os_linux.h" /> <CustomBuildStep Include="..\..\os_netbsd.h" /> <CustomBuildStep Include="..\..\os_openbsd.h" /> <CustomBuildStep Include="..\..\os_os2.h" /> <CustomBuildStep Include="..\..\os_qnxnto.h" /> <CustomBuildStep Include="..\..\os_solaris.h" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="smartctl_res.rc"> <Filter>os_win32</Filter> </ResourceCompile> <ResourceCompile Include="smartd_res.rc"> <Filter>os_win32</Filter> </ResourceCompile> </ItemGroup> </Project>���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/vc10/smartd.vcxproj.filters���������������������������������0000644�0000000�0000000�00000014446�12101000543�023646� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="os_win32"> <UniqueIdentifier>{44bb110e-4d44-4d5e-8186-354210a8d3ba}</UniqueIdentifier> </Filter> <Filter Include="regex"> <UniqueIdentifier>{fd3bb1d5-a72e-4f92-84a3-6eac97975ec7}</UniqueIdentifier> </Filter> <Filter Include="getopt"> <UniqueIdentifier>{1d1b67d5-219f-4e86-a5ff-9d94f1f751f9}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="..\daemon_win32.cpp"> <Filter>os_win32</Filter> </ClCompile> <ClCompile Include="..\syslog_win32.cpp"> <Filter>os_win32</Filter> </ClCompile> <ClCompile Include="..\wmiquery.cpp"> <Filter>os_win32</Filter> </ClCompile> <ClCompile Include="..\..\regex\regcomp.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\regex\regex.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\regex\regex_internal.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\regex\regexec.c"> <Filter>regex</Filter> </ClCompile> <ClCompile Include="..\..\getopt\getopt.c"> <Filter>getopt</Filter> </ClCompile> <ClCompile Include="..\..\getopt\getopt1.c"> <Filter>getopt</Filter> </ClCompile> <ClCompile Include="..\..\atacmdnames.cpp" /> <ClCompile Include="..\..\atacmds.cpp" /> <ClCompile Include="..\..\ataprint.cpp" /> <ClCompile Include="..\..\cciss.cpp" /> <ClCompile Include="..\..\dev_ata_cmd_set.cpp" /> <ClCompile Include="..\..\dev_interface.cpp" /> <ClCompile Include="..\..\dev_legacy.cpp" /> <ClCompile Include="..\..\knowndrives.cpp" /> <ClCompile Include="..\..\os_darwin.cpp" /> <ClCompile Include="..\..\os_freebsd.cpp" /> <ClCompile Include="..\..\os_generic.cpp" /> <ClCompile Include="..\..\os_linux.cpp" /> <ClCompile Include="..\..\os_netbsd.cpp" /> <ClCompile Include="..\..\os_openbsd.cpp" /> <ClCompile Include="..\..\os_os2.cpp" /> <ClCompile Include="..\..\os_qnxnto.cpp" /> <ClCompile Include="..\..\os_solaris.cpp" /> <ClCompile Include="..\..\os_win32.cpp" /> <ClCompile Include="..\..\scsiata.cpp" /> <ClCompile Include="..\..\scsicmds.cpp" /> <ClCompile Include="..\..\scsiprint.cpp" /> <ClCompile Include="..\..\smartctl.cpp" /> <ClCompile Include="..\..\smartd.cpp" /> <ClCompile Include="..\..\utility.cpp" /> <ClCompile Include="..\..\ataidentify.cpp" /> <ClCompile Include="..\..\dev_areca.cpp" /> </ItemGroup> <ItemGroup> <ClInclude Include="..\daemon_win32.h"> <Filter>os_win32</Filter> </ClInclude> <ClInclude Include="..\syslog.h"> <Filter>os_win32</Filter> </ClInclude> <ClInclude Include="..\wbemcli_small.h"> <Filter>os_win32</Filter> </ClInclude> <ClInclude Include="..\wmiquery.h"> <Filter>os_win32</Filter> </ClInclude> <ClInclude Include="..\..\regex\regex.h"> <Filter>regex</Filter> </ClInclude> <ClInclude Include="..\..\regex\regex_internal.h"> <Filter>regex</Filter> </ClInclude> <ClInclude Include="..\..\getopt\getopt.h"> <Filter>getopt</Filter> </ClInclude> <ClInclude Include="..\..\atacmdnames.h" /> <ClInclude Include="..\..\atacmds.h" /> <ClInclude Include="..\..\cissio_freebsd.h" /> <ClInclude Include="..\..\csmisas.h" /> <ClInclude Include="..\..\dev_ata_cmd_set.h" /> <ClInclude Include="..\..\dev_interface.h" /> <ClInclude Include="..\..\dev_tunnelled.h" /> <ClInclude Include="..\..\drivedb.h" /> <ClInclude Include="..\..\int64.h" /> <ClInclude Include="..\..\knowndrives.h" /> <ClInclude Include="..\..\scsicmds.h" /> <ClInclude Include="..\..\utility.h" /> <ClInclude Include="..\..\ataidentify.h" /> <ClInclude Include="..\..\dev_areca.h" /> <ClInclude Include="config.h" /> <ClInclude Include="svnversion.h" /> </ItemGroup> <ItemGroup> <None Include="..\installer.nsi"> <Filter>os_win32</Filter> </None> <None Include="..\update-smart-drivedb.nsi"> <Filter>os_win32</Filter> </None> <None Include="..\..\AUTHORS" /> <None Include="..\..\autogen.sh" /> <None Include="..\..\ChangeLog" /> <None Include="..\..\config.h.in" /> <None Include="..\..\configure.ac" /> <None Include="..\..\do_release" /> <None Include="..\..\Doxyfile" /> <None Include="..\..\INSTALL" /> <None Include="..\..\Makefile.am" /> <None Include="..\..\NEWS" /> <None Include="..\..\README" /> <None Include="..\..\smartctl.8.in" /> <None Include="..\..\smartd.8.in" /> <None Include="..\..\smartd.conf.5.in" /> <None Include="..\..\smartd.initd.in" /> <None Include="..\..\TODO" /> <None Include="..\..\update-smart-drivedb.in" /> <None Include="..\..\WARNINGS" /> <None Include="..\smartd_warning.cmd"> <Filter>os_win32</Filter> </None> <None Include="..\..\smartd_warning.sh.in" /> <None Include="..\smartctl_res.rc.in"> <Filter>os_win32</Filter> </None> <None Include="..\smartd_res.rc.in"> <Filter>os_win32</Filter> </None> </ItemGroup> <ItemGroup> <CustomBuildStep Include="..\..\ataprint.h" /> <CustomBuildStep Include="..\..\cciss.h" /> <CustomBuildStep Include="..\..\megaraid.h" /> <CustomBuildStep Include="..\..\os_darwin.h" /> <CustomBuildStep Include="..\..\os_freebsd.h" /> <CustomBuildStep Include="..\..\os_generic.h" /> <CustomBuildStep Include="..\..\os_linux.h" /> <CustomBuildStep Include="..\..\os_netbsd.h" /> <CustomBuildStep Include="..\..\os_openbsd.h" /> <CustomBuildStep Include="..\..\os_os2.h" /> <CustomBuildStep Include="..\..\os_qnxnto.h" /> <CustomBuildStep Include="..\..\os_solaris.h" /> <CustomBuildStep Include="..\..\scsiprint.h" /> <CustomBuildStep Include="..\..\smartctl.h" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="smartctl_res.rc"> <Filter>os_win32</Filter> </ResourceCompile> <ResourceCompile Include="smartd_res.rc"> <Filter>os_win32</Filter> </ResourceCompile> </ItemGroup> <ItemGroup> <CustomBuild Include="..\syslogevt.mc"> <Filter>os_win32</Filter> </CustomBuild> </ItemGroup> </Project>��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/smartctl_res.rc.in������������������������������������������0000644�0000000�0000000�00000001744�12100771204�022161� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// // os_win32/smartctl_res.rc.in // // $Id: smartctl_res.rc.in 3755 2013-01-26 15:13:08Z chrfranke $ // 1 VERSIONINFO FILEVERSION @BINARY_VERSION@ PRODUCTVERSION @BINARY_VERSION@ FILEFLAGSMASK 0x0 FILEFLAGS 0x0 FILEOS 0x4 // VOS__WINDOWS32 FILETYPE 0x1 // VFT_APP FILESUBTYPE 0x0 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "04090000" BEGIN VALUE "CompanyName", "www.smartmontools.org" VALUE "FileDescription", "Control and Monitor Utility for SMART Disks" VALUE "FileVersion", "@TEXT_VERSION@" VALUE "InternalName", "smartctl" VALUE "LegalCopyright", "(C) 2002-13, Bruce Allen, Christian Franke, www.smartmontools.org" VALUE "OriginalFilename", "smartctl.exe" VALUE "ProductName", "smartmontools" VALUE "ProductVersion", "@TEXT_VERSION@" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x0000 END END ����������������������������smartmontools-6.2+svn3841.orig/os_win32/smartd_warning.cmd������������������������������������������0000644�0000000�0000000�00000012140�12155125113�022222� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������@echo off :: :: smartd warning script :: :: Copyright (C) 2012-13 Christian Franke <smartmontools-support@lists.sourceforge.net> :: :: This program is free software; you can redistribute it and/or modify :: it under the terms of the GNU General Public License as published by :: the Free Software Foundation; either version 2, or (at your option) :: any later version. :: :: You should have received a copy of the GNU General Public License :: (for example COPYING); If not, see <http://www.gnu.org/licenses/>. :: :: $Id: smartd_warning.cmd 3816 2013-06-09 16:16:11Z chrfranke $ :: set err= :: Parse options set dryrun= if "%1" == "--dryrun" ( set dryrun=t shift ) if not "%1" == "" ( echo smartd warning message script echo. echo Usage: echo set SMARTD_MAILER='Path to external script, empty for "blat"' echo set SMARTD_ADDRESS='Space separated mail adresses, empty if none' echo set SMARTD_MESSAGE='Error Message' echo set SMARTD_FAILTYPE='Type of failure, "EMailTest" for tests' echo set SMARTD_TFIRST='Date of first message sent, empty if none' echo :: set SMARTD_TFIRSTEPOCH='time_t format of above' echo set SMARTD_PREVCNT='Number of previous messages, 0 if none' echo set SMARTD_NEXTDAYS='Number of days until next message, empty if none' echo set SMARTD_DEVICEINFO='Device identify information' echo :: set SMARTD_DEVICE='Device name' echo :: set SMARTD_DEVICESTRING='Annotated device name' echo :: set SMARTD_DEVICETYPE='Device type from -d directive, "auto" if none' echo smartd_warning.cmd [--dryrun] goto EOF ) if "%SMARTD_ADDRESS%%SMARTD_MAILER%" == "" ( echo smartd_warning.cmd: SMARTD_ADDRESS or SMARTD_MAILER must be set goto EOF ) :: USERDNSDOMAIN may be unset if running as service if "%USERDNSDOMAIN%" == "" ( for /f "delims== tokens=2 usebackq" %%d in (`WMIC PATH Win32_Computersystem WHERE "PartOfDomain=TRUE" GET Domain /VALUE 2^>nul ^| find "Domain=" 2^>nul`) do set USERDNSDOMAIN=%%~d ) :: Format subject set SMARTD_SUBJECT=SMART error (%SMARTD_FAILTYPE%) detected on host: %COMPUTERNAME% :: Temp file for message if not "%TMP%" == "" set SMARTD_FULLMSGFILE=%TMP%\smartd_warning-%RANDOM%.txt if "%TMP%" == "" set SMARTD_FULLMSGFILE=smartd_warning-%RANDOM%.txt :: Format message ( echo This message was generated by the smartd service running on: echo. echo. host name: %COMPUTERNAME% if not "%USERDNSDOMAIN%" == "" echo. DNS domain: %USERDNSDOMAIN% if "%USERDNSDOMAIN%" == "" echo. DNS domain: [Empty] if not "%USERDOMAIN%" == "" echo. Win domain: %USERDOMAIN% echo. echo The following warning/error was logged by the smartd service: echo. :: SMARTD_MESSAGE and SMARTD_DEVICEINFO may contain parentheses for %%m in ("%SMARTD_MESSAGE%") do echo.%%~m echo. echo Device info: for %%m in ("%SMARTD_DEVICEINFO%") do echo.%%~m set m= echo. echo For details see the event log or log file of smartd. if not "%SMARTD_FAILTYPE%" == "EmailTest" ( echo. echo You can also use the smartctl utility for further investigation. if not "%SMARTD_PREVCNT%" == "0" echo The original message about this issue was sent at %SMARTD_TFIRST% if "%SMARTD_NEXTDAYS%" == "" ( echo No additional messages about this problem will be sent. ) else ( if "%SMARTD_NEXTDAYS%" == "1" ( echo Another message will be sent in 24 hours if the problem persists. ) else ( echo Another message will be sent in %SMARTD_NEXTDAYS% days if the problem persists. )) ) ) > "%SMARTD_FULLMSGFILE%" if not "%dryrun%" == "" ( echo %SMARTD_FULLMSGFILE%: type "%SMARTD_FULLMSGFILE%" echo --EOF-- ) :: Check first address set first= for /F "tokens=1*" %%a in ("%SMARTD_ADDRESS%") do (set first=%%a) set wtssend= if "%first%" == "console" set wtssend=-c if "%first%" == "active" set wtssend=-a if "%first%" == "connected" set wtssend=-s set first= if not "%wtssend%" == "" ( :: Show Message box(es) via WTSSendMessage() if not "%dryrun%" == "" ( echo call wtssendmsg %wtssend% "%SMARTD_SUBJECT%" - ^< "%SMARTD_FULLMSGFILE%" ) else ( call wtssendmsg %wtssend% "%SMARTD_SUBJECT%" - < "%SMARTD_FULLMSGFILE%" if errorlevel 1 set err=t ) :: Remove first address for /F "tokens=1*" %%a in ("%SMARTD_ADDRESS%") do (set SMARTD_ADDRESS=%%b) ) set wtssend= :: Make comma separated address list set SMARTD_ADDRCSV= if not "%SMARTD_ADDRESS%" == "" set SMARTD_ADDRCSV=%SMARTD_ADDRESS: =,% :: Use blat mailer by default if not "%SMARTD_ADDRESS%" == "" if "%SMARTD_MAILER%" == "" set SMARTD_MAILER=blat :: Send mail or run command if not "%SMARTD_ADDRCSV%" == "" ( :: Send mail if not "%dryrun%" == "" ( echo call "%SMARTD_MAILER%" - -q -subject "%SMARTD_SUBJECT%" -to "%SMARTD_ADDRCSV%" ^< "%SMARTD_FULLMSGFILE%" ) else ( call "%SMARTD_MAILER%" - -q -subject "%SMARTD_SUBJECT%" -to "%SMARTD_ADDRCSV%" < "%SMARTD_FULLMSGFILE%" if errorlevel 1 set err=t ) ) else ( if not "%SMARTD_MAILER%" == "" ( :: Run command if not "%dryrun%" == "" ( echo call "%SMARTD_MAILER%" ^<nul ) else ( call "%SMARTD_MAILER%" <nul if errorlevel 1 set err=t ) )) del "%SMARTD_FULLMSGFILE%" >nul 2>nul :EOF if not "%err%" == "" goto ERROR 2>nul ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/wmiquery.h��������������������������������������������������0000644�0000000�0000000�00000010530�11657042614�020564� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_win32/wmiquery.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef WMIQUERY_H #define WMIQUERY_H #define WMIQUERY_H_CVSID "$Id: wmiquery.h 3475 2011-11-10 21:43:40Z chrfranke $" #ifdef HAVE_WBEMCLI_H #include <wbemcli.h> #else #include "wbemcli_small.h" #endif #include <string> #ifndef __GNUC__ #define __attribute_format_printf(x, y) /**/ #elif defined(__MINGW32__) && __USE_MINGW_ANSI_STDIO // Check format of __mingw_*printf() instead of MSVCRT.DLL:*printf() #define __attribute_format_printf(x, y) __attribute__((format (gnu_printf, x, y))) #else #define __attribute_format_printf(x, y) __attribute__((format (printf, x, y))) #endif ///////////////////////////////////////////////////////////////////////////// // com_bstr /// Wrapper class for COM BSTR class com_bstr { public: /// Construct from string. com_bstr(const char * str); /// Destructor frees BSTR. ~com_bstr() { SysFreeString(m_bstr); } /// Implicit conversion to BSTR. operator BSTR() { return m_bstr; } /// Convert BSTR back to std::string. static bool to_str(const BSTR & bstr, std::string & str); private: BSTR m_bstr; com_bstr(const com_bstr &); void operator=(const com_bstr &); }; ///////////////////////////////////////////////////////////////////////////// // com_intf_ptr /// Wrapper class for COM Interface pointer template <class T> class com_intf_ptr { public: /// Construct empty object com_intf_ptr() : m_ptr(0) { } /// Destructor releases the interface. ~com_intf_ptr() { reset(); } /// Release interface and clear the pointer. void reset() { if (m_ptr) { m_ptr->Release(); m_ptr = 0; } } /// Return the pointer. T * get() { return m_ptr; } /// Pointer dereferencing. T * operator->() { return m_ptr; } /// Return address of pointer for replacement. T * * replace() { reset(); return &m_ptr; } /// For (ptr != 0) check. operator bool() const { return !!m_ptr; } /// For (ptr == 0) check. bool operator!() const { return !m_ptr; } private: T * m_ptr; com_intf_ptr(const com_intf_ptr &); void operator=(const com_intf_ptr &); }; ///////////////////////////////////////////////////////////////////////////// // wbem_object class wbem_enumerator; /// Wrapper class for IWbemClassObject class wbem_object { public: /// Get string representation. std::string get_str(const char * name) /*const*/; private: /// Contents is set by wbem_enumerator. friend class wbem_enumerator; com_intf_ptr<IWbemClassObject> m_intf; }; ///////////////////////////////////////////////////////////////////////////// // wbem_enumerator class wbem_services; /// Wrapper class for IEnumWbemClassObject class wbem_enumerator { public: /// Get next object, return false if none or error. bool next(wbem_object & obj); private: /// Contents is set by wbem_services. friend class wbem_services; com_intf_ptr<IEnumWbemClassObject> m_intf; }; ///////////////////////////////////////////////////////////////////////////// // wbem_services /// Wrapper class for IWbemServices class wbem_services { public: /// Connect to service, return false on error. bool connect(); /// Execute query, get result list. /// Return false on error. bool vquery(wbem_enumerator & result, const char * qstr, va_list args) /*const*/; /// Execute query, get single result object. /// Return false on error or result size != 1. bool vquery1(wbem_object & obj, const char * qstr, va_list args) /*const*/; /// Version of vquery() with printf() formatting. bool query(wbem_enumerator & result, const char * qstr, ...) /*const*/ __attribute_format_printf(3, 4); /// Version of vquery1() with printf() formatting. bool query1(wbem_object & obj, const char * qstr, ...) /*const*/ __attribute_format_printf(3, 4); private: com_intf_ptr<IWbemServices> m_intf; }; #endif // WMIQUERY_H ������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/runcmda.exe.manifest����������������������������������������0000644�0000000�0000000�00000000761�11646550747�022510� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" name="runcmda.exe" type="win32" /> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> </requestedPrivileges> </security> </trustInfo> </assembly> ���������������smartmontools-6.2+svn3841.orig/os_win32/syslogevt.mc������������������������������������������������0000644�0000000�0000000�00000005117�12062407372�021113� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������;/* ; * os_win32/syslogevt.mc ; * ; * Home page of code is: http://smartmontools.sourceforge.net ; * ; * Copyright (C) 2004-10 Christian Franke <smartmontools-support@lists.sourceforge.net> ; * ; * This program is free software; you can redistribute it and/or modify ; * it under the terms of the GNU General Public License as published by ; * the Free Software Foundation; either version 2, or (at your option) ; * any later version. ; * ; * You should have received a copy of the GNU General Public License ; * (for example COPYING); if not, write to the Free Software Foundation, ; * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ; * ; */ ; ;// $Id: syslogevt.mc 3727 2012-12-13 17:23:06Z samm2 $ ; ;// Use message compiler "mc" or "windmc" to generate ;// syslogevt.rc, syslogevt.h, msg00001.bin ;// from this file. ;// MSG_SYSLOG in syslogmsg.h must be zero ;// MSG_SYSLOG_nn must be == nn ; ;// MS and binutils message compiler defaults for FacilityNames differ: ;// mc: Application = 0x000 ;// windmc: Application = 0xfff FacilityNames = (Application = 0x000) MessageId=0x0 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG Language=English %1 . ;// 1-10 Line SYSLOG Messages ;// %1=Ident, %2=PID, %3=Severity, %[4-13]=Line 1-10 MessageId=0x1 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_01 Language=English %1[%2]:%3: %4 . MessageId=0x2 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_02 Language=English %1[%2]:%3%n %4%n %5 . MessageId=0x3 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_03 Language=English %1[%2]:%3%n %4%n %5%n %6 . MessageId=0x4 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_04 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7 . MessageId=0x5 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_05 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7%n %8 . MessageId=0x6 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_06 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7%n %8%n %9 . MessageId=0x7 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_07 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7%n %8%n %9%n %10 . MessageId=0x8 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_08 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7%n %8%n %9%n %10%n %11 . MessageId=0x9 Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_09 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7%n %8%n %9%n %10%n %11%n %12 . MessageId=0xa Severity=Success Facility=Application SymbolicName=MSG_SYSLOG_10 Language=English %1[%2]:%3%n %4%n %5%n %6%n %7%n %8%n %9%n %10%n %11%n %12%n %13 . �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/runcmd.c����������������������������������������������������0000644�0000000�0000000�00000004052�11646550747�020200� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Run console command and wait for user input * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2011 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ char svnid[] = "$Id: runcmd.c 3453 2011-10-16 12:45:27Z chrfranke $"; #include <stdio.h> #include <windows.h> int main(int argc, char **argv) { char * cmd = GetCommandLineA(); DWORD exitcode; STARTUPINFOA si = { sizeof(si), }; PROCESS_INFORMATION pi; int key; if (*cmd == '"') { cmd++; while (*cmd && !(*cmd == '"' && cmd[-1] != '\\')) cmd++; if (*cmd) cmd++; } else { while (*cmd && !(*cmd == ' ' || *cmd == '\t')) cmd++; } while (*cmd == ' ' || *cmd == '\t') cmd++; if (*cmd) { printf("%s\n\n", cmd); fflush(stdout); } if (!*cmd) { printf("Usage: %s COMMAND [ARG ...]\n", argv[0]); exitcode = 1; } else if (!CreateProcessA((char *)0, cmd, (SECURITY_ATTRIBUTES *)0, (SECURITY_ATTRIBUTES *)0, TRUE/*inherit*/, 0/*no flags*/, (void *)0, (char *)0, &si, &pi) ) { DWORD err = GetLastError(); if (err == ERROR_FILE_NOT_FOUND) printf("Command not found\n"); else printf("CreateProcess() failed with error=%u\n", err); exitcode = 1; } else { CloseHandle(pi.hThread); exitcode = 42; WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitcode); CloseHandle(pi.hProcess); if (exitcode) printf("\nExitcode: %u (0x%02x)", exitcode, exitcode); } printf("\nType <return> to exit: "); fflush(stdout); while (!((key = getc(stdin)) == EOF || key == '\n' || key == '\r')) ; printf("\n"); return exitcode; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_win32/smartd_res.rc.in��������������������������������������������0000644�0000000�0000000�00000002026�12101000543�021604� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// // os_win32/smartd_res.rc.in // // $Id: smartd_res.rc.in 3756 2013-01-26 16:16:35Z chrfranke $ // 1 VERSIONINFO FILEVERSION @BINARY_VERSION@ PRODUCTVERSION @BINARY_VERSION@ FILEFLAGSMASK 0x0 FILEFLAGS 0x0 FILEOS 0x4 // VOS__WINDOWS32 FILETYPE 0x1 // VFT_APP FILESUBTYPE 0x0 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "04090000" BEGIN VALUE "CompanyName", "www.smartmontools.org" VALUE "FileDescription", "SMART Disk Monitoring Daemon" VALUE "FileVersion", "@TEXT_VERSION@" VALUE "InternalName", "smartd" VALUE "LegalCopyright", "(C) 2002-13, Bruce Allen, Christian Franke, www.smartmontools.org" VALUE "OriginalFilename", "smartd.exe" VALUE "ProductName", "smartmontools" VALUE "ProductVersion", "@TEXT_VERSION@" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0409, 0x0000 END END // eventlog MESSAGETABLE for syslog() emulation #include "syslogevt.rc" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/utility.h������������������������������������������������������������0000644�0000000�0000000�00000023766�12057213545�016757� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * utility.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef UTILITY_H_ #define UTILITY_H_ #define UTILITY_H_CVSID "$Id: utility.h 3719 2012-12-03 21:19:33Z chrfranke $" #include <time.h> #include <sys/types.h> // for regex.h (according to POSIX) #include <regex.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <string> #ifndef __GNUC__ #define __attribute_format_printf(x, y) /**/ #elif defined(__MINGW32__) && __USE_MINGW_ANSI_STDIO // Check format of __mingw_*printf() instead of MSVCRT.DLL:*printf() #define __attribute_format_printf(x, y) __attribute__((format (gnu_printf, x, y))) #define HAVE_WORKING_SNPRINTF 1 #else #define __attribute_format_printf(x, y) __attribute__((format (printf, x, y))) #endif // Make version information string std::string format_version_info(const char * prog_name, bool full = false); // return (v)sprintf() formated std::string std::string strprintf(const char * fmt, ...) __attribute_format_printf(1, 2); std::string vstrprintf(const char * fmt, va_list ap); // Return true if STR starts with PREFIX inline bool str_starts_with(const char * str, const char * prefix) { return !strncmp(str, prefix, strlen(prefix)); } inline bool str_starts_with(const std::string & str, const char * prefix) { return !strncmp(str.c_str(), prefix, strlen(prefix)); } #ifndef HAVE_WORKING_SNPRINTF // Substitute by safe replacement functions int safe_snprintf(char *buf, int size, const char *fmt, ...) __attribute_format_printf(3, 4); int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap); #define snprintf safe_snprintf #define vsnprintf safe_vsnprintf #endif #ifndef HAVE_STRTOULL // Replacement for missing strtoull() (Linux with libc < 6, MSVC) uint64_t strtoull(const char * p, char * * endp, int base); #endif // Utility function prints current date and time and timezone into a // character buffer of length>=64. All the fuss is needed to get the // right timezone info (sigh). #define DATEANDEPOCHLEN 64 void dateandtimezone(char *buffer); // Same, but for time defined by epoch tval void dateandtimezoneepoch(char *buffer, time_t tval); // like printf() except that we can control it better. Note -- // although the prototype is given here in utility.h, the function // itself is defined differently in smartctl and smartd. So the // function definition(s) are in smartd.c and in smartctl.c. void pout(const char *fmt, ...) __attribute_format_printf(1, 2); // replacement for perror() with redirected output. void syserror(const char *message); // Function for processing -r option in smartctl and smartd int split_report_arg(char *s, int *i); // Function for processing -t selective... option in smartctl int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode); // Guess device type (ata or scsi) based on device name // Guessing will now use Controller Type defines below // Moved to C++ interface //int guess_device_type(const char * dev_name); // Create and return the list of devices to probe automatically // if the DEVICESCAN option is in the smartd config file // Moved to C++ interface //int make_device_names (char ***devlist, const char* name); // Replacement for exit(status) // (exit is not compatible with C++ destructors) #define EXIT(status) { throw (int)(status); } #ifdef OLD_INTERFACE // replacement for calloc() that tracks memory usage void *Calloc(size_t nmemb, size_t size); // Utility function to free memory void *FreeNonZero1(void* address, int size, int whatline, const char* file); // Typesafe version of above template <class T> inline T * FreeNonZero(T * address, int size, int whatline, const char* file) { return (T *)FreeNonZero1((void *)address, size, whatline, file); } // A custom version of strdup() that keeps track of how much memory is // being allocated. If mustexist is set, it also throws an error if we // try to duplicate a NULL string. char *CustomStrDup(const char *ptr, int mustexist, int whatline, const char* file); // To help with memory checking. Use when it is known that address is // NOT null. void *CheckFree1(void *address, int whatline, const char* file); // Typesafe version of above template <class T> inline T * CheckFree(T * address, int whatline, const char* file) { return (T *)CheckFree1((void *)address, whatline, file); } #endif // OLD_INTERFACE // Compile time check of byte ordering // (inline const function allows compiler to remove dead code) inline bool isbigendian() { #ifdef WORDS_BIGENDIAN return true; #else return false; #endif } // Runtime check of byte ordering, throws if different from isbigendian(). void check_endianness(); // This value follows the peripheral device type value as defined in // SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in // the ATA standard for packet devices to define the device type. const char *packetdevicetype(int type); // Moved to C++ interface //int deviceopen(const char *pathname, char *type); //int deviceclose(int fd); // Optional functions of os_*.c #ifdef HAVE_GET_OS_VERSION_STR // Return build host and OS version as static string //const char * get_os_version_str(void); #endif // returns true if any of the n bytes are nonzero, else zero. bool nonempty(const void * data, int size); // needed to fix glibc bug void FixGlibcTimeZoneBug(); // Format integer with thousands separator const char * format_with_thousands_sep(char * str, int strsize, uint64_t val, const char * thousands_sep = 0); // Format capacity with SI prefixes const char * format_capacity(char * str, int strsize, uint64_t val, const char * decimal_point = 0); // Wrapper class for a raw data buffer class raw_buffer { public: explicit raw_buffer(unsigned sz, unsigned char val = 0) : m_data(new unsigned char[sz]), m_size(sz) { memset(m_data, val, m_size); } ~raw_buffer() { delete [] m_data; } unsigned size() const { return m_size; } unsigned char * data() { return m_data; } const unsigned char * data() const { return m_data; } private: unsigned char * m_data; unsigned m_size; raw_buffer(const raw_buffer &); void operator=(const raw_buffer &); }; /// Wrapper class for FILE *. class stdio_file { public: explicit stdio_file(FILE * f = 0, bool owner = false) : m_file(f), m_owner(owner) { } stdio_file(const char * name, const char * mode) : m_file(fopen(name, mode)), m_owner(true) { } ~stdio_file() { if (m_file && m_owner) fclose(m_file); } bool open(const char * name, const char * mode) { m_file = fopen(name, mode); m_owner = true; return !!m_file; } void open(FILE * f, bool owner = false) { m_file = f; m_owner = owner; } bool close() { if (!m_file) return true; bool ok = !ferror(m_file); if (fclose(m_file)) ok = false; m_file = 0; return ok; } operator FILE * () { return m_file; } bool operator!() const { return !m_file; } private: FILE * m_file; bool m_owner; stdio_file(const stdio_file &); void operator=(const stdio_file &); }; /// Wrapper class for regex(3). /// Supports copy & assignment and is compatible with STL containers. class regular_expression { public: // Construction & assignment regular_expression(); regular_expression(const char * pattern, int flags, bool throw_on_error = true); ~regular_expression(); regular_expression(const regular_expression & x); regular_expression & operator=(const regular_expression & x); /// Set and compile new pattern, return false on error. bool compile(const char * pattern, int flags); // Get pattern from last compile(). const char * get_pattern() const { return m_pattern.c_str(); } /// Get error message from last compile(). const char * get_errmsg() const { return m_errmsg.c_str(); } // Return true if pattern is not set or bad. bool empty() const { return (m_pattern.empty() || !m_errmsg.empty()); } /// Return true if substring matches pattern bool match(const char * str, int flags = 0) const { return !regexec(&m_regex_buf, str, 0, (regmatch_t*)0, flags); } /// Return true if full string matches pattern bool full_match(const char * str, int flags = 0) const { regmatch_t range; return ( !regexec(&m_regex_buf, str, 1, &range, flags) && range.rm_so == 0 && range.rm_eo == (int)strlen(str)); } /// Return true if substring matches pattern, fill regmatch_t array. bool execute(const char * str, unsigned nmatch, regmatch_t * pmatch, int flags = 0) const { return !regexec(&m_regex_buf, str, nmatch, pmatch, flags); } private: std::string m_pattern; int m_flags; regex_t m_regex_buf; std::string m_errmsg; void free_buf(); void copy(const regular_expression & x); bool compile(); }; #ifdef _WIN32 // Get exe directory //(implemented in os_win32.cpp) std::string get_exe_dir(); #endif #ifdef OLD_INTERFACE // remaining controller types in old interface modules #define CONTROLLER_UNKNOWN 0x00 #define CONTROLLER_ATA 0x01 #define CONTROLLER_SCSI 0x02 #endif #endif ����������smartmontools-6.2+svn3841.orig/dev_interface.h������������������������������������������������������0000644�0000000�0000000�00000061527�12042050453�020036� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * dev_interface.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef DEV_INTERFACE_H #define DEV_INTERFACE_H #define DEV_INTERFACE_H_CVSID "$Id: dev_interface.h 3663 2012-10-24 20:35:55Z chrfranke $\n" #include "utility.h" #include <stdexcept> #include <string> #include <vector> ///////////////////////////////////////////////////////////////////////////// // Common functionality for all device types // Forward declarations class smart_interface; class ata_device; class scsi_device; /// Base class for all devices class smart_device { // Types public: /// Device info strings struct device_info { device_info() { } device_info(const char * d_name, const char * d_type, const char * r_type) : dev_name(d_name), info_name(d_name), dev_type(d_type), req_type(r_type) { } std::string dev_name; ///< Device (path)name std::string info_name; ///< Informal name std::string dev_type; ///< Actual device type std::string req_type; ///< Device type requested by user, empty if none }; /// Error (number,message) pair struct error_info { explicit error_info(int n = 0) : no(n) { } error_info(int n, const char * m) : no(n), msg(m) { } void clear() { no = 0; msg.erase(); } int no; ///< Error number std::string msg; ///< Error message }; // Construction protected: /// Constructor to init interface and device info. /// Must be called in implementation classes. smart_device(smart_interface * intf, const char * dev_name, const char * dev_type, const char * req_type); /// Dummy enum for dummy constructor. enum do_not_use_in_implementation_classes { never_called }; /// Dummy constructor for abstract classes. /// Must never be called in implementation classes. smart_device(do_not_use_in_implementation_classes); public: virtual ~smart_device() throw(); // Attributes public: /////////////////////////////////////////////// // Dynamic downcasts to actual device flavor /// Return true if ATA device bool is_ata() const { return !!m_ata_ptr; } /// Return true if SCSI device bool is_scsi() const { return !!m_scsi_ptr; } /// Downcast to ATA device. ata_device * to_ata() { return m_ata_ptr; } /// Downcast to ATA device (const). const ata_device * to_ata() const { return m_ata_ptr; } /// Downcast to SCSI device. scsi_device * to_scsi() { return m_scsi_ptr; } /// Downcast to SCSI device (const). const scsi_device * to_scsi() const { return m_scsi_ptr; } /////////////////////////////////////////////// // Device information /// Get device info struct. const device_info & get_info() const { return m_info; } /// Get device (path)name. const char * get_dev_name() const { return m_info.dev_name.c_str(); } /// Get informal name. const char * get_info_name() const { return m_info.info_name.c_str(); } /// Get device type. const char * get_dev_type() const { return m_info.dev_type.c_str(); } /// Get type requested by user, empty if none. const char * get_req_type() const { return m_info.req_type.c_str(); } protected: /// R/W access to device info struct. device_info & set_info() { return m_info; } public: /////////////////////////////////////////////// // Last error information /// Get last error info struct. const error_info & get_err() const { return m_err; } /// Get last error number. int get_errno() const { return m_err.no; } /// Get last error message. const char * get_errmsg() const { return m_err.msg.c_str(); } /// Return true if last error indicates an unsupported system call. /// Default implementation returns true on ENOSYS and ENOTSUP. virtual bool is_syscall_unsup() const; /// Set last error number and message. /// Printf()-like formatting is supported. /// Returns false always to allow use as a return expression. bool set_err(int no, const char * msg, ...) __attribute_format_printf(3, 4); /// Set last error info struct. bool set_err(const error_info & err) { m_err = err; return false; } /// Clear last error info. void clear_err() { m_err.clear(); } /// Set last error number and default message. /// Message is retrieved from interface's get_msg_for_errno(no). bool set_err(int no); // Operations public: /////////////////////////////////////////////// // Device open/close // Must be implemented in derived class /// Return true if device is open. virtual bool is_open() const = 0; /// Open device, return false on error. virtual bool open() = 0; /// Close device, return false on error. virtual bool close() = 0; /// Open device with autodetection support. /// May return another device for further access. /// In this case, the original pointer is no longer valid. /// Default implementation calls 'open()' and returns 'this'. virtual smart_device * autodetect_open(); /////////////////////////////////////////////// // Support for tunnelled devices /// Return true if other device is owned by this device. /// Default implementation returns false. virtual bool owns(const smart_device * dev) const; /// Release ownership of other device. /// Default implementation does nothing. virtual void release(const smart_device * dev); protected: /// Get interface which produced this object. smart_interface * smi() { return m_intf; } /// Get interface which produced this object (const). const smart_interface * smi() const { return m_intf; } // Implementation private: smart_interface * m_intf; device_info m_info; error_info m_err; // Pointers for to_ata(), to_scsi(), // set by ATA/SCSI interface classes. friend class ata_device; ata_device * m_ata_ptr; friend class scsi_device; scsi_device * m_scsi_ptr; // Prevent copy/assigment smart_device(const smart_device &); void operator=(const smart_device &); }; ///////////////////////////////////////////////////////////////////////////// // ATA specific interface /// ATA register value and info whether it has ever been set // (Automatically set by first assignment) class ata_register { public: ata_register() : m_val(0x00), m_is_set(false) { } ata_register & operator=(unsigned char x) { m_val = x; m_is_set = true; return * this; } unsigned char val() const { return m_val; } operator unsigned char() const { return m_val; } bool is_set() const { return m_is_set; } private: unsigned char m_val; ///< Register value bool m_is_set; ///< true if set }; /// ATA Input registers (for 28-bit commands) struct ata_in_regs { // ATA-6/7 register names // ATA-3/4/5 // ATA-8 ata_register features; // features // features ata_register sector_count; // sector count // count ata_register lba_low; // sector number // ] ata_register lba_mid; // cylinder low // ] lba ata_register lba_high; // cylinder high // ] ata_register device; // device/head // device ata_register command; // command // command /// Return true if any register is set bool is_set() const { return (features.is_set() || sector_count.is_set() || lba_low.is_set() || lba_mid.is_set() || lba_high.is_set() || device.is_set() || command.is_set()); } }; /// ATA Output registers (for 28-bit commands) struct ata_out_regs { ata_register error; ata_register sector_count; ata_register lba_low; ata_register lba_mid; ata_register lba_high; ata_register device; ata_register status; /// Return true if any register is set bool is_set() const { return (error.is_set() || sector_count.is_set() || lba_low.is_set() || lba_mid.is_set() || lba_high.is_set() || device.is_set() || status.is_set()); } }; /// 16-bit alias to a 8-bit ATA register pair. class ata_reg_alias_16 { public: ata_reg_alias_16(ata_register & lo, ata_register & hi) : m_lo(lo), m_hi(hi) { } ata_reg_alias_16 & operator=(unsigned short x) { m_lo = (unsigned char) x; m_hi = (unsigned char)(x >> 8); return * this; } unsigned short val() const { return m_lo | (m_hi << 8); } operator unsigned short() const { return m_lo | (m_hi << 8); } private: ata_register & m_lo, & m_hi; // References must not be copied. ata_reg_alias_16(const ata_reg_alias_16 &); void operator=(const ata_reg_alias_16 &); }; /// 48-bit alias to six 8-bit ATA registers (for LBA). class ata_reg_alias_48 { public: ata_reg_alias_48(ata_register & ll, ata_register & lm, ata_register & lh, ata_register & hl, ata_register & hm, ata_register & hh) : m_ll(ll), m_lm(lm), m_lh(lh), m_hl(hl), m_hm(hm), m_hh(hh) { } ata_reg_alias_48 & operator=(uint64_t x) { m_ll = (unsigned char) x; m_lm = (unsigned char)(x >> 8); m_lh = (unsigned char)(x >> 16); m_hl = (unsigned char)(x >> 24); m_hm = (unsigned char)(x >> 32); m_hh = (unsigned char)(x >> 40); return * this; } uint64_t val() const { return ( (unsigned)m_ll | ((unsigned)m_lm << 8) | ((unsigned)m_lh << 16) | ((unsigned)m_hl << 24) | ((uint64_t)m_hm << 32) | ((uint64_t)m_hh << 40)); } operator uint64_t() const { return val(); } private: ata_register & m_ll, & m_lm, & m_lh, & m_hl, & m_hm, & m_hh; // References must not be copied. ata_reg_alias_48(const ata_reg_alias_48 &); void operator=(const ata_reg_alias_48 &); }; /// ATA Input registers for 48-bit commands // See section 4.14 of T13/1532D Volume 1 Revision 4b // // Uses ATA-6/7 method to specify 16-bit registers as // recent (low byte) and previous (high byte) content of // 8-bit registers. // // (ATA-8 ACS does not longer follow this scheme, it uses // abstract registers with sufficient size and leaves the // actual mapping to the transport layer.) // struct ata_in_regs_48bit : public ata_in_regs // "most recently written" registers { ata_in_regs prev; ///< "previous content" // 16-bit aliases for above pair. ata_reg_alias_16 features_16; ata_reg_alias_16 sector_count_16; ata_reg_alias_16 lba_low_16; ata_reg_alias_16 lba_mid_16; ata_reg_alias_16 lba_high_16; // 48-bit alias to all 8-bit LBA registers. ata_reg_alias_48 lba_48; /// Return true if 48-bit command bool is_48bit_cmd() const { return prev.is_set(); } /// Return true if 48-bit command with any nonzero high byte bool is_real_48bit_cmd() const { return ( prev.features || prev.sector_count || prev.lba_low || prev.lba_mid || prev.lba_high); } ata_in_regs_48bit(); }; /// ATA Output registers for 48-bit commands struct ata_out_regs_48bit : public ata_out_regs // read with HOB=0 { ata_out_regs prev; ///< read with HOB=1 // 16-bit aliases for above pair. ata_reg_alias_16 sector_count_16; ata_reg_alias_16 lba_low_16; ata_reg_alias_16 lba_mid_16; ata_reg_alias_16 lba_high_16; // 48-bit alias to all 8-bit LBA registers. ata_reg_alias_48 lba_48; ata_out_regs_48bit(); }; /// Flags for each ATA output register struct ata_out_regs_flags { bool error, sector_count, lba_low, lba_mid, lba_high, device, status; /// Return true if any flag is set. bool is_set() const { return ( error || sector_count || lba_low || lba_mid || lba_high || device || status); } /// Default constructor clears all flags. ata_out_regs_flags() : error(false), sector_count(false), lba_low(false), lba_mid(false), lba_high(false), device(false), status(false) { } }; /// ATA pass through input parameters struct ata_cmd_in { ata_in_regs_48bit in_regs; ///< Input registers ata_out_regs_flags out_needed; ///< True if output register value needed enum { no_data = 0, data_in, data_out } direction; ///< I/O direction void * buffer; ///< Pointer to data buffer unsigned size; ///< Size of buffer /// Prepare for 28-bit DATA IN command void set_data_in(void * buf, unsigned nsectors) { buffer = buf; in_regs.sector_count = nsectors; direction = data_in; size = nsectors * 512; } /// Prepare for 28-bit DATA OUT command void set_data_out(const void * buf, unsigned nsectors) { buffer = const_cast<void *>(buf); in_regs.sector_count = nsectors; direction = data_out; size = nsectors * 512; } /// Prepare for 48-bit DATA IN command void set_data_in_48bit(void * buf, unsigned nsectors) { buffer = buf; // Note: This also sets 'in_regs.is_48bit_cmd()' in_regs.sector_count_16 = nsectors; direction = data_in; size = nsectors * 512; } ata_cmd_in(); }; /// ATA pass through output parameters struct ata_cmd_out { ata_out_regs_48bit out_regs; ///< Output registers ata_cmd_out(); }; /// ATA device access class ata_device : virtual public /*extends*/ smart_device { public: /// ATA pass through. /// Return false on error. /// Must be implemented in derived class. virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) = 0; /// ATA pass through without output registers. /// Return false on error. /// Calls ata_pass_through(in, dummy), cannot be reimplemented. bool ata_pass_through(const ata_cmd_in & in); /// Return true if OS caches ATA identify sector. /// Default implementation returns false. virtual bool ata_identify_is_cached() const; protected: /// Flags for ata_cmd_is_supported(). enum { supports_data_out = 0x01, // PIO DATA OUT supports_smart_status = 0x02, // read output registers for SMART STATUS only supports_output_regs = 0x04, // read output registers for all commands supports_multi_sector = 0x08, // more than one sector (1 DRQ/sector variant) supports_48bit_hi_null = 0x10, // 48-bit commands with null high bytes only supports_48bit = 0x20, // all 48-bit commands }; /// Check command input parameters. /// Return false if required features are not implemented. /// Calls set_err(...) accordingly. bool ata_cmd_is_supported(const ata_cmd_in & in, unsigned flags, const char * type = 0); /// Check command input parameters (old version). // TODO: Remove if no longer used. bool ata_cmd_is_ok(const ata_cmd_in & in, bool data_out_support = false, bool multi_sector_support = false, bool ata_48bit_support = false) { return ata_cmd_is_supported(in, (data_out_support ? supports_data_out : 0) | supports_output_regs | (multi_sector_support ? supports_multi_sector : 0) | (ata_48bit_support ? supports_48bit : 0)); } /// Hide/unhide ATA interface. void hide_ata(bool hide = true) { m_ata_ptr = (!hide ? this : 0); } /// Default constructor, registers device as ATA. ata_device() : smart_device(never_called) { hide_ata(false); } }; ///////////////////////////////////////////////////////////////////////////// // SCSI specific interface struct scsi_cmnd_io; /// SCSI device access class scsi_device : virtual public /*extends*/ smart_device { public: /// SCSI pass through. /// Returns false on error. virtual bool scsi_pass_through(scsi_cmnd_io * iop) = 0; protected: /// Hide/unhide SCSI interface. void hide_scsi(bool hide = true) { m_scsi_ptr = (!hide ? this : 0); } /// Default constructor, registers device as SCSI. scsi_device() : smart_device(never_called) { hide_scsi(false); } }; ///////////////////////////////////////////////////////////////////////////// /// Smart pointer class for device pointers template <class Dev> class any_device_auto_ptr { public: typedef Dev device_type; /// Construct from optional pointer to device /// and optional pointer to base device. explicit any_device_auto_ptr(device_type * dev = 0, smart_device * base_dev = 0) : m_dev(dev), m_base_dev(base_dev) { } /// Destructor deletes device object. ~any_device_auto_ptr() throw() { reset(); } /// Assign a new pointer. /// Throws if a pointer is already assigned. void operator=(device_type * dev) { if (m_dev) fail(); m_dev = dev; } /// Delete device object and clear the pointer. void reset() { if (m_dev) { if (m_base_dev && m_dev->owns(m_base_dev)) m_dev->release(m_base_dev); delete m_dev; m_dev = 0; } } /// Return the pointer and release ownership. device_type * release() { device_type * dev = m_dev; m_dev = 0; return dev; } /// Replace the pointer. /// Used to call dev->autodetect_open(). void replace(device_type * dev) { m_dev = dev; } /// Return the pointer. device_type * get() const { return m_dev; } /// Pointer dereferencing. device_type & operator*() const { return *m_dev; } /// Pointer dereferencing. device_type * operator->() const { return m_dev; } /// For (ptr != 0) check. operator bool() const { return !!m_dev; } /// For (ptr == 0) check. bool operator !() const { return !m_dev; } private: device_type * m_dev; smart_device * m_base_dev; void fail() const { throw std::logic_error("any_device_auto_ptr: wrong usage"); } // Prevent copy/assignment any_device_auto_ptr(const any_device_auto_ptr<Dev> &); void operator=(const any_device_auto_ptr<Dev> &); }; typedef any_device_auto_ptr<smart_device> smart_device_auto_ptr; typedef any_device_auto_ptr<ata_device> ata_device_auto_ptr; typedef any_device_auto_ptr<scsi_device> scsi_device_auto_ptr; ///////////////////////////////////////////////////////////////////////////// // smart_device_list /// List of devices for DEVICESCAN class smart_device_list { // Construction public: smart_device_list() { } ~smart_device_list() throw() { for (unsigned i = 0; i < m_list.size(); i++) delete m_list[i]; } // Attributes unsigned size() const { return m_list.size(); } // Operations void clear() { for (unsigned i = 0; i < m_list.size(); i++) delete m_list[i]; m_list.clear(); } void push_back(smart_device * dev) { m_list.push_back(dev); } void push_back(smart_device_auto_ptr & dev) { m_list.push_back(dev.get()); dev.release(); } smart_device * at(unsigned i) { return m_list.at(i); } const smart_device * at(unsigned i) const { return m_list.at(i); } smart_device * release(unsigned i) { smart_device * dev = m_list.at(i); m_list[i] = 0; return dev; } // Implementation private: std::vector<smart_device *> m_list; // Prevent copy/assigment smart_device_list(const smart_device_list &); void operator=(const smart_device_list &); }; ///////////////////////////////////////////////////////////////////////////// // smart_interface /// The platform interface abstraction class smart_interface { public: /// Initialize platform interface and register with smi(). /// Must be implemented by platform module and register interface with set() static void init(); smart_interface() { } virtual ~smart_interface() throw() { } /// Return info string about build host and/or OS version. /// Default implementation returns SMARTMONTOOLS_BUILD_HOST. virtual std::string get_os_version_str(); /// Return valid args for device type option/directive. /// Default implementation returns "ata, scsi, sat, usb*..." /// concatenated with result from get_valid_custom_dev_types_str(). virtual std::string get_valid_dev_types_str(); /// Return example string for program 'appname'. /// Default implementation returns empty string. /// For the migration of print_smartctl_examples(), /// function is allowed to print examples to stdout. /// TODO: Remove this hack. virtual std::string get_app_examples(const char * appname); /// Get microseconds since some unspecified starting point. /// Used only for command duration measurements in debug outputs. /// Returns -1 if unsupported. /// Default implementation uses clock_gettime(), gettimeofday() or ftime(). virtual int64_t get_timer_usec(); /// Disable/Enable system auto standby/sleep mode. /// Return false if unsupported or if system is running /// on battery. /// Default implementation returns false. virtual bool disable_system_auto_standby(bool disable); /////////////////////////////////////////////// // Last error information /// Get last error info struct. const smart_device::error_info & get_err() const { return m_err; } /// Get last error number. int get_errno() const { return m_err.no; } /// Get last error message. const char * get_errmsg() const { return m_err.msg.c_str(); } /// Set last error number and message. /// Printf()-like formatting is supported. /// Returns false always to allow use as a return expression. bool set_err(int no, const char * msg, ...) __attribute_format_printf(3, 4); /// Set last error info struct. bool set_err(const smart_device::error_info & err) { m_err = err; return false; } /// Clear last error info. void clear_err() { m_err.clear(); } /// Set last error number and default message. /// Message is retrieved from get_msg_for_errno(no). bool set_err(int no); /// Set last error number and default message to any error_info. /// Used by set_err(no). bool set_err_var(smart_device::error_info * err, int no); /// Convert error number into message, used by set_err(no). /// Default implementation returns strerror(no). virtual const char * get_msg_for_errno(int no); /////////////////////////////////////////////////////////////////////////// // Device factory: /// Return device object for device 'name' with some 'type'. /// 'type' is 0 if not specified by user. /// Return 0 on error. /// Default implementation selects between ata, scsi and custom device. virtual smart_device * get_smart_device(const char * name, const char * type); /// Fill 'devlist' with devices of some 'type' with device names /// specified by some optional 'pattern'. /// Return false on error. virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern = 0) = 0; protected: /// Return standard ATA device. virtual ata_device * get_ata_device(const char * name, const char * type) = 0; /// Return standard SCSI device. virtual scsi_device * get_scsi_device(const char * name, const char * type) = 0; /// Autodetect device if no device type specified. virtual smart_device * autodetect_smart_device(const char * name) = 0; /// Return device for platform specific 'type'. /// Default implementation returns 0. virtual smart_device * get_custom_smart_device(const char * name, const char * type); /// Return valid 'type' args accepted by above. /// This is called in get_valid_dev_types_str(). /// Default implementation returns empty string. virtual std::string get_valid_custom_dev_types_str(); /// Return ATA->SCSI filter for SAT or USB. /// Override only if platform needs special handling. virtual ata_device * get_sat_device(const char * type, scsi_device * scsidev); //{ implemented in scsiata.cpp } public: /// Try to detect a SAT device behind a SCSI interface. /// Inquiry data can be passed if available. /// Return appropriate device if yes, otherwise 0. /// Override only if platform needs special handling. virtual ata_device * autodetect_sat_device(scsi_device * scsidev, const unsigned char * inqdata, unsigned inqsize); //{ implemented in scsiata.cpp } /// Get type name for USB device with known VENDOR:PRODUCT ID. /// Return name if device known and supported, otherwise 0. virtual const char * get_usb_dev_type_by_id(int vendor_id, int product_id, int version = -1); //{ implemented in scsiata.cpp } protected: /// Set interface to use, must be called from init(). static void set(smart_interface * intf) { s_instance = intf; } // Implementation private: smart_device::error_info m_err; friend smart_interface * smi(); // below static smart_interface * s_instance; ///< Pointer to the interface object. // Prevent copy/assigment smart_interface(const smart_interface &); void operator=(const smart_interface &); }; ///////////////////////////////////////////////////////////////////////////// // smi() /// Global access to the (usually singleton) smart_interface inline smart_interface * smi() { return smart_interface::s_instance; } ///////////////////////////////////////////////////////////////////////////// #endif // DEV_INTERFACE_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/cissio_freebsd.h�����������������������������������������������������0000644�0000000�0000000�00000014416�11576377613�020243� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*- * Copyright (c) 2001 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/sys/dev/ciss/cissio.h,v 1.6.2.1.6.1 2010/12/21 17:09:25 kensmith Exp $ */ /* * Driver ioctl interface. * * Note that this interface is API-compatible with the Linux implementation * except as noted, and thus this header bears a striking resemblance to * the Linux driver's cciss_ioctl.h. * */ #include <sys/ioccom.h> #pragma pack(1) typedef struct { u_int8_t bus; u_int8_t dev_fn; u_int32_t board_id; } cciss_pci_info_struct; typedef struct { u_int32_t delay; u_int32_t count; } cciss_coalint_struct; typedef char NodeName_type[16]; typedef u_int32_t Heartbeat_type; #define CISS_PARSCSIU2 0x0001 #define CISS_PARCSCIU3 0x0002 #define CISS_FIBRE1G 0x0100 #define CISS_FIBRE2G 0x0200 typedef u_int32_t BusTypes_type; typedef char FirmwareVer_type[4]; typedef u_int32_t DriverVer_type; /* passthrough command definitions */ #define SENSEINFOBYTES 32 #define CISS_MAX_LUN 16 #define LEVEL2LUN 1 #define LEVEL3LUN 0 /* command status value */ #define CMD_SUCCESS 0x0000 #define CMD_TARGET_STATUS 0x0001 #define CMD_DATA_UNDERRUN 0x0002 #define CMD_DATA_OVERRUN 0x0003 #define CMD_INVALID 0x0004 #define CMD_PROTOCOL_ERR 0x0005 #define CMD_HARDWARE_ERR 0x0006 #define CMD_CONNECTION_LOST 0x0007 #define CMD_ABORTED 0x0008 #define CMD_ABORT_FAILED 0x0009 #define CMD_UNSOLICITED_ABORT 0x000A #define CMD_TIMEOUT 0x000B #define CMD_UNABORTABLE 0x000C /* transfer direction */ #define XFER_NONE 0x00 #define XFER_WRITE 0x01 #define XFER_READ 0x02 #define XFER_RSVD 0x03 /* task attribute */ #define ATTR_UNTAGGED 0x00 #define ATTR_SIMPLE 0x04 #define ATTR_HEADOFQUEUE 0x05 #define ATTR_ORDERED 0x06 #define ATTR_ACA 0x07 /* CDB type */ #define TYPE_CMD 0x00 #define TYPE_MSG 0x01 /* command list structure */ typedef union { struct { u_int8_t Dev; u_int8_t Bus:6; u_int8_t Mode:2; } __packed PeripDev; struct { u_int8_t DevLSB; u_int8_t DevMSB:6; u_int8_t Mode:2; } __packed LogDev; struct { u_int8_t Dev:5; u_int8_t Bus:3; u_int8_t Targ:6; u_int8_t Mode:2; } __packed LogUnit; } SCSI3Addr_struct; typedef struct { u_int32_t TargetId:24; u_int32_t Bus:6; u_int32_t Mode:2; SCSI3Addr_struct Target[2]; } __packed PhysDevAddr_struct; typedef struct { u_int32_t VolId:30; u_int32_t Mode:2; u_int8_t reserved[4]; } __packed LogDevAddr_struct; typedef union { u_int8_t LunAddrBytes[8]; SCSI3Addr_struct SCSI3Lun[4]; PhysDevAddr_struct PhysDev; LogDevAddr_struct LogDev; } __packed LUNAddr_struct; typedef struct { u_int8_t CDBLen; struct { u_int8_t Type:3; u_int8_t Attribute:3; u_int8_t Direction:2; } __packed Type; u_int16_t Timeout; u_int8_t CDB[16]; } __packed RequestBlock_struct; typedef union { struct { u_int8_t Reserved[3]; u_int8_t Type; u_int32_t ErrorInfo; } __packed Common_Info; struct { u_int8_t Reserved[2]; u_int8_t offense_size; u_int8_t offense_num; u_int32_t offense_value; } __packed Invalid_Cmd; } __packed MoreErrInfo_struct; typedef struct { u_int8_t ScsiStatus; u_int8_t SenseLen; u_int16_t CommandStatus; u_int32_t ResidualCnt; MoreErrInfo_struct MoreErrInfo; u_int8_t SenseInfo[SENSEINFOBYTES]; } __packed ErrorInfo_struct; typedef struct { LUNAddr_struct LUN_info; /* 8 */ RequestBlock_struct Request; /* 20 */ ErrorInfo_struct error_info; /* 48 */ u_int16_t buf_size; /* 2 */ u_int8_t *buf; /* 4 */ } __packed IOCTL_Command_struct; #ifdef __amd64__ typedef struct { LUNAddr_struct LUN_info; /* 8 */ RequestBlock_struct Request; /* 20 */ ErrorInfo_struct error_info; /* 48 */ u_int16_t buf_size; /* 2 */ u_int32_t buf; /* 4 */ } __packed IOCTL_Command_struct32; #endif /************************************************************************ * Command queue statistics */ #define CISSQ_FREE 0 #define CISSQ_NOTIFY 1 #define CISSQ_COUNT 2 struct ciss_qstat { uint32_t q_length; uint32_t q_max; }; union ciss_statrequest { uint32_t cs_item; struct ciss_qstat cs_qstat; }; /* * Note that we'd normally pass the struct in directly, but * this code is trying to be compatible with other drivers. */ #define CCISS_GETPCIINFO _IOR ('C', 200, cciss_pci_info_struct) #define CCISS_GETINTINFO _IOR ('C', 201, cciss_coalint_struct) #define CCISS_SETINTINFO _IOW ('C', 202, cciss_coalint_struct) #define CCISS_GETNODENAME _IOR ('C', 203, NodeName_type) #define CCISS_SETNODENAME _IOW ('C', 204, NodeName_type) #define CCISS_GETHEARTBEAT _IOR ('C', 205, Heartbeat_type) #define CCISS_GETBUSTYPES _IOR ('C', 206, BusTypes_type) #define CCISS_GETFIRMVER _IOR ('C', 207, FirmwareVer_type) #define CCISS_GETDRIVERVER _IOR ('C', 208, DriverVer_type) #define CCISS_REVALIDVOLS _IO ('C', 209) #define CCISS_PASSTHRU _IOWR ('C', 210, IOCTL_Command_struct) #ifdef __amd64 #define CCISS_PASSTHRU32 _IOWR ('C', 210, IOCTL_Command_struct32) #endif #define CCISS_GETQSTATS _IOWR ('C', 211, union ciss_statrequest) #pragma pack() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/ChangeLog������������������������������������������������������������0000644�0000000�0000000�00000047772�12174532061�016655� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������$Id: ChangeLog 3841 2013-07-26 17:38:57Z chrfranke $ 2013-07-26 Christian Franke <franke@computer.org> smartmontools 6.2 2013-07-25 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: ADATA SP900 - Transcend CompactFlash Cards: *GCF150 - Hitachi/HGST Travelstar 5K750: Apple OEM - Hitachi/HGST Travelstar Z7K500 - Hitachi/HGST Travelstar 7K750 - Hitachi Deskstar 5K3000: *BLE630 OEM - Seagate Constellation ES.3 - Western Digital Caviar Blue (SATA): Rename, add WD1602ABKS - Western Digital Caviar Blue (SATA 6Gb/s): Rename, add WD10EZEX - USB: Toshiba Canvio 3.0 Portable Hard Drive (0x0480:0xa007) - USB: Toshiba Canvio Desktop (0x0480:0xd010) - USB: Seagate FreeAgent Desk (0x0bc2:0x3008) - USB: Sharkoon 2-Bay RAID Box (0x6795:0x2756) 2013-07-21 Christian Franke <franke@computer.org> utility.cpp: Add check for empty subexpressions in regular expressions. 2013-07-21 Christian Franke <franke@computer.org> drivedb.h: - Crucial/Micron RealSSD C300/M500: Rename, add M500 - SandForce Driven SSDs: Kingston KC300, MS200 - Intel 320 Series SSDs: *A variant - Intel 330/335 Series SSDs: Rename, add 335 Series - Toshiba 2.5" HDD MK..46GSX - Toshiba 2.5" HDD MK..61GSY[N]: Rename, add *GSY variant - Toshiba 2.5" HDD MK..65GSX: *GSXF variant - Toshiba 3.5" HDD DT01ACA... - Seagate Laptop SSHD - Seagate Constellation ES.2: 2GB - USB: Seagate Expansion External (0x0bc2:0x3320) - USB: Seagate Backup Plus Desktop USB 3.0 (0x0bc2:0xa0a1) - USB: WD Elements (0x1058:0x10a2) 2013-07-20 Christian Franke <franke@computer.org> dev_areca.cpp: Fix possible segfault on empty port. 2013-07-20 Christian Franke <franke@computer.org> os_win32/daemon_win32.cpp: Do not install the service as interactive. This is no longer supported since Vista and produces misleading error messages in event log. 2013-07-20 Christian Franke <franke@computer.org> ataprint.cpp: Do not print 'SCT Commands not supported' if SCT is not used (regression from r3825 r3826). smartctl.8.in: Mark '-g/-s wcreorder' as EXPERIMENTAL. 2013-07-18 Christian Franke <franke@computer.org> os_win32.cpp: Add Win-8.1 and 2012r2 to get_os_version_str(), remove 9x/ME and NT4. 2013-07-08 Alex Samorukov <samm@os2.kiev.ua> Add Automake 1.12.2 to the list of supported versions 2013-07-07 Christian Franke <franke@computer.org> configure.ac: Support SVN 1.8 working copy format. 2013-07-06 Alex Samorukov <samm@os2.kiev.ua> smartctl: Added ATA Write Cache Reordering control using "-g wcreorder" and "-s wcreorder[,on|off]" options (bug #221) smartctl: minor formatting fixes 2013-07-05 Alex Samorukov <samm@os2.kiev.ua> HPT RAID support: maximum disk number now is 128 (#281) 2013-06-28 Alex Samorukov <samm@os2.kiev.ua> drivedb.h: - Apacer SDM4 2Gb SSD 2013-06-17 Alex Samorukov <samm@os2.kiev.ua> scsicmds.cpp: fix build on RedHat 9 os_freebsd.cpp: skip port multipliers on FreeBSD drivedb.h: - OWC Mercury EXTREME Pro 6G SSD (from #277) - USB: Fujitsu SATA-to-USB3.0 bridge chip (#280) 2013-06-12 Alex Samorukov <samm@os2.kiev.ua> drivedb.h: - JMicron SSD: P400e/P400m series 2013-06-09 Christian Franke <franke@computer.org> INSTALL, NEWS, README, WARNINGS: Update SVN repository URLs. 2013-06-09 Christian Franke <franke@computer.org> os_win32/smartd_warning.cmd: Using %DATE% in temp file names breaks the script if localized date contains '/' (This fix is already included in smartmontools-6.1-2.win32-setup.exe). 2013-06-06 Christian Franke <franke@computer.org> os_win32/update-smart-drivedb.nsi: Use new SVN repository for download. 2013-06-04 Christian Franke <franke@computer.org> update-smart-drivedb.in: Use new sourceforge code browser for download. 2013-04-20 Christian Franke <franke@computer.org> drivedb.h: - InnoDisk InnoLite SATADOM D150QV-L SSDs - Intel 313 Series SSDs - Intel 330 Series SSDs: 240GB - JMicron based SSDs: Kingston V200 (ticket #267) - Samsung based SSDs: SM843T Series 2013-04-20 Christian Franke <franke@computer.org> configure.ac: Linux: Try 'hostname -y' if 'nishostname' is missing. 2013-04-18 Christian Franke <franke@computer.org> configure.ac, smartd_warning.sh.in: Add platform specific commands for host and domain names. os_win32/smartd_warning.cmd: Use WMI for DNS domain name. 2013-04-18 Christian Franke <franke@computer.org> scsicmds.cpp, scsiprint.cpp: Silence -Wmaybe-uninitialized warning (g++ 4.8.0 with -flto). 2013-03-29 Christian Franke <franke@computer.org> os_darwin.cpp: Silence -Wself-assign warning (ticket #266). os_darwin.cpp, os_netbsd.cpp, os_os2.cpp, os_qnxnto.cpp, os_solaris.cpp: Remove dummy functions no longer called since r3192. 2013-03-27 Christian Franke <franke@computer.org> os_win32.cpp: Silence -Wunused-local-typedefs warning. 2013-03-24 Christian Franke <franke@computer.org> dev_areca.cpp: Add casts to silence C++11 -Wnarrowing warning from g++ 4.8. 2013-03-24 Christian Franke <franke@computer.org> Windows: Compile fixes for 64-bit Cygwin. It uses LP64 model instead of LLP64 (64-bit MSVC, MinGW). 2013-03-16 Christian Franke <franke@computer.org> smartmontools 6.1 2013-03-15 Christian Franke <franke@computer.org> os_win32.cpp: Support device names /dev/sd[a-z][a-z] (ticket #240). Enhance DEVICESCAN to 128 drives. Add '-d [TYPE,]pd' option. smartctl.8.in, smartd.8.in: Document these enhancements. 2013-03-14 Christian Franke <franke@computer.org> drivedb.h: - Seagate Barracuda 7200.14: Fix regex for new firmware version. 2013-03-13 Christian Franke <franke@computer.org> drivedb.h: - USB: Prolific PL3507 (0x067b:0x3507): works with '-d usbjmicron,p' 2013-03-13 Christian Franke <franke@computer.org> Create branch RELEASE_6_0_DRIVEDB with last drivedb.h file compatible with smartmontools 6.0. 2013-03-13 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: Fix format of attribute 198 (ticket #258). - SandForce Driven SSDs: Corsair Force GS - Indilinx Barefoot_2/Everest/Martini based SSDs: OCZ VERTEX PLUS R2 - Samsung/Seagate SpinPoint M8: 320GB, 640GB - Seagate Momentus Thin - Quantum Fireball EX: 10.2GB 2013-03-07 Christian Franke <franke@computer.org> ataidentify.cpp, ataprint.cpp: ACS-3 updates. ataprint.cpp: Improve device statistics error messages. 2013-03-06 Christian Franke <franke@computer.org> smartd_warning.sh.in: Support BSD variant of 'hostname' command which prints FQDN. Add Windows domain name (Cygwin). 2013-03-01 Douglas Gilbert <dgilbert@interlog.com> scsicmds.h, scsicmds.cpp, scsiprint.cpp: - for SCSI disks prefer READ DEFECT(12) for finding the grown defect list length (previously used READ DEFECT(10) only) 2013-03-01 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: Transcend SSD320 - Intel 520 Series SSDs: OEM variant - JMicron based SSDs: Transcend SSD25 IDE - HGST Travelstar 7K1000 - Seagate Desktop HDD.15 - Seagate LD25.2 - Western Digital RE4 (SATA 6Gb/s) - USB: Fujitsu/Zalman ZM-VE300 (0x04c5:0x2028) 2013-02-23 Christian Franke <franke@computer.org> drivedb.h: Crucial/Micron RealSSD C300: Remove bogus trailing '|' from regex (Regression from r3772). 2013-02-16 Douglas Gilbert <dgilbert@interlog.com> scsicmds.h, scsicmds.cpp, scsiprint.h, scsiprint.cpp: - for SCSI disks, in 'smartctl --info' report physical block size and lowest LBA alignement (if PB size different from LB size); logical block provisioning status (if any); and disk protection (a.k.a. DIF) type 2013-02-19 Alex Samorukov <samm@os2.kiev.ua> atacmds.cpp: fixed scttemphist on LE machines, including PPC. Patch and report provided by Roger Roehrig. 2013-02-16 Douglas Gilbert <dgilbert@interlog.com> scsicmds.h, scsicmds.cpp, scsiprint.h, scsiprint.cpp: - SCSI VPD work; improve rotation rate reporting and add form factor 2013-02-14 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: Kingston V+ 200, Mushkin Chronos deluxe, OCZ Talos 2 - Plextor M3 (Pro) Series SSDs 2013-02-13 Christian Franke <franke@computer.org> drivedb.h: - Crucial/Micron RealSSD C300: new separate entry - Crucial/Micron RealSSD m4/C400: firmware bug warning 2013-02-10 Alex Samorukov <samm@os2.kiev.ua> os_freebsd.cpp: adding device type fix for devices on MPT controllers. 2013-02-06 Christian Franke <franke@computer.org> drivedb.h: - Seagate Samsung SpinPoint M8U (USB) - Hitachi/HGST Travelstar Z5K500 - Hitachi/HGST Travelstar 5K750 - Hitachi/HGST Deskstar 7K4000 - Toshiba 2.5" HDD MK..37GSX - Toshiba 2.5" HDD MK..65GSX: GSXN variant - Toshiba 2.5" HDD MQ01ABD... - Seagate Momentus 7200.5 - Western Digital Caviar Green (AF, SATA 6Gb/s): 2TB - USB: Samsung M3 Portable USB 3.0 (0x04e8:0x61b6) - USB: LaCie Rugged Mini USB 3.0 (0x059f:0x1051) - Change short attribute names required before r3343. 2013-02-05 Christian Franke <franke@computer.org> smartd.cpp: Fix allocation of buffer passed to putenv(). Using putenv("NAME") to unset NAME is not portable. 2013-02-05 Christian Franke <franke@computer.org> do_release: New Signing Key. 2013-01-31 Christian Franke <franke@computer.org> dev_areca.h: Use the C++ way to specify unused arguments. This silences -Wself-assign warning from clang++. 2013-01-30 Christian Franke <franke@computer.org> configure.ac: Use AC_CHECK_TOOL for winmc and windres. 2013-01-30 Christian Franke <franke@computer.org> Windows smartd: Install service with delayed auto start enabled. 2013-01-26 Christian Franke <franke@computer.org> Windows smartd: Add eventlog MESSAGETABLE resource. Install/remove smartd.exe as event message file. Remove syslogevt.exe tool. 2013-01-26 Christian Franke <franke@computer.org> Windows: Add required string CompanyName to VERSIONINFO. 2013-01-23 Christian Franke <franke@computer.org> Windows: Add VERSIONINFO resource to exe files. 2013-01-23 Christian Franke <franke@computer.org> drivedb.h: - Crucial/Micron RealSSD C300/C400/m4: m4 mSATA variant - Indilinx Barefoot 3 based SSDs - Intel DC S3700 Series SSDs - Samsung based SSD: Samsung SSD 840 Series 2013-01-18 Christian Franke <franke@computer.org> AUTHORS: Convert to UTF-8. Sort names. Replace tabs. 2013-01-18 Christian Franke <franke@computer.org> Rename configure.in to configure.ac to silence warning from new automake. autogen.sh: automake 1.12.5 is OK. 2013-01-16 Christian Franke <franke@computer.org> atacmds.cpp: Fix assignment of BYTEORDER from -v option (Regression from r3719). 2013-01-13 Ole Jørgen LegÃ¥rd <ole@smartautomation.no> os_qnxnto.cpp: Fix include of errno.h. 2013-01-12 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: Mushkin Callisto deluxe, SuperSSpeed S301 - Intel 320 Series SSDs: 'B' (7mm) variant (ticket #257) - SAMSUNG SpinPoint F1 EG - SAMSUNG SpinPoint P80: SP0401N/TJ100-30 - Western Digital Caviar Black: 4TB - Western Digital Caviar Black (AF): Remove non-AF models - Western Digital My Passport (USB, AF): 5000L, 10J variants - USB: WD My Passport USB 3.0 (0x1058:0x07a8) - USB: WD My Book Studio II (0x1058:0x1105) 2013-01-02 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: ADATA S396, Kingston 3K, V+ - Indilinx Everest/Martini based SSDs: OCZ VERTEX PLUS - Samsung based SSD: Samsung SSD 840 PRO Series 2013-01-02 Christian Franke <franke@computer.org> Add '-d usbjmicron,p' device type for Prolific USB bridges. Based on patch provided by Edward Sheldrake. 2013-01-01 Christian Franke <franke@computer.org> smartd: Use Attribute 190 for temperature (-W) if 194 is not present. 2013-01-01 Christian Franke <franke@computer.org> Happy New Year! Update copyright year in version info. 2012-12-16 Alex Samorukov <samm@os2.kiev.ua> os_freebsd.cpp: WRITE LOG on LSI/Megaraid should work fine, disable check, problem was linux related. os_linux.cpp: Implemented autoscan for the megaraid SAS controolers. os_linux.cpp: fix WRITE LOG command in SAT layer for -d megaraid. Reason was direction flag always set to READ. os_linux.cpp: unblock autodetection for the SAT drives in -d megaraid. 2012-12-14 Christian Franke <franke@computer.org> man pages: Fix usage of Hyphen (-) and Minus sign (\-). 2012-12-13 Christian Franke <franke@computer.org> man pages: Update EXPERIMENTAL notes. Fix spelling (Red Hat Bugzilla 665028). 2012-12-13 Christian Franke <franke@computer.org> ataprint.cpp: Print Additional Product Identifier (OEM Id). 2012-12-13 Stanislav Brabec <sbrabec@suse.cz> Update FSF postal address in all files. 2012-12-12 Christian Franke <franke@computer.org> smartctl.cpp: Remove include <new> for QNXNTO. Should only be needed if placement new is used. smartd.cpp: Remove very old _GNU_SOURCE define. It was added 10 years ago in r147. It is not (or no longer) needed and has an unwanted side effect (__USE_MINGW_ANSI_STDIO) on MinGW. 2012-12-11 Christian Franke <franke@computer.org> smartd.cpp: Add '-w PATH, --warnexec=PATH' option. smartd.8.in: Document this option. 2012-12-11 Christian Franke <franke@computer.org> smartd.cpp: Add '-d ignore' directive. smartd.conf.5.in: Document '-d ignore'. Add DEVICESCAN example. Remove duplicate and outdated info about device scanning. smartd.8.in: Add notes about RAID controllers to device scanning info. 2012-12-11 Stanislav Brabec <sbrabec@suse.cz> * smartd.initd.in: SUSE: Added sysconfig options to disable persistent state writes, attribute log and set arbitrary smartd options. 2012-12-03 Christian Franke <franke@computer.org> Avoid usage of strcpy(), strcat(), sprintf(). Use snprintf() instead or change type to std::string. Use array references instead of char pointers for parameters. 2012-12-03 Christian Franke <franke@computer.org> smartd.cpp: Ignore a device from DEVICESCAN if a preceding smartd.conf entry for the same device exists. 2012-11-28 Christian Franke <franke@computer.org> smartd.conf.5.in: Document smartd_warning.sh/cmd scripts and the new environment variables. Makefile.am: Replace smartd_warning.* paths on man pages. Reformat long sed commands. 2012-11-27 Christian Franke <franke@computer.org> smartd.cpp: Remove trailing newlines from some MailWarning() strings. os_win32/smartd_warning.cmd: Fix SMARTD_MESSAGE with parentheses. 2012-11-25 Alex Samorukov <samm@os2.kiev.ua> OpenBSD: remove dummy functions 2012-11-24 Christian Franke <franke@computer.org> Windows: Add tool wtssendmsg.exe based on no longer used module os_win32/wtssendmsg.cpp. os_win32/smartd_warning.cmd: Fix wtssendmsg call. os_win32/installer.nsi: Install smartd_warning.cmd and wtssendmsg.exe. Fix uninstall of old ChangeLog. 2012-11-23 Christian Franke <franke@computer.org> Move MSVC10 project files to new directory os_win32/vc10. 2012-11-22 Christian Franke <franke@computer.org> smartd: Move warning message formatting and mailer/command startup to new script SYSCONFDIR/smartd_warning.sh (Windows: smartd_warning.cmd). Add environment variables SMARTD_PREVCNT and SMARTD_NEXTDAYS. Remove host/domainname related code from smartd.cpp and configure.in 2012-11-22 Alex Samorukov <samm@os2.kiev.ua> smartctl: implemeted support for -g/-s rcache and -g/-s wcache for SCSI devices to control read/write device cache. 2012-11-19 Alex Samorukov <samm@os2.kiev.ua> smartctl: supports progress indicator on selftests smartctl: prints rotation speed for SCSI drives, if supported smartctl: add headers to SCSI output, fix data blocks formatting, trim identification data os_linux.cpp: add autodetection for PERC H700 array smartd: trim SCSI vendor/model/serial before creating state files 2012-11-18 Alex Samorukov <samm@os2.kiev.ua> smartd.cpp: implement error counters and temperature saving to the attrlog file for SCSI devices. smartd.cpp: added reset_warning_mail() if device is working for SCSI 2012-11-18 Christian Franke <franke@computer.org> drivedb.h: Western Digital Caviar Green: Add -F xerrorlba 2012-11-17 Alex Samorukov <samm@os2.kiev.ua> smartd.cpp: print lu_id for SPC devices, it is supported by standard smartd.cpp: added initial state file support for the SCSI devices smartd.cpp: add S/N to SCSI device identifier, lu_id is not available on some drives. smartd.cpp: fix warning for SCSI drives with self test in progress (#249) drivedb.h: added -F xerrorlba flag Seagate Barracuda LP/CC32 2012-11-09 Christian Franke <franke@computer.org> Windows smartd: Allow quoting of '-M exec' argument to support path names with spaces. 2012-11-09 Christian Franke <franke@computer.org> ataprint.cpp: Rework smartctl -l directory output. Add R/W, R/O info. Report identical logs in one line. 2012-11-09 Alex Samorukov <samm@os2.kiev.ua> os_freebsd.cpp: adding handling of SCSI devices exported with mfip driver. FreeBSD changing PDT code to 0x1f and we are changing it back to 0x00 (direct-access block device). os_freebsd.cpp: improved error handling for the ATA devices 2012-11-04 Christian Franke <franke@computer.org> drivedb.h: - SandForce Driven SSDs: Mushkin Chronos - Indilinx Everest/Martini based SSDs: OCZ AGILITY4 - Intel 710 Series SSDs: Add attribute 174 - JMicron based SSDs: KINGSTON SSDNOW 30GB - Hitachi Deskstar 7K1000.C: *CLA330 - Seagate DiamondMax 23, Barracuda 7200.12, 7200.14 (AF), LP, Green (AF): no warnings for newer firmware versions - Western Digital Caviar Green (AF, SATA 6Gb/s): rename, add 1TB - USB: Toshiba Stor.E (0x0930:0x0b1[9a]) - USB: Verbatim Store'n'Go (0x18a5:0x022b) 2012-11-02 Alex Samorukov <samm@os2.kiev.ua> os_freebsd.cpp: disabling 48bit commands on legacy ATA controllers in ATACAM mode because of kernel bug. 2012-10-31 Christian Franke <franke@computer.org> atacmdnames.cpp: Update for ATA-8-ACS, ACS-2, ACS-3. ataidentify.cpp: Mark retired/obsolete values. ataprint.cpp: Add new ACS-3 logs, mark obsolete logs. 2012-10-27 Alex Samorukov <samm@os2.kiev.ua> os_freebsd.cpp: Have smartd prefer real device names over passN. Patch provided by dnelson, see ticket #21 os_freebsd.cpp: fix 48-bit support for ATA legacy controllers in ATACAM mode, patch provided by Alexander Motin 2012-10-25 Christian Franke <franke@computer.org> atacmds.cpp: Return error for get SCT ERC if ATA registers are unchanged after SMART_WRITE_LOG command (see ticket #245). 2012-10-24 Christian Franke <franke@computer.org> dev_areca.cpp: Add missing parameter check to ata_pass_through(). Update Areca info on man pages. 2012-10-24 Christian Franke <franke@computer.org> dev_interface: Rework ATA parameter checks, use new flags ata_device::supports_* for new ata_cmd_is_supported(). Replace ata_cmd_is_ok() by ata_cmd_is_supported() in scsiata.cpp and os_win32.cpp. 2012-10-19 Alex Samorukov <samm@os2.kiev.ua> os_freebsd.cpp - fixed 3ware twe controller support broken by inerface migration. 2012-10-18 Christian Franke <franke@computer.org> utility.cpp: Add missing errno clear in split_selective_arg() (Debian bug 690108). Remove unused function split_report_arg2(). 2012-10-18 Christian Franke <franke@computer.org> os_win32.cpp: define _WIN32. This fixes build on Cygwin with new w32api-headers. 2012-10-18 Alex Samorukov <samm@os2.kiev.ua> Compile fixes for Areca patch on FreeBSD. Added support for the /dev/twsX (3ware 9750) controller on FreeBSD. Manual pages updated with /dev/twsX device FreeBSD: Migrate 3ware interface to ata_pass_through() FreeBSD: fix missing drives detection on -d 3ware FreeBSD: 3ware - do not pass buffers direcly, use memcpy() instead FreeBSD: improved detection of 3ware/LSI controllers 2012-10-16 Christian Franke <franke@computer.org> Compile fixes for Areca patch: Add missing includes. Add GPL header. Add dev_areca.* to configure.in and Makefile.am. 2012-10-16 Hank Wu <hank@areca.com.tw> Move common Areca code from os_freebsd.cpp, os_linux.cpp, os_win32.cpp to new files dev_areca.h, dev_areca.cpp. Add SAS support for FreeBSD and Linux. 2012-10-10 Christian Franke <franke@computer.org> Rename old CHANGELOG to ChangeLog-5.0-6.0. Start new ChangeLog. 2012-10-10 Christian Franke <franke@computer.org> smartmontools 6.0 ������smartmontools-6.2+svn3841.orig/knowndrives.cpp������������������������������������������������������0000644�0000000�0000000�00000062610�12057213545�020147� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * knowndrives.cpp * * Home page of code is: http://smartmontools.sourceforge.net * Address of support mailing list: smartmontools-support@lists.sourceforge.net * * Copyright (C) 2003-11 Philip Williams, Bruce Allen * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "config.h" #include "int64.h" #include <stdio.h> #include "atacmds.h" #include "knowndrives.h" #include "utility.h" #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifdef _WIN32 #include <io.h> // access() #endif #include <stdexcept> const char * knowndrives_cpp_cvsid = "$Id: knowndrives.cpp 3719 2012-12-03 21:19:33Z chrfranke $" KNOWNDRIVES_H_CVSID; #define MODEL_STRING_LENGTH 40 #define FIRMWARE_STRING_LENGTH 8 #define TABLEPRINTWIDTH 19 // Builtin table of known drives. // Used as a default if not read from // "/usr/{,/local}share/smartmontools/drivedb.h" // or any other file specified by '-B' option, // see read_default_drive_databases() below. // The drive_settings structure is described in drivedb.h. const drive_settings builtin_knowndrives[] = { #include "drivedb.h" }; /// Drive database class. Stores custom entries read from file. /// Provides transparent access to concatenation of custom and /// default table. class drive_database { public: drive_database(); ~drive_database(); /// Get total number of entries. unsigned size() const { return m_custom_tab.size() + m_builtin_size; } /// Get number of custom entries. unsigned custom_size() const { return m_custom_tab.size(); } /// Array access. const drive_settings & operator[](unsigned i); /// Append new custom entry. void push_back(const drive_settings & src); /// Append builtin table. void append(const drive_settings * builtin_tab, unsigned builtin_size) { m_builtin_tab = builtin_tab; m_builtin_size = builtin_size; } private: const drive_settings * m_builtin_tab; unsigned m_builtin_size; std::vector<drive_settings> m_custom_tab; std::vector<char *> m_custom_strings; const char * copy_string(const char * str); drive_database(const drive_database &); void operator=(const drive_database &); }; drive_database::drive_database() : m_builtin_tab(0), m_builtin_size(0) { } drive_database::~drive_database() { for (unsigned i = 0; i < m_custom_strings.size(); i++) delete [] m_custom_strings[i]; } const drive_settings & drive_database::operator[](unsigned i) { return (i < m_custom_tab.size() ? m_custom_tab[i] : m_builtin_tab[i - m_custom_tab.size()] ); } void drive_database::push_back(const drive_settings & src) { drive_settings dest; dest.modelfamily = copy_string(src.modelfamily); dest.modelregexp = copy_string(src.modelregexp); dest.firmwareregexp = copy_string(src.firmwareregexp); dest.warningmsg = copy_string(src.warningmsg); dest.presets = copy_string(src.presets); m_custom_tab.push_back(dest); } const char * drive_database::copy_string(const char * src) { size_t len = strlen(src); char * dest = new char[len+1]; memcpy(dest, src, len+1); try { m_custom_strings.push_back(dest); } catch (...) { delete [] dest; throw; } return dest; } /// The drive database. static drive_database knowndrives; // Return true if modelfamily string describes entry for USB ID static bool is_usb_modelfamily(const char * modelfamily) { return !strncmp(modelfamily, "USB:", 4); } // Return true if entry for USB ID static inline bool is_usb_entry(const drive_settings * dbentry) { return is_usb_modelfamily(dbentry->modelfamily); } // Compile regular expression, print message on failure. static bool compile(regular_expression & regex, const char *pattern) { if (!regex.compile(pattern, REG_EXTENDED)) { pout("Internal error: unable to compile regular expression \"%s\": %s\n" "Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n", pattern, regex.get_errmsg()); return false; } return true; } // Compile & match a regular expression. static bool match(const char * pattern, const char * str) { regular_expression regex; if (!compile(regex, pattern)) return false; return regex.full_match(str); } // Searches knowndrives[] for a drive with the given model number and firmware // string. If either the drive's model or firmware strings are not set by the // manufacturer then values of NULL may be used. Returns the entry of the // first match in knowndrives[] or 0 if no match if found. static const drive_settings * lookup_drive(const char * model, const char * firmware) { if (!model) model = ""; if (!firmware) firmware = ""; for (unsigned i = 0; i < knowndrives.size(); i++) { // Skip USB entries if (is_usb_entry(&knowndrives[i])) continue; // Check whether model matches the regular expression in knowndrives[i]. if (!match(knowndrives[i].modelregexp, model)) continue; // Model matches, now check firmware. "" matches always. if (!( !*knowndrives[i].firmwareregexp || match(knowndrives[i].firmwareregexp, firmware))) continue; // Found return &knowndrives[i]; } // Not found return 0; } // Parse drive or USB options in preset string, return false on error. static bool parse_db_presets(const char * presets, ata_vendor_attr_defs * defs, firmwarebug_defs * firmwarebugs, std::string * type) { for (int i = 0; ; ) { i += strspn(presets+i, " \t"); if (!presets[i]) break; char opt, arg[80+1+13]; int len = -1; if (!(sscanf(presets+i, "-%c %80[^ ]%n", &opt, arg, &len) >= 2 && len > 0)) return false; if (opt == 'v' && defs) { // Parse "-v N,format[,name]" if (!parse_attribute_def(arg, *defs, PRIOR_DATABASE)) return false; } else if (opt == 'F' && firmwarebugs) { firmwarebug_defs bug; if (!parse_firmwarebug_def(arg, bug)) return false; // Don't set if user specified '-F none'. if (!firmwarebugs->is_set(BUG_NONE)) firmwarebugs->set(bug); } else if (opt == 'd' && type) { // TODO: Check valid types *type = arg; } else return false; i += len; } return true; } // Parse '-v' and '-F' options in preset string, return false on error. static inline bool parse_presets(const char * presets, ata_vendor_attr_defs & defs, firmwarebug_defs & firmwarebugs) { return parse_db_presets(presets, &defs, &firmwarebugs, 0); } // Parse '-d' option in preset string, return false on error. static inline bool parse_usb_type(const char * presets, std::string & type) { return parse_db_presets(presets, 0, 0, &type); } // Parse "USB: [DEVICE] ; [BRIDGE]" string static void parse_usb_names(const char * names, usb_dev_info & info) { int n1 = -1, n2 = -1, n3 = -1; sscanf(names, "USB: %n%*[^;]%n; %n", &n1, &n2, &n3); if (0 < n1 && n1 < n2) info.usb_device.assign(names+n1, n2-n1); else sscanf(names, "USB: ; %n", &n3); if (0 < n3) info.usb_bridge = names+n3; } // Search drivedb for USB device with vendor:product ID. int lookup_usb_device(int vendor_id, int product_id, int bcd_device, usb_dev_info & info, usb_dev_info & info2) { // Format strings to match char usb_id_str[16], bcd_dev_str[16]; snprintf(usb_id_str, sizeof(usb_id_str), "0x%04x:0x%04x", vendor_id, product_id); if (bcd_device >= 0) snprintf(bcd_dev_str, sizeof(bcd_dev_str), "0x%04x", bcd_device); else bcd_dev_str[0] = 0; int found = 0; for (unsigned i = 0; i < knowndrives.size(); i++) { const drive_settings & dbentry = knowndrives[i]; // Skip drive entries if (!is_usb_entry(&dbentry)) continue; // Check whether USB vendor:product ID matches if (!match(dbentry.modelregexp, usb_id_str)) continue; // Parse '-d type' usb_dev_info d; if (!parse_usb_type(dbentry.presets, d.usb_type)) return 0; // Syntax error parse_usb_names(dbentry.modelfamily, d); // If two entries with same vendor:product ID have different // types, use bcd_device (if provided by OS) to select entry. if ( *dbentry.firmwareregexp && *bcd_dev_str && match(dbentry.firmwareregexp, bcd_dev_str)) { // Exact match including bcd_device info = d; found = 1; break; } else if (!found) { // First match without bcd_device info = d; found = 1; } else if (info.usb_type != d.usb_type) { // Another possible match with different type info2 = d; found = 2; break; } // Stop search at first matching entry with empty bcd_device if (!*dbentry.firmwareregexp) break; } return found; } // Shows one entry of knowndrives[], returns #errors. static int showonepreset(const drive_settings * dbentry) { // Basic error check if (!( dbentry && dbentry->modelfamily && dbentry->modelregexp && *dbentry->modelregexp && dbentry->firmwareregexp && dbentry->warningmsg && dbentry->presets )) { pout("Invalid drive database entry. Please report\n" "this error to smartmontools developers at " PACKAGE_BUGREPORT ".\n"); return 1; } bool usb = is_usb_entry(dbentry); // print and check model and firmware regular expressions int errcnt = 0; regular_expression regex; pout("%-*s %s\n", TABLEPRINTWIDTH, (!usb ? "MODEL REGEXP:" : "USB Vendor:Product:"), dbentry->modelregexp); if (!compile(regex, dbentry->modelregexp)) errcnt++; pout("%-*s %s\n", TABLEPRINTWIDTH, (!usb ? "FIRMWARE REGEXP:" : "USB bcdDevice:"), *dbentry->firmwareregexp ? dbentry->firmwareregexp : ".*"); // preserve old output (TODO: Change) if (*dbentry->firmwareregexp && !compile(regex, dbentry->firmwareregexp)) errcnt++; if (!usb) { pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", dbentry->modelfamily); // if there are any presets, then show them firmwarebug_defs firmwarebugs; bool first_preset = true; if (*dbentry->presets) { ata_vendor_attr_defs defs; if (!parse_presets(dbentry->presets, defs, firmwarebugs)) { pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); errcnt++; } for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) { if (defs[i].priority != PRIOR_DEFAULT) { std::string name = ata_get_smart_attr_name(i, defs); // Use leading zeros instead of spaces so that everything lines up. pout("%-*s %03d %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", i, name.c_str()); // Check max name length suitable for smartctl -A output const unsigned maxlen = 23; if (name.size() > maxlen) { pout("%*s\n", TABLEPRINTWIDTH+6+maxlen, "Error: Attribute name too long ------^"); errcnt++; } first_preset = false; } } } if (first_preset) pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required."); // describe firmwarefix for (int b = BUG_NOLOGDIR; b <= BUG_XERRORLBA; b++) { if (!firmwarebugs.is_set((firmwarebug_t)b)) continue; const char * fixdesc; switch ((firmwarebug_t)b) { case BUG_NOLOGDIR: fixdesc = "Avoids reading GP/SMART Log Directories (same as -F nologdir)"; break; case BUG_SAMSUNG: fixdesc = "Fixes byte order in some SMART data (same as -F samsung)"; break; case BUG_SAMSUNG2: fixdesc = "Fixes byte order in some SMART data (same as -F samsung2)"; break; case BUG_SAMSUNG3: fixdesc = "Fixes completed self-test reported as in progress (same as -F samsung3)"; break; case BUG_XERRORLBA: fixdesc = "Fixes LBA byte ordering in Ext. Comprehensive SMART error log (same as -F xerrorlba)"; break; default: fixdesc = "UNKNOWN"; errcnt++; break; } pout("%-*s %s\n", TABLEPRINTWIDTH, "OTHER PRESETS:", fixdesc); } } else { // Print USB info usb_dev_info info; parse_usb_names(dbentry->modelfamily, info); pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Device:", (!info.usb_device.empty() ? info.usb_device.c_str() : "[unknown]")); pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Bridge:", (!info.usb_bridge.empty() ? info.usb_bridge.c_str() : "[unknown]")); if (*dbentry->presets && !parse_usb_type(dbentry->presets, info.usb_type)) { pout("Syntax error in USB type string \"%s\"\n", dbentry->presets); errcnt++; } pout("%-*s %s\n", TABLEPRINTWIDTH, "USB Type", (!info.usb_type.empty() ? info.usb_type.c_str() : "[unsupported]")); } // Print any special warnings if (*dbentry->warningmsg) pout("%-*s %s\n", TABLEPRINTWIDTH, "WARNINGS:", dbentry->warningmsg); return errcnt; } // Shows all presets for drives in knowndrives[]. // Returns #syntax errors. int showallpresets() { // loop over all entries in the knowndrives[] table, printing them // out in a nice format int errcnt = 0; for (unsigned i = 0; i < knowndrives.size(); i++) { errcnt += showonepreset(&knowndrives[i]); pout("\n"); } pout("Total number of entries :%5u\n" "Entries read from file(s):%5u\n\n", knowndrives.size(), knowndrives.custom_size()); pout("For information about adding a drive to the database see the FAQ on the\n"); pout("smartmontools home page: " PACKAGE_HOMEPAGE "\n"); if (errcnt > 0) pout("\nFound %d syntax error(s) in database.\n" "Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n", errcnt); return errcnt; } // Shows all matching presets for a drive in knowndrives[]. // Returns # matching entries. int showmatchingpresets(const char *model, const char *firmware) { int cnt = 0; const char * firmwaremsg = (firmware ? firmware : "(any)"); for (unsigned i = 0; i < knowndrives.size(); i++) { if (!match(knowndrives[i].modelregexp, model)) continue; if ( firmware && *knowndrives[i].firmwareregexp && !match(knowndrives[i].firmwareregexp, firmware)) continue; // Found if (++cnt == 1) pout("Drive found in smartmontools Database. Drive identity strings:\n" "%-*s %s\n" "%-*s %s\n" "match smartmontools Drive Database entry:\n", TABLEPRINTWIDTH, "MODEL:", model, TABLEPRINTWIDTH, "FIRMWARE:", firmwaremsg); else if (cnt == 2) pout("and match these additional entries:\n"); showonepreset(&knowndrives[i]); pout("\n"); } if (cnt == 0) pout("No presets are defined for this drive. Its identity strings:\n" "MODEL: %s\n" "FIRMWARE: %s\n" "do not match any of the known regular expressions.\n", model, firmwaremsg); return cnt; } // Shows the presets (if any) that are available for the given drive. void show_presets(const ata_identify_device * drive) { char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1]; // get the drive's model/firmware strings ata_format_id_string(model, drive->model, sizeof(model)-1); ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1); // and search to see if they match values in the table const drive_settings * dbentry = lookup_drive(model, firmware); if (!dbentry) { // no matches found pout("No presets are defined for this drive. Its identity strings:\n" "MODEL: %s\n" "FIRMWARE: %s\n" "do not match any of the known regular expressions.\n" "Use -P showall to list all known regular expressions.\n", model, firmware); return; } // We found a matching drive. Print out all information about it. pout("Drive found in smartmontools Database. Drive identity strings:\n" "%-*s %s\n" "%-*s %s\n" "match smartmontools Drive Database entry:\n", TABLEPRINTWIDTH, "MODEL:", model, TABLEPRINTWIDTH, "FIRMWARE:", firmware); showonepreset(dbentry); } // Searches drive database and sets preset vendor attribute // options in defs and firmwarebugs. // Values that have already been set will not be changed. // Returns pointer to database entry or nullptr if none found const drive_settings * lookup_drive_apply_presets( const ata_identify_device * drive, ata_vendor_attr_defs & defs, firmwarebug_defs & firmwarebugs) { // get the drive's model/firmware strings char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1]; ata_format_id_string(model, drive->model, sizeof(model)-1); ata_format_id_string(firmware, drive->fw_rev, sizeof(firmware)-1); // Look up the drive in knowndrives[]. const drive_settings * dbentry = lookup_drive(model, firmware); if (!dbentry) return 0; if (*dbentry->presets) { // Apply presets if (!parse_presets(dbentry->presets, defs, firmwarebugs)) pout("Syntax error in preset option string \"%s\"\n", dbentry->presets); } return dbentry; } ///////////////////////////////////////////////////////////////////////////// // Parser for drive database files // Abstract pointer to read file input. // Operations supported: c = *p; c = p[1]; ++p; class stdin_iterator { public: explicit stdin_iterator(FILE * f) : m_f(f) { get(); get(); } stdin_iterator & operator++() { get(); return *this; } char operator*() const { return m_c; } char operator[](int i) const { if (i != 1) fail(); return m_next; } private: FILE * m_f; char m_c, m_next; void get(); void fail() const; }; void stdin_iterator::get() { m_c = m_next; int ch = getc(m_f); m_next = (ch != EOF ? ch : 0); } void stdin_iterator::fail() const { throw std::runtime_error("stdin_iterator: wrong usage"); } // Use above as parser input 'pointer'. Can easily be changed later // to e.g. 'const char *' if above is too slow. typedef stdin_iterator parse_ptr; // Skip whitespace and comments. static parse_ptr skip_white(parse_ptr src, const char * path, int & line) { for ( ; ; ++src) switch (*src) { case ' ': case '\t': continue; case '\n': ++line; continue; case '/': switch (src[1]) { case '/': // skip '// comment' ++src; ++src; while (*src && *src != '\n') ++src; if (*src) ++line; break; case '*': // skip '/* comment */' ++src; ++src; for (;;) { if (!*src) { pout("%s(%d): Missing '*/'\n", path, line); return src; } char c = *src; ++src; if (c == '\n') ++line; else if (c == '*' && *src == '/') break; } break; default: return src; } continue; default: return src; } } // Info about a token. struct token_info { char type; int line; std::string value; token_info() : type(0), line(0) { } }; // Get next token. static parse_ptr get_token(parse_ptr src, token_info & token, const char * path, int & line) { src = skip_white(src, path, line); switch (*src) { case '{': case '}': case ',': // Simple token token.type = *src; token.line = line; ++src; break; case '"': // String constant token.type = '"'; token.line = line; token.value = ""; do { for (++src; *src != '"'; ++src) { char c = *src; if (!c || c == '\n' || (c == '\\' && !src[1])) { pout("%s(%d): Missing terminating '\"'\n", path, line); token.type = '?'; token.line = line; return src; } if (c == '\\') { c = *++src; switch (c) { case 'n' : c = '\n'; break; case '\n': ++line; break; case '\\': case '"': break; default: pout("%s(%d): Unknown escape sequence '\\%c'\n", path, line, c); token.type = '?'; token.line = line; continue; } } token.value += c; } // Lookahead to detect string constant concatentation src = skip_white(++src, path, line); } while (*src == '"'); break; case 0: // EOF token.type = 0; token.line = line; break; default: pout("%s(%d): Syntax error, invalid char '%c'\n", path, line, *src); token.type = '?'; token.line = line; while (*src && *src != '\n') ++src; break; } return src; } // Parse drive database from abstract input pointer. static bool parse_drive_database(parse_ptr src, drive_database & db, const char * path) { int state = 0, field = 0; std::string values[5]; bool ok = true; token_info token; int line = 1; src = get_token(src, token, path, line); for (;;) { // EOF is ok after '}', trailing ',' is also allowed. if (!token.type && (state == 0 || state == 4)) break; // Check expected token const char expect[] = "{\",},"; if (token.type != expect[state]) { if (token.type != '?') pout("%s(%d): Syntax error, '%c' expected\n", path, token.line, expect[state]); ok = false; // Skip to next entry while (token.type && token.type != '{') src = get_token(src, token, path, line); state = 0; if (token.type) continue; break; } // Interpret parser state switch (state) { case 0: // ... ^{...} state = 1; field = 0; break; case 1: // {... ^"..." ...} switch (field) { case 1: case 2: if (!token.value.empty()) { regular_expression regex; if (!regex.compile(token.value.c_str(), REG_EXTENDED)) { pout("%s(%d): Error in regular expression: %s\n", path, token.line, regex.get_errmsg()); ok = false; } } else if (field == 1) { pout("%s(%d): Missing regular expression for drive model\n", path, token.line); ok = false; } break; case 4: if (!token.value.empty()) { if (!is_usb_modelfamily(values[0].c_str())) { ata_vendor_attr_defs defs; firmwarebug_defs fix; if (!parse_presets(token.value.c_str(), defs, fix)) { pout("%s(%d): Syntax error in preset option string\n", path, token.line); ok = false; } } else { std::string type; if (!parse_usb_type(token.value.c_str(), type)) { pout("%s(%d): Syntax error in USB type string\n", path, token.line); ok = false; } } } break; } values[field] = token.value; state = (++field < 5 ? 2 : 3); break; case 2: // {... "..."^, ...} state = 1; break; case 3: // {...^}, ... { drive_settings entry; entry.modelfamily = values[0].c_str(); entry.modelregexp = values[1].c_str(); entry.firmwareregexp = values[2].c_str(); entry.warningmsg = values[3].c_str(); entry.presets = values[4].c_str(); db.push_back(entry); } state = 4; break; case 4: // {...}^, ... state = 0; break; default: pout("Bad state %d\n", state); return false; } src = get_token(src, token, path, line); } return ok; } // Read drive database from file. bool read_drive_database(const char * path) { stdio_file f(path, "r" #ifdef __CYGWIN__ // Allow files with '\r\n'. "t" #endif ); if (!f) { pout("%s: cannot open drive database file\n", path); return false; } return parse_drive_database(parse_ptr(f), knowndrives, path); } // Get path for additional database file const char * get_drivedb_path_add() { #ifndef _WIN32 return SMARTMONTOOLS_SYSCONFDIR"/smart_drivedb.h"; #else static std::string path = get_exe_dir() + "/drivedb-add.h"; return path.c_str(); #endif } #ifdef SMARTMONTOOLS_DRIVEDBDIR // Get path for default database file const char * get_drivedb_path_default() { #ifndef _WIN32 return SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h"; #else static std::string path = get_exe_dir() + "/drivedb.h"; return path.c_str(); #endif } #endif // Read drive databases from standard places. bool read_default_drive_databases() { // Read file for local additions: /{,usr/local/}etc/smart_drivedb.h const char * db1 = get_drivedb_path_add(); if (!access(db1, 0)) { if (!read_drive_database(db1)) return false; } #ifdef SMARTMONTOOLS_DRIVEDBDIR // Read file from package: /usr/{,local/}share/smartmontools/drivedb.h const char * db2 = get_drivedb_path_default(); if (!access(db2, 0)) { if (!read_drive_database(db2)) return false; } else #endif { // Append builtin table. knowndrives.append(builtin_knowndrives, sizeof(builtin_knowndrives)/sizeof(builtin_knowndrives[0])); } return true; } ������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_solaris.h���������������������������������������������������������0000644�0000000�0000000�00000004167�12062413436�017420� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_solaris.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef OS_SOLARIS_H_ #define OS_SOLARIS_H_ #define OS_SOLARIS_H_CVSID "$Id: os_solaris.h 3728 2012-12-13 17:57:50Z chrfranke $\n" // Additional material should start here. Note: to keep the '-V' CVS // reporting option working as intended, you should only #include // system include files <something.h>. Local #include files // <"something.h"> should be #included in os_solaris.c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> // function prototypes for functions defined in os_solaris_ata.s extern "C" { int smart_read_data(int fd, void *data); int smart_read_thresholds(int fd, void *data); int smart_read_log(int fd, int s, int count, void *data); int ata_identify(int fd, void *data); int ata_pidentify(int fd, void *data); int smart_enable(int fd); int smart_disable(int fd); int smart_status(int fd); int smart_auto_offline(int fd, int s); int smart_auto_save(int fd, int s); int smart_immediate_offline(int fd, int s); int smart_status_check(int fd); } // wrapper macros #define smart_enable_auto_save(fd) smart_auto_save(fd, 0xf1) #define smart_disable_auto_save(fd) smart_auto_save(fd, 0x00) #endif /* OS_SOLARIS_H_ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/dev_areca.h����������������������������������������������������������0000644�0000000�0000000�00000013511�12102567525�017151� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * dev_areca.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2012 Hank Wu <hank@areca.com.tw> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef DEV_ARECA_H #define DEV_ARECA_H #define DEV_ARECA_H_CVSID "$Id: dev_areca.h 3763 2013-01-31 22:25:25Z chrfranke $" ///////////////////////////////////////////////////////////////////////////// /// Areca RAID support /* GENERIC ARECA IO CONTROL CODE*/ enum _GENERIC_ARCMSR_CMDS { ARCMSR_READ_RQBUFFER = 0, ARCMSR_WRITE_WQBUFFER, ARCMSR_CLEAR_RQBUFFER, ARCMSR_CLEAR_WQBUFFER, ARCMSR_RETURN_CODE_3F, ARCMSR_CMD_TOTAL }; #define ARECA_SIG_STR "ARCMSR" #if defined(_WIN32) || defined(__CYGWIN__) #define ARCMSR_IOCTL_READ_RQBUFFER 0x90002004 #define ARCMSR_IOCTL_WRITE_WQBUFFER 0x90002008 #define ARCMSR_IOCTL_CLEAR_RQBUFFER 0x9000200C #define ARCMSR_IOCTL_CLEAR_WQBUFFER 0x90002010 #define ARCMSR_IOCTL_RETURN_CODE_3F 0x90002018 #elif defined(__linux__) /*DeviceType*/ #define ARECA_SATA_RAID 0x90000000 /*FunctionCode*/ #define FUNCTION_READ_RQBUFFER 0x0801 #define FUNCTION_WRITE_WQBUFFER 0x0802 #define FUNCTION_CLEAR_RQBUFFER 0x0803 #define FUNCTION_CLEAR_WQBUFFER 0x0804 #define FUNCTION_RETURN_CODE_3F 0x0806 /* ARECA IO CONTROL CODE*/ #define ARCMSR_IOCTL_READ_RQBUFFER (ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER) #define ARCMSR_IOCTL_WRITE_WQBUFFER (ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER) #define ARCMSR_IOCTL_CLEAR_RQBUFFER (ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER) #define ARCMSR_IOCTL_CLEAR_WQBUFFER (ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER) #define ARCMSR_IOCTL_RETURN_CODE_3F (ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F) #elif defined(__FreeBSD__) #include <sys/ioctl.h> // _IOWR /*FunctionCode*/ #define FUNCTION_READ_RQBUFFER 0x0801 #define FUNCTION_WRITE_WQBUFFER 0x0802 #define FUNCTION_CLEAR_RQBUFFER 0x0803 #define FUNCTION_CLEAR_WQBUFFER 0x0804 #define FUNCTION_RETURN_CODE_3F 0x0806 /* ARECA IO CONTROL CODE*/ #define ARCMSR_IOCTL_READ_RQBUFFER _IOWR('F', FUNCTION_READ_RQBUFFER, sSRB_BUFFER) #define ARCMSR_IOCTL_WRITE_WQBUFFER _IOWR('F', FUNCTION_WRITE_WQBUFFER, sSRB_BUFFER) #define ARCMSR_IOCTL_CLEAR_RQBUFFER _IOWR('F', FUNCTION_CLEAR_RQBUFFER, sSRB_BUFFER) #define ARCMSR_IOCTL_CLEAR_WQBUFFER _IOWR('F', FUNCTION_CLEAR_WQBUFFER, sSRB_BUFFER) #define ARCMSR_IOCTL_RETURN_CODE_3F _IOWR('F', FUNCTION_RETURN_CODE_3F, sSRB_BUFFER) #endif // The SRB_IO_CONTROL & SRB_BUFFER structures are used to communicate(to/from) to areca driver typedef struct _ARCMSR_IO_HDR { unsigned int HeaderLength; unsigned char Signature[8]; unsigned int Timeout; unsigned int ControlCode; unsigned int ReturnCode; unsigned int Length; } sARCMSR_IO_HDR; typedef struct _SRB_BUFFER { sARCMSR_IO_HDR srbioctl; unsigned char ioctldatabuffer[1032]; // the buffer to put the command data to/from firmware } sSRB_BUFFER; class generic_areca_device : virtual public smart_device { public: generic_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); ~generic_areca_device() throw(); ///////////////////////////////////////////////////////////////////// // OS-dependent functions virtual bool arcmsr_lock() = 0; virtual bool arcmsr_unlock() = 0; virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) = 0; ///////////////////////////////////////////////////////////////////// // OS-independent functions virtual int arcmsr_command_handler(unsigned long arcmsr_cmd, unsigned char *data, int data_len); virtual int arcmsr_ui_handler(unsigned char *areca_packet, int areca_packet_len, unsigned char *result); virtual bool arcmsr_probe(); virtual int arcmsr_get_dev_type(); virtual int arcmsr_get_controller_type(); virtual bool arcmsr_scsi_pass_through(scsi_cmnd_io * iop); virtual bool arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); protected: generic_areca_device() : smart_device(never_called) { } void set_disknum(int disknum) {m_disknum = disknum;} void set_encnum(int encnum) {m_encnum = encnum;} int get_disknum() {return m_disknum;} int get_encnum() {return m_encnum;} private: int m_disknum; ///< Disk number. int m_encnum; ///< Enclosure number. }; // SATA(ATA) device behind Areca RAID Controller class areca_ata_device : public ata_device, public generic_areca_device { public: areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); ~areca_ata_device() throw(); bool arcmsr_lock() { return true; } bool arcmsr_unlock() { return true; } int arcmsr_do_scsi_io(struct scsi_cmnd_io * /* iop */) { return -1; } protected: areca_ata_device(): smart_device(never_called) { } virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); }; // SAS(SCSI) device behind Areca RAID Controller class areca_scsi_device : public scsi_device, public generic_areca_device { public: areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); ~areca_scsi_device() throw(); bool arcmsr_lock() { return true; } bool arcmsr_unlock() { return true; } int arcmsr_do_scsi_io(struct scsi_cmnd_io * /* iop */) { return -1; } protected: areca_scsi_device(): smart_device(never_called) { } virtual bool scsi_pass_through(scsi_cmnd_io * iop); }; #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_qnxnto.h����������������������������������������������������������0000644�0000000�0000000�00000056343�12062413436�017276� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_generic.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) Joerg Hering <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef OS_QNXNTO_H_ #define OS_QNXNTO_H_ #define OS_QNXNTO_H_CVSID "$Id: os_qnxnto.h 3728 2012-12-13 17:57:50Z chrfranke $\n" // Additional material should start here. Note: to keep the '-V' CVS // reporting option working as intended, you should only #include // system include files <something.h>. Local #include files // <"something.h"> should be #included in os_generic.c #include <sys/cpt.h> #ifndef __TYPES_H_INCLUDED #include <sys/types.h> #endif #include <stdio.h> #include <fcntl.h> #include <gulliver.h> #include <sys/cpt.h> #include <sys/dcmd_cam.h> #include <sys/cam_device.h> #include "atacmds.h" //---------------------------------------------------------------------------------------------------------- typedef struct _ata_pass_thru ATA_PASS_THRU; typedef struct _eide_identify EIDE_IDENTIFY; typedef struct _ata_sense ATA_SENSE; typedef void CCB; struct _sim_hba; struct _resmgr_context; typedef struct _drive_attribute { int id; int threshold; char *name; }DRIVE_ATTRIBUTE; //---------------------------------------------------------------------------------------------------------- /* UNIVOS OSD defines and data structures. */ #define INQLEN 36 /* Inquiry string length to store. */ #define CAM_SUCCESS 0 /* For signaling general success */ #define CAM_FAILURE 1 /* For signaling general failure */ #define CAM_FALSE 0 /* General purpose flag value */ #define CAM_TRUE 1 /* General purpose flag value */ //---------------------------------------------------------------------------------------------------------- // Group 3 and 4, command codes 60H-9FH are reserved #define SC_ATA_PT16 0x85 // ATA Pass-through //---------------------------------------------------------------------------------------------------------- #define ATA_SMART_LBA_MID_SIG 0x4f #define ATA_SMART_LBA_HI_SIG 0xc2 #define ATA_SMART_SIG 0xc24f //---------------------------------------------------------------------------------------------------------- struct _ata_pass_thru { uchar_t opcode; #define ATA_PROTO_MSK 0x1e #define ATA_PROTO_RESPONSE (15 << 1) #define ATA_PROTO_FPDMA (12 << 1) #define ATA_PROTO_UDMA_DATA_OUT (11 << 1) #define ATA_PROTO_UDMA_DATA_IN (10 << 1) #define ATA_PROTO_DEVICE_RESET (9 << 1) #define ATA_PROTO_DEVICE_DIAGNOSTIC (8 << 1) #define ATA_PROTO_DMA_QUEUED (7 << 1) #define ATA_PROTO_DMA (6 << 1) #define ATA_PROTO_PIO_DATA_OUT (5 << 1) #define ATA_PROTO_PIO_DATA_IN (4 << 1) #define ATA_PROTO_DATA_NONE (3 << 1) #define ATA_PROTO_SRST (1 << 1) #define ATA_PROTO_HRST (0 << 1) #define ATA_PROTO_EXTEND 0x01 uchar_t protocol; // multiple count, protocol #define ATA_MCOUNT_MSK 0xe0 #define ATA_FLG_CK_COND 0x20 #define ATA_FLG_T_DIR 0x08 // data from device #define ATA_FLG_BYT_BLOK 0x04 #define ATA_FLG_TLEN_STPSIU 0x03 #define ATA_FLG_TLEN_SECTOR_COUNT 0x02 #define ATA_FLG_TLEN_FEATURE 0x01 uchar_t flags; uchar_t efeatures; uchar_t features; uchar_t esector_count; uchar_t sector_count; uchar_t elba_low; uchar_t lba_low; uchar_t elba_mid; uchar_t lba_mid; uchar_t elba_high; uchar_t lba_high; uchar_t device; uchar_t command; uchar_t control; } ata_pass_thru_; //---------------------------------------------------------------------------------------------------------- #define SENSE_DATA_FMT_DESCRIPTOR 0x02 // Fixed Format Sense Data Structure // Note: The field "error" has the following format: // bit 7 - Address valid bit // bits 6-4 - Error class // bits 3-0 - Error code // // Error classes 0-6 are vendor unique and also indicate that the // sense data is in _nonextended_ format. (i.e. not usually used) // struct _scsi_nonextended_sense { // uchar_t sd_err; // ulong_t sd_block_address; // }; // // An error class of 7 and an error code of 0 (70H) indicate SCSI-1 // extended sense data format (or SCSI-2 sense data format). // // An error class of 7 and an error code of 1 (71H) indicate SCSI-2 // deferred errors. // // Error codes 74H to 7EH are reserved and error code 7FH indicates // a vendor-specific sense data format. typedef struct _scsi_sense { uchar_t error; // Error Code uchar_t segment; // Segment number uchar_t sense; // Sense key/flags uchar_t info[4]; // Information (32bit big-endian value) uchar_t asl; // Additional Sense Length uchar_t csinfo[4]; // Command-Specific Information uchar_t asc; // Additional Sense Code uchar_t ascq; // Additional Sense Code Qualifier uchar_t fruc; // Field Replaceable Unit Code uchar_t sks; // Sense Key Specific ushort_t sks_data; // Sense Key Specific Data (16bit big-endian) ushort_t asb; // Additional Sense uchar_ts (Max 256-18) } SCSI_SENSE; // Descriptor Format Sense Data Structure // error code of 72 current, 73 deferred // extended sense data format (or SCSI-2 sense data format). typedef struct _scsi_sense_descriptor { uchar_t error; // Error Code uchar_t sense; // Sense key/flags uchar_t asc; // Additional Sense Code uchar_t ascq; // Additional Sense Code Qualifier uchar_t rsvd[3]; uchar_t asl; // Additional Sense Length } SCSI_SENSE_DESCRIPTOR; typedef struct _scsi_sense_desriptor_header { uchar_t descriptor_type; uchar_t descriptor_len; } SCSI_SENSE_DESCRIPTOR_HEADER; #define SENSE_DTYPE_INFORMATION 0x00 #define SENSE_DTYPE_CSI 0x01 // Command Specific Information #define SENSE_DTYPE_SKS 0x02 // Sense Key Specific #define SENSE_DTYPE_FRU 0x03 // Field Replaceable Unit #define SENSE_DTYPE_STREAM 0x04 #define SENSE_DTYPE_BLOCK 0x05 #define SENSE_DTYPE_OSD_OBJ_IDENT 0x06 // OSD Object Identification #define SENSE_DTYPE_OSD_INTEGRITY 0x07 // OSD Response Integrity Check Value #define SENSE_DTYPE_OSD_ATR_IDENT 0x08 // OSD Attribute Identification #define SENSE_DTYPE_ATA 0x09 typedef struct _ata_status_descriptor { uchar_t descriptor_type; #define ATA_SD_DLEN 0x0c uchar_t descriptor_len; /* 0xc */ #define ATA_SD_FLG_EXTEND 0x01 uchar_t flags; uchar_t error; uchar_t esector_count; /* (15:8) */ uchar_t sector_count; /* (7:0) */ uchar_t elba_low; /* (15:8) */ uchar_t lba_low; /* (7:0) */ uchar_t elba_mid; /* (15:8) */ uchar_t lba_mid; /* (7:0) */ uchar_t elba_high; /* (15:8) */ uchar_t lba_high; /* (7:0) */ uchar_t device; uchar_t status; } ATA_STATUS_DESCRIPTOR; //---------------------------------------------------------------------------------------------------------- // Sense Keys #define SK_MSK 0x0F // mask to sd_sense field for key #define SK_NO_SENSE 0 // No sense data (no error) #define ASCQ_FILEMARK_DETECTED 0x01 #define ASCQ_EOPM_DETECTED 0x02 // End of Partition/Medium Detected #define ASCQ_SETMARK_DETECTED 0x03 #define ASCQ_BOPM_DETECTED 0x04 // Beginning of Partition/Medium Detected #define SK_RECOVERED 1 // Recovered error #define ASC_ATA_PASS_THRU 0x00 #define ASCQ_ATA_PASS_THRU_INFO_AVAIL 0x1d #define SK_NOT_RDY 2 // Device not ready #define ASC_NO_SEEK_COMPLETE 0x02 #define ASC_NOT_READY 0x04 #define ASCQ_CAUSE_NOT_REPORTABLE 0x00 #define ASCQ_BECOMING_READY 0x01 #define ASCQ_INIT_COMMAND_REQUIRED 0x02 #define ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03 #define ASCQ_FORMAT_IN_PROGRESS 0x04 #define ASCQ_UNKNOWN_CHANGED 0xff // NTO extension for fdc's #define ASC_MEDIA_FORMAT 0x30 // bad format #define ASC_MEDIA_NOT_PRESENT 0x3a #define ASC_NOT_CONFIGURED 0x3e #define SK_MEDIUM 3 // Medium error #define ASC_UNRECOVERABLE_READ_ERROR 0x11 #define ASC_RECORD_NOT_FOUND 0x14 #define ASCQ_RECORD_NOT_FOUND 0x01 #define ASC_UNABLE_TO_RECOVER_TOC 0x57 #define ASC_INCOMPATIBLE_MEDIUM 0x64 #define SK_HARDWARE 4 // Hardware error #define ASC_INTERNAL_TARGET_FAILURE 0x44 #define ASC_MEDIA_LOAD_EJECT_FAILURE 0x53 #define ASCQ_UNRECOVERABLE_CIRC 0x06 #define SK_ILLEGAL 5 // Illegal Request (bad command) #define ASC_INVALID_COMMAND 0x20 #define ASC_INVALID_FIELD 0x24 #define ASC_INVALID_FIELD_PARAMETER 0x26 #define ASC_COMMAND_SEQUENCE_ERROR 0x2c #define ASCQ_READ_SCRAMBLED 0x03 #define ASC_ILLEGAL_MODE 0x64 #define ASC_COPY_PROTECTION 0x6f #define SK_UNIT_ATN 6 // Unit Attention #define ASC_MEDIUM_CHANGED 0x28 #define ASC_BUS_RESET 0x29 #define ASC_INSUFFICIENT_TIME_FOR_OPERATION 0x2e #define ASC_OPERATOR_REQUEST 0x5a #define ASCQ_OPERATOR_MEDIUM_REMOVAL 0x01 #define SK_DATA_PROT 7 // Data Protect #define ASC_WRITE_PROTECTED 0x27 #define SK_BLNK_CHK 8 // Blank Check #define SK_VENDOR 9 // Vendor Specific #define SK_CPY_ABORT 10 // Copy Aborted #define SK_CMD_ABORT 11 // Aborted Command #define SK_EQUAL 12 // Equal #define SK_VOL_OFL 13 // Volume Overflow #define SK_MISCMP 14 // Miscompare #define SK_RESERVED 15 // Reserved //---------------------------------------------------------------------------------------------------------- // Command Descriptor Block structure definitions // CDB Flags #define CF_LINK 0x01 // Linked-command indication #define CF_FLAG 0x02 // Linked-command with flag bit #define CF_VENDOR0 0x40 // Vendor unique bits #define CF_VENDOR1 0x80 #define CF_FUA 0x08 #define CF_DPO 0x10 typedef union _cdb { // generic 6 byte command descriptor block struct { uchar_t opcode; uchar_t lun_opt; uchar_t lba_byte1; uchar_t lba_byte0; // LSB uchar_t transfer_len; uchar_t control; } gen6; // generic 10 byte command descriptor block struct { uchar_t opcode; uchar_t lun_opt; uchar_t lba_byte3; uchar_t lba_byte4; uchar_t lba_byte1; uchar_t lba_byte0; uchar_t rsvd; uchar_t transfer_len[2]; uchar_t control; } gen10; // generic 12 byte command descriptor block struct { uchar_t opcode; uchar_t lun_opt; uchar_t lba_byte3; uchar_t lba_byte4; uchar_t lba_byte1; uchar_t lba_byte0; uchar_t transfer_len[4]; uchar_t rsvd10; uchar_t control; } gen12; struct _format_unit { uchar_t op_code; #define FU_RSVD0 0xc0 // reserved bits #define FU_FMTDAT 0x10 #define FU_CMPLIST 0x08 uchar_t defect_list_fmt; uchar_t track_num; ushort_t interleave; uchar_t rsvd1[7]; } format_unit; struct _format_unit_old { uchar_t op_code; uchar_t rsvd0; uchar_t medium_type_code; uchar_t rsvd1; uchar_t interleave; uchar_t rsvd2; #define FMT_RSVD3 0x80 #define FMT_SECT_SIZE_CD 0x70 #define FMT_IMMED 0x08 #define FMT_HEAD 0x04 #define FMT_ST 0x02 #define FMT_CERT 0x01 uchar_t cert; uchar_t track_addr; uchar_t rsvd4[4]; } format_unit_old; #define RW_OPT_RELADR 0x01 #define RW_OPT_CORRCT 0x02 // Disable Corrections #define RW_OPT_FUA 0x08 // Force Unit Access #define RW_OPT_DPO 0x10 // Disable Page Out struct { uchar_t opcode; uchar_t lun_lba; uchar_t lba[2]; uchar_t transfer_len; uchar_t control; } read_write6; struct { uchar_t opcode; uchar_t lun_opt; uchar_t lba[4]; uchar_t rsvd2; uchar_t transfer_len[2]; uchar_t control; } read_write10; struct { uchar_t opcode; uchar_t lun_opt; uchar_t lba[4]; uchar_t transfer_len[4]; uchar_t rsvd2; uchar_t control; } read_write12; #define MSEL_OPT_PF 0x10 // Page Format #define MSEL_OPT_SP 0x01 // Save Page struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; uchar_t param_length; uchar_t control; } mode_select; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t param_length[2]; uchar_t control; } mode_select10; struct { uchar_t opcode; #define LS_OPT_SP 0x01 // Save Parameters #define LS_OPT_PCR 0x02 // Parameter Code Reset uchar_t lun_opt; #define LS_PC_CUR_THRESHOLD 0x00 #define LS_PC_CUR_CUMULATIVE 0x01 #define LS_PC_DFLT_THRESHOLD 0x02 #define LS_PC_DFLT_CUMULATIVE 0x03 uchar_t pc; // Page Control uchar_t rsvd3; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t param_length[2]; uchar_t control; } log_select; struct { uchar_t opcode; #define MSNS_OPT_DBD 0x08 // Disable Block Descriptors uchar_t lun_opt; #define PC_CURRENT 0x00 #define PC_CHANGEABLE 0x40 #define PC_DEFAULT 0x80 #define PC_SAVED 0xC0 #define PC_MSK 0xC0 uchar_t pc_page; uchar_t subpage; uchar_t allocation_length; uchar_t control; } mode_sense; struct _mode_sense10 { uchar_t opcode; uchar_t lun_opt; uchar_t pc_page; uchar_t subpage; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t allocation_length[2]; uchar_t control; } mode_sense10; struct { uchar_t opcode; uchar_t lun_opt; uchar_t pc_page; uchar_t rsvd3; uchar_t rsvd4; uchar_t parameter_pointer[2]; uchar_t allocation_length[2]; uchar_t control; } log_sense; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; uchar_t prevent; uchar_t control; } removal; struct { uchar_t opcode; #define LD_OPT_IMMED 0x01 uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; #define LD_CMD_START 0x01 #define LD_CMD_LOEJ 0x02 #define LD_CMD_STOP 0x00 #define LD_CMD_EJECT 0x02 #define LD_CMD_LOAD 0x03 // Sequential-Access #define LD_CMD_SA_HOLD 0x08 #define LD_CMD_SA_EOT 0x04 #define LD_CMD_SA_RT 0x02 // re-tension #define LD_CMD_SA_LOEJ 0x01 // Block #define LD_CMD_PC_MSK 0xf0 #define LD_CMD_PC_NC 0 #define LD_CMD_PC_ACTIVE 1 #define LD_CMD_PC_IDLE 2 #define LD_CMD_PC_STANDBY 3 #define LD_CMD_PC_SLEEP 5 uchar_t cmd; uchar_t control; } load; struct { uchar_t opcode; uchar_t lun_opt; #define SC_OPT_RELADR 0x01 #define SC_OPT_IMMED 0x02 uchar_t lba[4]; uchar_t num_blocks[2]; uchar_t control; } synchronize_cache; // cdrom commands struct { uchar_t opcode; uchar_t rsvd1; uchar_t rsvd2; uchar_t rsvd3; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t allocation_length[2]; uchar_t control; } read_disc_information; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t rsvd7; uchar_t resume; uchar_t control; } pause_resume; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t start_minute; uchar_t start_second; uchar_t start_frame; uchar_t end_minute; uchar_t end_second; uchar_t end_frame; uchar_t control; } play_audio_msf; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; uchar_t start_track; uchar_t start_index; uchar_t rsvd6; uchar_t end_track; uchar_t end_index; uchar_t control; } play_audio_ti; struct { uchar_t opcode; #define CD_SCAN_DIR_FORWARD 0x00 #define CD_SCAN_DIR_REVERSE 0x10 uchar_t opt; uchar_t start_address[4]; #define CD_SCAN_TYPE_LBA 0x00 #define CD_SCAN_TYPE_MSF 0x40 #define CD_SCAN_TYPE_TRK 0x80 #define CD_SCAN_TYPE_MSK 0xc0 uchar_t rsvd6; uchar_t rsvd7; uchar_t rsvd8; uchar_t type; uchar_t rsvd10; uchar_t rsvd11; } cd_scan; struct { uchar_t opcode; #define RTOC_OPT_MSF 0x02 uchar_t lun_opt; #define RTOC_FMT_TOC 0x0 #define RTOC_FMT_SESSION 0x1 #define RTOC_FMT_QSUBCODE 0x2 #define RTOC_FMT_QSUBCHNL 0x3 #define RTOC_FMT_ATIP 0x4 #define RTOC_FMT_CDTEXT 0x5 uchar_t format; uchar_t rsvd3; uchar_t rsvd4; uchar_t rsvd5; uchar_t start_track; uchar_t allocation_length[2]; #define RTOC_CNTL_FMT_SESSION 0x40 uchar_t control_format; } read_toc; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2[6]; uchar_t allocation_length[2]; uchar_t rsvd3[2]; } mechanism_status; struct { uchar_t opcode; #define EXCHANGE_OPT_IMMED 0x01 uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; #define EXCHANGE_CMD_START 0x01 #define EXCHANGE_CMD_LOEJ 0x02 uchar_t cmd; uchar_t rsvd5; uchar_t rsvd6; uchar_t rsvd7; uchar_t slot; uchar_t rsvd9; uchar_t rsvd10; uchar_t rsvd11; } exchange; struct { uchar_t opcode; uchar_t rt; uchar_t feature_number[2]; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t allocation_length[2]; uchar_t control; } get_configuration; struct { uchar_t opcode; #define GE_OPT_POLLED 0x01 uchar_t opt; uchar_t rsvd2; uchar_t rsvd3; #define NCR_OPERATIONAL_CHANGE 0x02 #define NCR_POWER_MANAGEMENT 0x04 #define NCR_EXTERNAL_REQUEST 0x08 #define NCR_MEDIA 0x10 #define NCR_MULTI_INITIATOR 0x20 #define NCR_DEVICE_BUSY 0x40 uchar_t ncr; // notification class request uchar_t rsvd5; uchar_t rsvd6; uchar_t allocation_length[2]; uchar_t control; } get_event; struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2; uchar_t rsvd3; uchar_t rsvd4; uchar_t rsvd5; uchar_t rsvd6; uchar_t allocation_length[2]; uchar_t control; } read_formated_capacities; struct { uchar_t opcode; uchar_t lun_opt; uchar_t read_speed[2]; uchar_t write_speed[2]; uchar_t rsvd2[6]; } cd_speed; struct { uchar_t opcode; #define RSCHNL_OPT_MSF 0x02 uchar_t lun_opt; #define RSCHNL_DATA_SUBQ 0x40 uchar_t data; uchar_t data_format; uchar_t rsvd4; uchar_t rsvd5; uchar_t track; uchar_t allocation_length[2]; uchar_t control; } read_subchannel; #define CD_FRAME_SYNC_SIZE 12 #define CD_FRAME_HDR_SIZE 4 #define CD_FRAME_SUB_HDR_SIZE 8 #define CD_FRAME_EDC_SIZE 4 #define CD_FRAME_ECC_SIZE 276 #define CD_FRAME_AUX_SIZE 8 #define CD_FRAME_ZERO_SIZE 8 #define CD_FRAME_SPARE_SIZE 4 #define CD_FRAME_C2_ERR_SIZE 294 #define CD_FRAME_BLOCK_ERR_SIZE 2 struct { uchar_t opcode; uchar_t lun_stype; // expected sector type #define RDCD_EST_ANY_SECTOR (0 << 2) #define RDCD_EST_CDDA_SECTOR (1 << 2) #define RDCD_EST_YELLOW_MODE1_SECTOR (2 << 2) #define RDCD_EST_YELLOW_MODE2_SECTOR (3 << 2) #define RDCD_EST_XA_SECTOR (4 << 2) #define RDCD_EST_XA_FORM2_SECTOR (5 << 2) #define RDCD_EST_MSK (7 << 2) uchar_t lba[4]; uchar_t transfer_len[3]; uchar_t flags; #define RDCD_FLG_SYNC 0x80 #define RDCD_FLG_UDATA 0x10 #define RDCD_FLG_ECC 0x08 #define RDCD_FLG_CD_ERR 0x02 #define RDCD_FLG_CD_BLOCK_ERR 0x04 #define RDCD_FLG_HC_NONE ( 0x00 << 5 ) #define RDCD_FLG_HC_HDR ( 0x01 << 5 ) #define RDCD_FLG_HC_SUBHEADER ( 0x02 << 5 ) #define RDCD_FLG_HC_ALL_HEADERS ( 0x03 << 5 ) uchar_t subch_selection; uchar_t rsvd3; } read_cd; struct { uchar_t opcode; uchar_t lun_stype; uchar_t rsvd2; uchar_t start_minute; uchar_t start_second; uchar_t start_frame; uchar_t end_minute; uchar_t end_second; uchar_t end_frame; uchar_t flags; uchar_t subch_selection; uchar_t rsvd11; } read_cd_msf; struct _ata_pass_thru { uchar_t opcode; #define ATA_PROTO_MSK 0x1e #define ATA_PROTO_RESPONSE (15 << 1) #define ATA_PROTO_FPDMA (12 << 1) #define ATA_PROTO_UDMA_DATA_OUT (11 << 1) #define ATA_PROTO_UDMA_DATA_IN (10 << 1) #define ATA_PROTO_DEVICE_RESET (9 << 1) #define ATA_PROTO_DEVICE_DIAGNOSTIC (8 << 1) #define ATA_PROTO_DMA_QUEUED (7 << 1) #define ATA_PROTO_DMA (6 << 1) #define ATA_PROTO_PIO_DATA_OUT (5 << 1) #define ATA_PROTO_PIO_DATA_IN (4 << 1) #define ATA_PROTO_DATA_NONE (3 << 1) #define ATA_PROTO_SRST (1 << 1) #define ATA_PROTO_HRST (0 << 1) #define ATA_PROTO_EXTEND 0x01 uchar_t protocol; // multiple count, protocol #define ATA_MCOUNT_MSK 0xe0 #define ATA_FLG_CK_COND 0x20 #define ATA_FLG_T_DIR 0x08 // data from device #define ATA_FLG_BYT_BLOK 0x04 #define ATA_FLG_TLEN_STPSIU 0x03 #define ATA_FLG_TLEN_SECTOR_COUNT 0x02 #define ATA_FLG_TLEN_FEATURE 0x01 uchar_t flags; uchar_t efeatures; uchar_t features; uchar_t esector_count; uchar_t sector_count; uchar_t elba_low; uchar_t lba_low; uchar_t elba_mid; uchar_t lba_mid; uchar_t elba_high; uchar_t lba_high; uchar_t device; uchar_t command; uchar_t control; } ata_pass_thru; // sequential access commands struct { uchar_t opcode; #define ERASE_OPT_LONG 0x01 uchar_t opt; uchar_t rsvd[3]; uchar_t control; } erase; struct { uchar_t opcode; #define LOCATE_OPT_CP 0x2 #define LOCATE_OPT_BT 0x4 uchar_t opt; uchar_t rsvd2; uchar_t ba[4]; // block address uchar_t rsvd7; uchar_t partition; uchar_t control; } locate; struct { uchar_t opcode; uchar_t opt; uchar_t rsvd2[3]; uchar_t control; } read_block_limits; #define RP_OPT_BT 0x01 // block address type #define RP_OPT_LNG 0x02 // long format #define RP_OPT_TCLP 0x04 // total current logical position struct { uchar_t opcode; uchar_t lun_opt; uchar_t rsvd2[7]; uchar_t control; } read_position; #define SRW_OPT_FIXED 0x01 #define SRW_OPT_SILI 0x02 struct { uchar_t opcode; uchar_t opt; uchar_t transfer_len[3]; uchar_t control; } sa_read_write; struct { uchar_t opcode; uchar_t opt; uchar_t rsvd[3]; uchar_t control; } rewind; struct { uchar_t opcode; #define SPACE_CODE_BLOCKS 0x00 #define SPACE_CODE_FMRKS 0x01 #define SPACE_CODE_SEQ_FMRKS 0x02 #define SPACE_CODE_EOD 0x03 #define SPACE_CODE_SMRKS 0x04 #define SPACE_CODE_SEQ_SMRKS 0x05 uchar_t lun_code; uchar_t count[3]; uchar_t control; } space; struct { uchar_t opcode; #define WF_OPT_IMMED 0x01 #define WF_OPT_WSMK 0x02 uchar_t opt; uchar_t transfer_length[3]; uchar_t control; } write_filemarks; struct { uchar_t opcode; #define RD_OPT_MEDIA 0x01 uchar_t opt; uchar_t rsvd[5]; uchar_t allocation_length[2]; uchar_t control; } report_density; struct { uchar_t opcode; #define FM_OPT_IMMED 0x01 #define FM_OPT_VERIFY 0x02 uchar_t opt; #define FM_FMT_DFLT 0x00 #define FM_FMT_PARTITION 0x01 #define FM_FMT_FORMAT_PARTITION 0x02 uchar_t format; uchar_t transfer_length[2]; uchar_t control; } format_media; } CDB; //---------------------------------------------------------------------------------------------------------- struct _ata_sense { SCSI_SENSE_DESCRIPTOR sense; ATA_STATUS_DESCRIPTOR desc; }; //---------------------------------------------------------------------------------------------------------- #endif /* OS_QNXNTO_H_ */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/dev_tunnelled.h������������������������������������������������������0000644�0000000�0000000�00000004331�11227432427�020067� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * dev_tunnelled.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef DEV_TUNNELLED_H #define DEV_TUNNELLED_H #define DEV_TUNNELLED_H_CVSID "$Id: dev_tunnelled.h,v 1.1 2008/07/25 21:16:00 chrfranke Exp $\n" #include "dev_interface.h" ///////////////////////////////////////////////////////////////////////////// // tunnelled_device_base /// Common functionality for all tunnelled_device classes. class tunnelled_device_base : virtual public /*implements*/ smart_device { protected: explicit tunnelled_device_base(smart_device * tunnel_dev); public: virtual ~tunnelled_device_base() throw(); virtual bool is_open() const; virtual bool open(); virtual bool close(); virtual bool owns(const smart_device * dev) const; virtual void release(const smart_device * dev); private: smart_device * m_tunnel_base_dev; }; ///////////////////////////////////////////////////////////////////////////// // tunnelled_device /// Implement a device by tunneling through another device template <class BaseDev, class TunnelDev> class tunnelled_device : public BaseDev, public tunnelled_device_base { public: typedef TunnelDev tunnel_device_type; protected: explicit tunnelled_device(tunnel_device_type * tunnel_dev) : smart_device(smart_device::never_called), tunnelled_device_base(tunnel_dev), m_tunnel_dev(tunnel_dev) { } public: virtual void release(const smart_device * dev) { if (m_tunnel_dev == dev) m_tunnel_dev = 0; tunnelled_device_base::release(dev); } tunnel_device_type * get_tunnel_dev() { return m_tunnel_dev; } const tunnel_device_type * get_tunnel_dev() const { return m_tunnel_dev; } private: tunnel_device_type * m_tunnel_dev; }; #endif // DEV_TUNNELLED_H �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/csmisas.h������������������������������������������������������������0000644�0000000�0000000�00000155564�12123643645�016722� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************** Module Name: CSMISAS.H Abstract: This file contains constants and data structure definitions used by drivers that support the Common Storage Management Interface specification for SAS or SATA in either the Windows or Linux. This should be considered as a reference implementation only. Changes may be necessary to accommodate a specific build environment or target OS. Revision History: 001 SEF 8/12/03 Initial release. 002 SEF 8/20/03 Cleanup to match documentation. 003 SEF 9/12/03 Additional cleanup, created combined header 004 SEF 9/23/03 Changed base types to match linux defaults Added RAID signature Added bControllerFlags to CSMI_SAS_CNTLR_CONFIG Changed CSMI_SAS_BEGIN_PACK to 8 for common structures Fixed other typos identified in first compilation test 005 SEF 10/03/03 Additions to match first version of CSMI document 006 SEF 10/14/03 Fixed typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER Added defines for bConnectionRate 007 SEF 10/15/03 Added Firmware Download Control Code and support Added CSMI revision support 008 SEF 10/30/03 No functional change, just updated version to track spec changes 009 SEF 12/09/03 No functional change, just updated version to track spec changes 010 SEF 3/11/04 Fixed typedef struct CSMI_SAS_RAID_DRIVES to include the bFirmware member that is defined in the spec, but was missing in this file, added CC_CSMI_SAS_TASK_MANAGEMENT 011 SEF 4/02/04 No functional change, added comment line before CC_CSMI_SAS_TASK_MANAGEMENT 012 SEF 4/16/04 Added IOControllerNumber to linux header, Modified linux control codes to have upper word of 0xCC77.... to indicate CSMI version 77 Added bSignalClass to CC_CSMI_SET_PHY_INFO Added CC_CSMI_SAS_PHY_CONTROL support 013 SEF 5/14/04 Added CC_CSMI_SAS_GET_CONNECTOR_INFO support 014 SEF 5/24/04 No functional change, just updated version to track spec changes 015 SEF 6/16/04 changed bPinout to uPinout to reflect proper size, changed width of bLocation defines to reflect size 016 SEF 6/17/04 changed bLengthOfControls in CSMI_SAS_PHY_CONTROL to be proper size 017 SEF 9/17/04 added CSMI_SAS_SATA_PORT_SELECTOR, CSMI_SAS_LINK_VIRTUAL, CSMI_SAS_CON_NOT_PRESENT, and CSMI_SAS_CON_NOT_CONNECTED 018 SEF 9/20/04 added CSMI_SAS_PHY_USER_PATTERN, changed definition of CSMI_SAS_PHY_FIXED_PATTERN to not conflict with activate definition 019 SEF 12/06/04 added CSMI_SAS_GET_LOCATION added bSSPStatus to CSMI_SAS_SSP_PASSTHRU_STATUS structure 020 SEF 5/25/05 added CSMI_SAS_PHY_VIRTUAL_SMP, and changes to CSMI_SAS_GET_LOCATION 021 SEF 11/03/05 added new RAID creation functionality 022 SEF 2/01/06 corrected typo bNegotitiatedLInkRate Added two more RAID_TYPES, 7 and 8 023 SEF 4/04/06 added CSMI_RAID_TYPE_1E changed structures that contained surface scan to priority approach rather than time, causes 0.89 to incompatible with 0.87, so a version check is necessary when interpreting the raid structures Added netware section 024 DRG 5/22/06 Added uFailureCode to CSMI_SAS_RAID_CONFIG and CSMI_SAS_RAID_FEATURES Changed __u64 fields to high and low __u32 fields in order to avoid backward compatibility issues with packing and alignment. Fixed alignment problem in CSMI_SAS_RAID_DRIVES. Added CSMI_SAS_CNTLR_SMART_ARRAY to uControllerFlags Reassigned the value of CSMI_SAS_CNTLR_RAID_CFG_SUPPORT to avoid a conflict. **************************************************************************/ #ifndef _CSMI_SAS_H_ #define _CSMI_SAS_H_ // CSMI Specification Revision, the intent is that all versions of the // specification will be backward compatible after the 1.00 release. // Major revision number, corresponds to xxxx. of CSMI specification // Minor revision number, corresponds to .xxxx of CSMI specification #define CSMI_MAJOR_REVISION 0 #define CSMI_MINOR_REVISION 90 /*************************************************************************/ /* PATCHES FOR TYPOS */ /*************************************************************************/ #define bNegotitiatedLInkRate bNegotiatedLinkRate /*************************************************************************/ /* TARGET OS LINUX SPECIFIC CODE */ /*************************************************************************/ // EDM #ifdef _linux #ifdef __KERNEL__ // Linux base types #include <linux/types.h> #define __i8 char // pack definition // EDM #define CSMI_SAS_BEGIN_PACK(x) pack(x) // EDM #define CSMI_SAS_END_PACK pack() // IOCTL Control Codes // (IoctlHeader.ControlCode) // Control Codes prior to 0.77 // Control Codes requiring CSMI_ALL_SIGNATURE // #define CC_CSMI_SAS_GET_DRIVER_INFO 0x12345678 // #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x23456781 // #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x34567812 // #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x92345678 // Control Codes requiring CSMI_RAID_SIGNATURE // #define CC_CSMI_SAS_GET_RAID_INFO 0x45678123 // #define CC_CSMI_SAS_GET_RAID_CONFIG 0x56781234 // Control Codes requiring CSMI_SAS_SIGNATURE // #define CC_CSMI_SAS_GET_PHY_INFO 0x67812345 // #define CC_CSMI_SAS_SET_PHY_INFO 0x78123456 // #define CC_CSMI_SAS_GET_LINK_ERRORS 0x81234567 // #define CC_CSMI_SAS_SMP_PASSTHRU 0xA1234567 // #define CC_CSMI_SAS_SSP_PASSTHRU 0xB1234567 // #define CC_CSMI_SAS_STP_PASSTHRU 0xC1234567 // #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xD1234567 // #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xE1234567 // #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xF1234567 // #define CC_CSMI_SAS_TASK_MANAGEMENT 0xA2345678 // Control Codes for 0.77 and later // Control Codes requiring CSMI_ALL_SIGNATURE #define CC_CSMI_SAS_GET_DRIVER_INFO 0xCC770001 #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0xCC770002 #define CC_CSMI_SAS_GET_CNTLR_STATUS 0xCC770003 #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0xCC770004 // Control Codes requiring CSMI_RAID_SIGNATURE #define CC_CSMI_SAS_GET_RAID_INFO 0xCC77000A #define CC_CSMI_SAS_GET_RAID_CONFIG 0xCC77000B #define CC_CSMI_SAS_GET_RAID_FEATURES 0xCC77000C #define CC_CSMI_SAS_SET_RAID_CONTROL 0xCC77000D #define CC_CSMI_SAS_GET_RAID_ELEMENT 0xCC77000E #define CC_CSMI_SAS_SET_RAID_OPERATION 0xCC77000F // Control Codes requiring CSMI_SAS_SIGNATURE #define CC_CSMI_SAS_GET_PHY_INFO 0xCC770014 #define CC_CSMI_SAS_SET_PHY_INFO 0xCC770015 #define CC_CSMI_SAS_GET_LINK_ERRORS 0xCC770016 #define CC_CSMI_SAS_SMP_PASSTHRU 0xCC770017 #define CC_CSMI_SAS_SSP_PASSTHRU 0xCC770018 #define CC_CSMI_SAS_STP_PASSTHRU 0xCC770019 #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0xCC770020 #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0xCC770021 #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0xCC770022 #define CC_CSMI_SAS_TASK_MANAGEMENT 0xCC770023 #define CC_CSMI_SAS_GET_CONNECTOR_INFO 0xCC770024 #define CC_CSMI_SAS_GET_LOCATION 0xCC770025 // Control Codes requiring CSMI_PHY_SIGNATURE #define CC_CSMI_SAS_PHY_CONTROL 0xCC77003C // EDM #pragma CSMI_SAS_BEGIN_PACK(8) #pragma pack(8) // IOCTL_HEADER typedef struct _IOCTL_HEADER { __u32 IOControllerNumber; __u32 Length; __u32 ReturnCode; __u32 Timeout; __u16 Direction; } IOCTL_HEADER, *PIOCTL_HEADER; // EDM #pragma CSMI_SAS_END_PACK #pragma pack() #endif /*************************************************************************/ /* TARGET OS WINDOWS SPECIFIC CODE */ /*************************************************************************/ #ifdef _WIN32 // windows IOCTL definitions #if 0 // <ntddscsi.h> and CSMI_*_PACK are no longer needed #ifndef _NTDDSCSIH_ #include <ntddscsi.h> #endif // pack definition #if defined _MSC_VER #define CSMI_SAS_BEGIN_PACK(x) pack(push,x) #define CSMI_SAS_END_PACK pack(pop) #elif defined __BORLANDC__ #define CSMI_SAS_BEGIN_PACK(x) option -a##x #define CSMI_SAS_END_PACK option -a. #else #error "CSMISAS.H - Must externally define a pack compiler designator." #endif #endif // #if 0 // base types #define __u8 unsigned char #define __u16 unsigned short #ifndef __LP64__ // ILP32 (32-bit), LLP64 (64-bit MSVC, MinGW) #define __u32 unsigned long #else // LP64 (64-bit Cygwin) #define __u32 unsigned int #endif #define __u64 unsigned __int64 #define __i8 char // IOCTL Control Codes // (IoctlHeader.ControlCode) // Control Codes requiring CSMI_ALL_SIGNATURE #define CC_CSMI_SAS_GET_DRIVER_INFO 1 #define CC_CSMI_SAS_GET_CNTLR_CONFIG 2 #define CC_CSMI_SAS_GET_CNTLR_STATUS 3 #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 4 // Control Codes requiring CSMI_RAID_SIGNATURE #define CC_CSMI_SAS_GET_RAID_INFO 10 #define CC_CSMI_SAS_GET_RAID_CONFIG 11 #define CC_CSMI_SAS_GET_RAID_FEATURES 12 #define CC_CSMI_SAS_SET_RAID_CONTROL 13 #define CC_CSMI_SAS_GET_RAID_ELEMENT 14 #define CC_CSMI_SAS_SET_RAID_OPERATION 15 // Control Codes requiring CSMI_SAS_SIGNATURE #define CC_CSMI_SAS_GET_PHY_INFO 20 #define CC_CSMI_SAS_SET_PHY_INFO 21 #define CC_CSMI_SAS_GET_LINK_ERRORS 22 #define CC_CSMI_SAS_SMP_PASSTHRU 23 #define CC_CSMI_SAS_SSP_PASSTHRU 24 #define CC_CSMI_SAS_STP_PASSTHRU 25 #define CC_CSMI_SAS_GET_SATA_SIGNATURE 26 #define CC_CSMI_SAS_GET_SCSI_ADDRESS 27 #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 28 #define CC_CSMI_SAS_TASK_MANAGEMENT 29 #define CC_CSMI_SAS_GET_CONNECTOR_INFO 30 #define CC_CSMI_SAS_GET_LOCATION 31 // Control Codes requiring CSMI_PHY_SIGNATURE #define CC_CSMI_SAS_PHY_CONTROL 60 #define IOCTL_HEADER SRB_IO_CONTROL #define PIOCTL_HEADER PSRB_IO_CONTROL #endif /*************************************************************************/ /* TARGET OS NETWARE SPECIFIC CODE */ /*************************************************************************/ #ifdef _NETWARE // NetWare IOCTL definitions #define CSMI_SAS_BEGIN_PACK(x) pack(x) #define CSMI_SAS_END_PACK pack() #ifndef LONG typedef unsigned long LONG; #endif #ifndef WORD typedef unsigned short WORD; #endif #ifndef BYTE typedef unsigned char BYTE; #endif /* Need to have these definitions for Netware */ #define __u8 unsigned char #define __u16 unsigned short #define __u32 unsigned long #define __u64 unsigned __int64 #define __i8 char // EDM #pragma CSMI_SAS_BEGIN_PACK(8) #pragma pack(8) // IOCTL_HEADER typedef struct _IOCTL_HEADER { __u32 Length; __u32 ReturnCode; } IOCTL_HEADER, *PIOCTL_HEADER; // EDM #pragma CSMI_SAS_END_PACK #pragma pack() // IOCTL Control Codes // (IoctlHeader.ControlCode) // Control Codes requiring CSMI_ALL_SIGNATURE #define CC_CSMI_SAS_GET_DRIVER_INFO 0x01FF0001 #define CC_CSMI_SAS_GET_CNTLR_CONFIG 0x01FF0002 #define CC_CSMI_SAS_GET_CNTLR_STATUS 0x01FF0003 #define CC_CSMI_SAS_FIRMWARE_DOWNLOAD 0x01FF0004 // Control Codes requiring CSMI_RAID_SIGNATURE #define CC_CSMI_SAS_GET_RAID_INFO 0x01FF000A #define CC_CSMI_SAS_GET_RAID_CONFIG 0x01FF000B #define CC_CSMI_SAS_GET_RAID_FEATURES 0x01FF000C #define CC_CSMI_SAS_SET_RAID_CONTROL 0x01FF000D #define CC_CSMI_SAS_GET_RAID_ELEMENT 0x01FF000E #define CC_CSMI_SAS_SET_RAID_OPERATION 0x01FF000F // Control Codes requiring CSMI_SAS_SIGNATURE #define CC_CSMI_SAS_GET_PHY_INFO 0x01FF0014 #define CC_CSMI_SAS_SET_PHY_INFO 0x01FF0015 #define CC_CSMI_SAS_GET_LINK_ERRORS 0x01FF0016 #define CC_CSMI_SAS_SMP_PASSTHRU 0x01FF0017 #define CC_CSMI_SAS_SSP_PASSTHRU 0x01FF0018 #define CC_CSMI_SAS_STP_PASSTHRU 0x01FF0019 #define CC_CSMI_SAS_GET_SATA_SIGNATURE 0x01FF001A #define CC_CSMI_SAS_GET_SCSI_ADDRESS 0x01FF001B #define CC_CSMI_SAS_GET_DEVICE_ADDRESS 0x01FF001C #define CC_CSMI_SAS_TASK_MANAGEMENT 0x01FF001D #define CC_CSMI_SAS_GET_CONNECTOR_INFO 0x01FF001E #define CC_CSMI_SAS_GET_LOCATION 0x01FF001F // Control Codes requiring CSMI_PHY_SIGNATURE #define CC_CSMI_SAS_PHY_CONTROL 60 #endif /*************************************************************************/ /* TARGET OS NOT DEFINED ERROR */ /*************************************************************************/ // EDM //#if (!_WIN32 && !_linux && !_NETWARE) // #error "Unknown target OS." //#endif /*************************************************************************/ /* OS INDEPENDENT CODE */ /*************************************************************************/ /* * * * * * * * * * Class Independent IOCTL Constants * * * * * * * * * */ // Return codes for all IOCTL's regardless of class // (IoctlHeader.ReturnCode) #define CSMI_SAS_STATUS_SUCCESS 0 #define CSMI_SAS_STATUS_FAILED 1 #define CSMI_SAS_STATUS_BAD_CNTL_CODE 2 #define CSMI_SAS_STATUS_INVALID_PARAMETER 3 #define CSMI_SAS_STATUS_WRITE_ATTEMPTED 4 // Signature value // (IoctlHeader.Signature) #define CSMI_ALL_SIGNATURE "CSMIALL" // Timeout value default of 60 seconds // (IoctlHeader.Timeout) #define CSMI_ALL_TIMEOUT 60 // Direction values for data flow on this IOCTL // (IoctlHeader.Direction, Linux only) #define CSMI_SAS_DATA_READ 0 #define CSMI_SAS_DATA_WRITE 1 // I/O Bus Types // ISA and EISA bus types are not supported // (bIoBusType) #define CSMI_SAS_BUS_TYPE_PCI 3 #define CSMI_SAS_BUS_TYPE_PCMCIA 4 // Controller Status // (uStatus) #define CSMI_SAS_CNTLR_STATUS_GOOD 1 #define CSMI_SAS_CNTLR_STATUS_FAILED 2 #define CSMI_SAS_CNTLR_STATUS_OFFLINE 3 #define CSMI_SAS_CNTLR_STATUS_POWEROFF 4 // Offline Status Reason // (uOfflineReason) #define CSMI_SAS_OFFLINE_REASON_NO_REASON 0 #define CSMI_SAS_OFFLINE_REASON_INITIALIZING 1 #define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_DEGRADED 2 #define CSMI_SAS_OFFLINE_REASON_BACKSIDE_BUS_FAILURE 3 // Controller Class // (bControllerClass) #define CSMI_SAS_CNTLR_CLASS_HBA 5 // Controller Flag bits // (uControllerFlags) #define CSMI_SAS_CNTLR_SAS_HBA 0x00000001 #define CSMI_SAS_CNTLR_SAS_RAID 0x00000002 #define CSMI_SAS_CNTLR_SATA_HBA 0x00000004 #define CSMI_SAS_CNTLR_SATA_RAID 0x00000008 #define CSMI_SAS_CNTLR_SMART_ARRAY 0x00000010 // for firmware download #define CSMI_SAS_CNTLR_FWD_SUPPORT 0x00010000 #define CSMI_SAS_CNTLR_FWD_ONLINE 0x00020000 #define CSMI_SAS_CNTLR_FWD_SRESET 0x00040000 #define CSMI_SAS_CNTLR_FWD_HRESET 0x00080000 #define CSMI_SAS_CNTLR_FWD_RROM 0x00100000 // for RAID configuration supported #define CSMI_SAS_CNTLR_RAID_CFG_SUPPORT 0x01000000 // Download Flag bits // (uDownloadFlags) #define CSMI_SAS_FWD_VALIDATE 0x00000001 #define CSMI_SAS_FWD_SOFT_RESET 0x00000002 #define CSMI_SAS_FWD_HARD_RESET 0x00000004 // Firmware Download Status // (usStatus) #define CSMI_SAS_FWD_SUCCESS 0 #define CSMI_SAS_FWD_FAILED 1 #define CSMI_SAS_FWD_USING_RROM 2 #define CSMI_SAS_FWD_REJECT 3 #define CSMI_SAS_FWD_DOWNREV 4 // Firmware Download Severity // (usSeverity> #define CSMI_SAS_FWD_INFORMATION 0 #define CSMI_SAS_FWD_WARNING 1 #define CSMI_SAS_FWD_ERROR 2 #define CSMI_SAS_FWD_FATAL 3 /* * * * * * * * * * SAS RAID Class IOCTL Constants * * * * * * * * */ // Return codes for the RAID IOCTL's regardless of class // (IoctlHeader.ReturnCode) #define CSMI_SAS_RAID_SET_OUT_OF_RANGE 1000 #define CSMI_SAS_RAID_SET_BUFFER_TOO_SMALL 1001 #define CSMI_SAS_RAID_SET_DATA_CHANGED 1002 // Signature value // (IoctlHeader.Signature) #define CSMI_RAID_SIGNATURE "CSMIARY" // Timeout value default of 60 seconds // (IoctlHeader.Timeout) #define CSMI_RAID_TIMEOUT 60 // RAID Types // (bRaidType) #define CSMI_SAS_RAID_TYPE_NONE 0 #define CSMI_SAS_RAID_TYPE_0 1 #define CSMI_SAS_RAID_TYPE_1 2 #define CSMI_SAS_RAID_TYPE_10 3 #define CSMI_SAS_RAID_TYPE_5 4 #define CSMI_SAS_RAID_TYPE_15 5 #define CSMI_SAS_RAID_TYPE_6 6 #define CSMI_SAS_RAID_TYPE_50 7 #define CSMI_SAS_RAID_TYPE_VOLUME 8 #define CSMI_SAS_RAID_TYPE_1E 9 #define CSMI_SAS_RAID_TYPE_OTHER 255 // the last value 255 was already defined for other // so end is defined as 254 #define CSMI_SAS_RAID_TYPE_END 254 // RAID Status // (bStatus) #define CSMI_SAS_RAID_SET_STATUS_OK 0 #define CSMI_SAS_RAID_SET_STATUS_DEGRADED 1 #define CSMI_SAS_RAID_SET_STATUS_REBUILDING 2 #define CSMI_SAS_RAID_SET_STATUS_FAILED 3 #define CSMI_SAS_RAID_SET_STATUS_OFFLINE 4 #define CSMI_SAS_RAID_SET_STATUS_TRANSFORMING 5 #define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_REBUILD 6 #define CSMI_SAS_RAID_SET_STATUS_QUEUED_FOR_TRANSFORMATION 7 // RAID Drive Count // (bDriveCount, 0xF1 to 0xFF are reserved) #define CSMI_SAS_RAID_DRIVE_COUNT_TOO_BIG 0xF1 #define CSMI_SAS_RAID_DRIVE_COUNT_SUPRESSED 0xF2 // RAID Data Type // (bDataType) #define CSMI_SAS_RAID_DATA_DRIVES 0 #define CSMI_SAS_RAID_DATA_DEVICE_ID 1 #define CSMI_SAS_RAID_DATA_ADDITIONAL_DATA 2 // RAID Drive Status // (bDriveStatus) #define CSMI_SAS_DRIVE_STATUS_OK 0 #define CSMI_SAS_DRIVE_STATUS_REBUILDING 1 #define CSMI_SAS_DRIVE_STATUS_FAILED 2 #define CSMI_SAS_DRIVE_STATUS_DEGRADED 3 #define CSMI_SAS_DRIVE_STATUS_OFFLINE 4 #define CSMI_SAS_DRIVE_STATUS_QUEUED_FOR_REBUILD 5 // RAID Drive Usage // (bDriveUsage) #define CSMI_SAS_DRIVE_CONFIG_NOT_USED 0 #define CSMI_SAS_DRIVE_CONFIG_MEMBER 1 #define CSMI_SAS_DRIVE_CONFIG_SPARE 2 #define CSMI_SAS_DRIVE_CONFIG_SPARE_ACTIVE 3 // RAID Drive Type // (bDriveType) #define CSMI_SAS_DRIVE_TYPE_UNKNOWN 0 #define CSMI_SAS_DRIVE_TYPE_SINGLE_PORT_SAS 1 #define CSMI_SAS_DRIVE_TYPE_DUAL_PORT_SAS 2 #define CSMI_SAS_DRIVE_TYPE_SATA 3 #define CSMI_SAS_DRIVE_TYPE_SATA_PS 4 #define CSMI_SAS_DRIVE_TYPE_OTHER 255 // RAID Write Protect // (bWriteProtect) #define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNKNOWN 0 #define CSMI_SAS_RAID_SET_WRITE_PROTECT_UNCHANGED 0 #define CSMI_SAS_RAID_SET_WRITE_PROTECT_ENABLED 1 #define CSMI_SAS_RAID_SET_WRITE_PROTECT_DISABLED 2 // RAID Cache Setting // (bCacheSetting) #define CSMI_SAS_RAID_SET_CACHE_UNKNOWN 0 #define CSMI_SAS_RAID_SET_CACHE_UNCHANGED 0 #define CSMI_SAS_RAID_SET_CACHE_ENABLED 1 #define CSMI_SAS_RAID_SET_CACHE_DISABLED 2 #define CSMI_SAS_RAID_SET_CACHE_CORRUPT 3 // RAID Features // (uFeatures) #define CSMI_SAS_RAID_FEATURE_TRANSFORMATION 0x00000001 #define CSMI_SAS_RAID_FEATURE_REBUILD 0x00000002 #define CSMI_SAS_RAID_FEATURE_SPLIT_MIRROR 0x00000004 #define CSMI_SAS_RAID_FEATURE_MERGE_MIRROR 0x00000008 #define CSMI_SAS_RAID_FEATURE_LUN_RENUMBER 0x00000010 #define CSMI_SAS_RAID_FEATURE_SURFACE_SCAN 0x00000020 #define CSMI_SAS_RAID_FEATURE_SPARES_SHARED 0x00000040 // RAID Priority // (bDefaultTransformPriority, etc.) #define CSMI_SAS_PRIORITY_UNKNOWN 0 #define CSMI_SAS_PRIORITY_UNCHANGED 0 #define CSMI_SAS_PRIORITY_AUTO 1 #define CSMI_SAS_PRIORITY_OFF 2 #define CSMI_SAS_PRIORITY_LOW 3 #define CSMI_SAS_PRIORITY_MEDIUM 4 #define CSMI_SAS_PRIORITY_HIGH 5 // RAID Transformation Rules // (uRaidSetTransformationRules) #define CSMI_SAS_RAID_RULE_AVAILABLE_MEMORY 0x00000001 #define CSMI_SAS_RAID_RULE_OVERLAPPED_EXTENTS 0x00000002 // RAID Cache Ratios Supported // (bCacheRatiosSupported) // from 0 to 100 defines the write to read ratio, 0 is 100% write #define CSMI_SAS_RAID_CACHE_RATIO_RANGE 101 #define CSMI_SAS_RAID_CACHE_RATIO_FIXED 102 #define CSMI_SAS_RAID_CACHE_RATIO_AUTO 103 #define CSMI_SAS_RAID_CACHE_RATIO_END 255 // RAID Cache Ratio Flag // (bCacheRatioFlag) #define CSMI_SAS_RAID_CACHE_RATIO_DISABLE 0 #define CSMI_SAS_RAID_CACHE_RATIO_ENABLE 1 // RAID Clear Configuration Signature // (bClearConfiguration) #define CSMI_SAS_RAID_CLEAR_CONFIGURATION_SIGNATURE "RAIDCLR" // RAID Failure Codes // (uFailureCode) #define CSMI_SAS_FAIL_CODE_OK 0 #define CSMI_SAS_FAIL_CODE_PARAMETER_INVALID 1000 #define CSMI_SAS_FAIL_CODE_TRANSFORM_PRIORITY_INVALID 1001 #define CSMI_SAS_FAIL_CODE_REBUILD_PRIORITY_INVALID 1002 #define CSMI_SAS_FAIL_CODE_CACHE_RATIO_INVALID 1003 #define CSMI_SAS_FAIL_CODE_SURFACE_SCAN_INVALID 1004 #define CSMI_SAS_FAIL_CODE_CLEAR_CONFIGURATION_INVALID 1005 #define CSMI_SAS_FAIL_CODE_ELEMENT_INDEX_INVALID 1006 #define CSMI_SAS_FAIL_CODE_SUBELEMENT_INDEX_INVALID 1007 #define CSMI_SAS_FAIL_CODE_EXTENT_INVALID 1008 #define CSMI_SAS_FAIL_CODE_BLOCK_COUNT_INVALID 1009 #define CSMI_SAS_FAIL_CODE_DRIVE_INDEX_INVALID 1010 #define CSMI_SAS_FAIL_CODE_EXISTING_LUN_INVALID 1011 #define CSMI_SAS_FAIL_CODE_RAID_TYPE_INVALID 1012 #define CSMI_SAS_FAIL_CODE_STRIPE_SIZE_INVALID 1013 #define CSMI_SAS_FAIL_CODE_TRANSFORMATION_INVALID 1014 #define CSMI_SAS_FAIL_CODE_CHANGE_COUNT_INVALID 1015 #define CSMI_SAS_FAIL_CODE_ENUMERATION_TYPE_INVALID 1016 #define CSMI_SAS_FAIL_CODE_EXCEEDED_RAID_SET_COUNT 2000 #define CSMI_SAS_FAIL_CODE_DUPLICATE_LUN 2001 #define CSMI_SAS_FAIL_CODE_WAIT_FOR_OPERATION 3000 // RAID Enumeration Types // (uEnumerationType) #define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE 0 #define CSMI_SAS_RAID_ELEMENT_TYPE_MODULE 1 #define CSMI_SAS_RAID_ELEMENT_TYPE_DRIVE_RAID_SET 2 #define CSMI_SAS_RAID_ELEMENT_TYPE_EXTENT_DRIVE 3 // RAID Extent Types // (bExtentType) #define CSMI_SAS_RAID_EXTENT_RESERVED 0 #define CSMI_SAS_RAID_EXTENT_METADATA 1 #define CSMI_SAS_RAID_EXTENT_ALLOCATED 2 #define CSMI_SAS_RAID_EXTENT_UNALLOCATED 3 // RAID Operation Types // (uOperationType) #define CSMI_SAS_RAID_SET_CREATE 0 #define CSMI_SAS_RAID_SET_LABEL 1 #define CSMI_SAS_RAID_SET_TRANSFORM 2 #define CSMI_SAS_RAID_SET_DELETE 3 #define CSMI_SAS_RAID_SET_WRITE_PROTECT 4 #define CSMI_SAS_RAID_SET_CACHE 5 #define CSMI_SAS_RAID_SET_ONLINE_STATE 6 #define CSMI_SAS_RAID_SET_SPARE 7 // RAID Transform Types // (bTransformType) #define CSMI_SAS_RAID_SET_TRANSFORM_SPLIT_MIRROR 0 #define CSMI_SAS_RAID_SET_TRANSFORM_MERGE_RAID_0 1 #define CSMI_SAS_RAID_SET_TRANSFORM_LUN_RENUMBER 2 #define CSMI_SAS_RAID_SET_TRANSFORM_RAID_SET 3 // RAID Online State // (bOnlineState) #define CSMI_SAS_RAID_SET_STATE_UNKNOWN 0 #define CSMI_SAS_RAID_SET_STATE_ONLINE 1 #define CSMI_SAS_RAID_SET_STATE_OFFLINE 2 /* * * * * * * * * * SAS HBA Class IOCTL Constants * * * * * * * * * */ // Return codes for SAS IOCTL's // (IoctlHeader.ReturnCode) #define CSMI_SAS_PHY_INFO_CHANGED CSMI_SAS_STATUS_SUCCESS #define CSMI_SAS_PHY_INFO_NOT_CHANGEABLE 2000 #define CSMI_SAS_LINK_RATE_OUT_OF_RANGE 2001 #define CSMI_SAS_PHY_DOES_NOT_EXIST 2002 #define CSMI_SAS_PHY_DOES_NOT_MATCH_PORT 2003 #define CSMI_SAS_PHY_CANNOT_BE_SELECTED 2004 #define CSMI_SAS_SELECT_PHY_OR_PORT 2005 #define CSMI_SAS_PORT_DOES_NOT_EXIST 2006 #define CSMI_SAS_PORT_CANNOT_BE_SELECTED 2007 #define CSMI_SAS_CONNECTION_FAILED 2008 #define CSMI_SAS_NO_SATA_DEVICE 2009 #define CSMI_SAS_NO_SATA_SIGNATURE 2010 #define CSMI_SAS_SCSI_EMULATION 2011 #define CSMI_SAS_NOT_AN_END_DEVICE 2012 #define CSMI_SAS_NO_SCSI_ADDRESS 2013 #define CSMI_SAS_NO_DEVICE_ADDRESS 2014 // Signature value // (IoctlHeader.Signature) #define CSMI_SAS_SIGNATURE "CSMISAS" // Timeout value default of 60 seconds // (IoctlHeader.Timeout) #define CSMI_SAS_TIMEOUT 60 // Device types // (bDeviceType) #define CSMI_SAS_PHY_UNUSED 0x00 #define CSMI_SAS_NO_DEVICE_ATTACHED 0x00 #define CSMI_SAS_END_DEVICE 0x10 #define CSMI_SAS_EDGE_EXPANDER_DEVICE 0x20 #define CSMI_SAS_FANOUT_EXPANDER_DEVICE 0x30 // Protocol options // (bInitiatorPortProtocol, bTargetPortProtocol) #define CSMI_SAS_PROTOCOL_SATA 0x01 #define CSMI_SAS_PROTOCOL_SMP 0x02 #define CSMI_SAS_PROTOCOL_STP 0x04 #define CSMI_SAS_PROTOCOL_SSP 0x08 // Negotiated and hardware link rates // (bNegotiatedLinkRate, bMinimumLinkRate, bMaximumLinkRate) #define CSMI_SAS_LINK_RATE_UNKNOWN 0x00 #define CSMI_SAS_PHY_DISABLED 0x01 #define CSMI_SAS_LINK_RATE_FAILED 0x02 #define CSMI_SAS_SATA_SPINUP_HOLD 0x03 #define CSMI_SAS_SATA_PORT_SELECTOR 0x04 #define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08 #define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09 #define CSMI_SAS_LINK_VIRTUAL 0x10 // Discover state // (bAutoDiscover) #define CSMI_SAS_DISCOVER_NOT_SUPPORTED 0x00 #define CSMI_SAS_DISCOVER_NOT_STARTED 0x01 #define CSMI_SAS_DISCOVER_IN_PROGRESS 0x02 #define CSMI_SAS_DISCOVER_COMPLETE 0x03 #define CSMI_SAS_DISCOVER_ERROR 0x04 // Phy features #define CSMI_SAS_PHY_VIRTUAL_SMP 0x01 // Programmed link rates // (bMinimumLinkRate, bMaximumLinkRate) // (bProgrammedMinimumLinkRate, bProgrammedMaximumLinkRate) #define CSMI_SAS_PROGRAMMED_LINK_RATE_UNCHANGED 0x00 #define CSMI_SAS_PROGRAMMED_LINK_RATE_1_5_GBPS 0x08 #define CSMI_SAS_PROGRAMMED_LINK_RATE_3_0_GBPS 0x09 // Link rate // (bNegotiatedLinkRate in CSMI_SAS_SET_PHY_INFO) #define CSMI_SAS_LINK_RATE_NEGOTIATE 0x00 #define CSMI_SAS_LINK_RATE_PHY_DISABLED 0x01 // Signal class // (bSignalClass in CSMI_SAS_SET_PHY_INFO) #define CSMI_SAS_SIGNAL_CLASS_UNKNOWN 0x00 #define CSMI_SAS_SIGNAL_CLASS_DIRECT 0x01 #define CSMI_SAS_SIGNAL_CLASS_SERVER 0x02 #define CSMI_SAS_SIGNAL_CLASS_ENCLOSURE 0x03 // Link error reset // (bResetCounts) #define CSMI_SAS_LINK_ERROR_DONT_RESET_COUNTS 0x00 #define CSMI_SAS_LINK_ERROR_RESET_COUNTS 0x01 // Phy identifier // (bPhyIdentifier) #define CSMI_SAS_USE_PORT_IDENTIFIER 0xFF // Port identifier // (bPortIdentifier) #define CSMI_SAS_IGNORE_PORT 0xFF // Programmed link rates // (bConnectionRate) #define CSMI_SAS_LINK_RATE_NEGOTIATED 0x00 #define CSMI_SAS_LINK_RATE_1_5_GBPS 0x08 #define CSMI_SAS_LINK_RATE_3_0_GBPS 0x09 // Connection status // (bConnectionStatus) #define CSMI_SAS_OPEN_ACCEPT 0 #define CSMI_SAS_OPEN_REJECT_BAD_DESTINATION 1 #define CSMI_SAS_OPEN_REJECT_RATE_NOT_SUPPORTED 2 #define CSMI_SAS_OPEN_REJECT_NO_DESTINATION 3 #define CSMI_SAS_OPEN_REJECT_PATHWAY_BLOCKED 4 #define CSMI_SAS_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED 5 #define CSMI_SAS_OPEN_REJECT_RESERVE_ABANDON 6 #define CSMI_SAS_OPEN_REJECT_RESERVE_CONTINUE 7 #define CSMI_SAS_OPEN_REJECT_RESERVE_INITIALIZE 8 #define CSMI_SAS_OPEN_REJECT_RESERVE_STOP 9 #define CSMI_SAS_OPEN_REJECT_RETRY 10 #define CSMI_SAS_OPEN_REJECT_STP_RESOURCES_BUSY 11 #define CSMI_SAS_OPEN_REJECT_WRONG_DESTINATION 12 // SSP Status // (bSSPStatus) #define CSMI_SAS_SSP_STATUS_UNKNOWN 0x00 #define CSMI_SAS_SSP_STATUS_WAITING 0x01 #define CSMI_SAS_SSP_STATUS_COMPLETED 0x02 #define CSMI_SAS_SSP_STATUS_FATAL_ERROR 0x03 #define CSMI_SAS_SSP_STATUS_RETRY 0x04 #define CSMI_SAS_SSP_STATUS_NO_TAG 0x05 // SSP Flags // (uFlags) #define CSMI_SAS_SSP_READ 0x00000001 #define CSMI_SAS_SSP_WRITE 0x00000002 #define CSMI_SAS_SSP_UNSPECIFIED 0x00000004 #define CSMI_SAS_SSP_TASK_ATTRIBUTE_SIMPLE 0x00000000 #define CSMI_SAS_SSP_TASK_ATTRIBUTE_HEAD_OF_QUEUE 0x00000010 #define CSMI_SAS_SSP_TASK_ATTRIBUTE_ORDERED 0x00000020 #define CSMI_SAS_SSP_TASK_ATTRIBUTE_ACA 0x00000040 // SSP Data present // (bDataPresent) #define CSMI_SAS_SSP_NO_DATA_PRESENT 0x00 #define CSMI_SAS_SSP_RESPONSE_DATA_PRESENT 0x01 #define CSMI_SAS_SSP_SENSE_DATA_PRESENT 0x02 // STP Flags // (uFlags) #define CSMI_SAS_STP_READ 0x00000001 #define CSMI_SAS_STP_WRITE 0x00000002 #define CSMI_SAS_STP_UNSPECIFIED 0x00000004 #define CSMI_SAS_STP_PIO 0x00000010 #define CSMI_SAS_STP_DMA 0x00000020 #define CSMI_SAS_STP_PACKET 0x00000040 #define CSMI_SAS_STP_DMA_QUEUED 0x00000080 #define CSMI_SAS_STP_EXECUTE_DIAG 0x00000100 #define CSMI_SAS_STP_RESET_DEVICE 0x00000200 // Task Management Flags // (uFlags) #define CSMI_SAS_TASK_IU 0x00000001 #define CSMI_SAS_HARD_RESET_SEQUENCE 0x00000002 #define CSMI_SAS_SUPPRESS_RESULT 0x00000004 // Task Management Functions // (bTaskManagement) #define CSMI_SAS_SSP_ABORT_TASK 0x01 #define CSMI_SAS_SSP_ABORT_TASK_SET 0x02 #define CSMI_SAS_SSP_CLEAR_TASK_SET 0x04 #define CSMI_SAS_SSP_LOGICAL_UNIT_RESET 0x08 #define CSMI_SAS_SSP_CLEAR_ACA 0x40 #define CSMI_SAS_SSP_QUERY_TASK 0x80 // Task Management Information // (uInformation) #define CSMI_SAS_SSP_TEST 1 #define CSMI_SAS_SSP_EXCEEDED 2 #define CSMI_SAS_SSP_DEMAND 3 #define CSMI_SAS_SSP_TRIGGER 4 // Connector Pinout Information // (uPinout) #define CSMI_SAS_CON_UNKNOWN 0x00000001 #define CSMI_SAS_CON_SFF_8482 0x00000002 #define CSMI_SAS_CON_SFF_8470_LANE_1 0x00000100 #define CSMI_SAS_CON_SFF_8470_LANE_2 0x00000200 #define CSMI_SAS_CON_SFF_8470_LANE_3 0x00000400 #define CSMI_SAS_CON_SFF_8470_LANE_4 0x00000800 #define CSMI_SAS_CON_SFF_8484_LANE_1 0x00010000 #define CSMI_SAS_CON_SFF_8484_LANE_2 0x00020000 #define CSMI_SAS_CON_SFF_8484_LANE_3 0x00040000 #define CSMI_SAS_CON_SFF_8484_LANE_4 0x00080000 // Connector Location Information // (bLocation) // same as uPinout above... // #define CSMI_SAS_CON_UNKNOWN 0x01 #define CSMI_SAS_CON_INTERNAL 0x02 #define CSMI_SAS_CON_EXTERNAL 0x04 #define CSMI_SAS_CON_SWITCHABLE 0x08 #define CSMI_SAS_CON_AUTO 0x10 #define CSMI_SAS_CON_NOT_PRESENT 0x20 #define CSMI_SAS_CON_NOT_CONNECTED 0x80 // Device location identification // (bIdentify) #define CSMI_SAS_LOCATE_UNKNOWN 0x00 #define CSMI_SAS_LOCATE_FORCE_OFF 0x01 #define CSMI_SAS_LOCATE_FORCE_ON 0x02 // Location Valid flags // (uLocationFlags) #define CSMI_SAS_LOCATE_SAS_ADDRESS_VALID 0x00000001 #define CSMI_SAS_LOCATE_SAS_LUN_VALID 0x00000002 #define CSMI_SAS_LOCATE_ENCLOSURE_IDENTIFIER_VALID 0x00000004 #define CSMI_SAS_LOCATE_ENCLOSURE_NAME_VALID 0x00000008 #define CSMI_SAS_LOCATE_BAY_PREFIX_VALID 0x00000010 #define CSMI_SAS_LOCATE_BAY_IDENTIFIER_VALID 0x00000020 #define CSMI_SAS_LOCATE_LOCATION_STATE_VALID 0x00000040 /* * * * * * * * SAS Phy Control Class IOCTL Constants * * * * * * * * */ // Return codes for SAS Phy Control IOCTL's // (IoctlHeader.ReturnCode) // Signature value // (IoctlHeader.Signature) #define CSMI_PHY_SIGNATURE "CSMIPHY" // Phy Control Functions // (bFunction) // values 0x00 to 0xFF are consistent in definition with the SMP PHY CONTROL // function defined in the SAS spec #define CSMI_SAS_PC_NOP 0x00000000 #define CSMI_SAS_PC_LINK_RESET 0x00000001 #define CSMI_SAS_PC_HARD_RESET 0x00000002 #define CSMI_SAS_PC_PHY_DISABLE 0x00000003 // 0x04 to 0xFF reserved... #define CSMI_SAS_PC_GET_PHY_SETTINGS 0x00000100 // Link Flags #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 #define CSMI_SAS_PHY_UPDATE_SPINUP_RATE 0x00000002 #define CSMI_SAS_PHY_AUTO_COMWAKE 0x00000004 // Device Types for Phy Settings // (bType) #define CSMI_SAS_UNDEFINED 0x00 #define CSMI_SAS_SATA 0x01 #define CSMI_SAS_SAS 0x02 // Transmitter Flags // (uTransmitterFlags) #define CSMI_SAS_PHY_PREEMPHASIS_DISABLED 0x00000001 // Receiver Flags // (uReceiverFlags) #define CSMI_SAS_PHY_EQUALIZATION_DISABLED 0x00000001 // Pattern Flags // (uPatternFlags) // #define CSMI_SAS_PHY_ACTIVATE_CONTROL 0x00000001 #define CSMI_SAS_PHY_DISABLE_SCRAMBLING 0x00000002 #define CSMI_SAS_PHY_DISABLE_ALIGN 0x00000004 #define CSMI_SAS_PHY_DISABLE_SSC 0x00000008 #define CSMI_SAS_PHY_FIXED_PATTERN 0x00000010 #define CSMI_SAS_PHY_USER_PATTERN 0x00000020 // Fixed Patterns // (bFixedPattern) #define CSMI_SAS_PHY_CJPAT 0x00000001 #define CSMI_SAS_PHY_ALIGN 0x00000002 // Type Flags // (bTypeFlags) #define CSMI_SAS_PHY_POSITIVE_DISPARITY 0x01 #define CSMI_SAS_PHY_NEGATIVE_DISPARITY 0x02 #define CSMI_SAS_PHY_CONTROL_CHARACTER 0x04 // Miscellaneous #define SLOT_NUMBER_UNKNOWN 0xFFFF /*************************************************************************/ /* DATA STRUCTURES */ /*************************************************************************/ /* * * * * * * * * * Class Independent Structures * * * * * * * * * */ // EDM #pragma CSMI_SAS_BEGIN_PACK(8) #pragma pack(8) // CC_CSMI_SAS_DRIVER_INFO typedef struct _CSMI_SAS_DRIVER_INFO { __u8 szName[81]; __u8 szDescription[81]; __u16 usMajorRevision; __u16 usMinorRevision; __u16 usBuildRevision; __u16 usReleaseRevision; __u16 usCSMIMajorRevision; __u16 usCSMIMinorRevision; } CSMI_SAS_DRIVER_INFO, *PCSMI_SAS_DRIVER_INFO; typedef struct _CSMI_SAS_DRIVER_INFO_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_DRIVER_INFO Information; } CSMI_SAS_DRIVER_INFO_BUFFER, *PCSMI_SAS_DRIVER_INFO_BUFFER; // CC_CSMI_SAS_CNTLR_CONFIGURATION typedef struct _CSMI_SAS_PCI_BUS_ADDRESS { __u8 bBusNumber; __u8 bDeviceNumber; __u8 bFunctionNumber; __u8 bReserved; } CSMI_SAS_PCI_BUS_ADDRESS, *PCSMI_SAS_PCI_BUS_ADDRESS; typedef union _CSMI_SAS_IO_BUS_ADDRESS { CSMI_SAS_PCI_BUS_ADDRESS PciAddress; __u8 bReserved[32]; } CSMI_SAS_IO_BUS_ADDRESS, *PCSMI_SAS_IO_BUS_ADDRESS; typedef struct _CSMI_SAS_CNTLR_CONFIG { __u32 uBaseIoAddress; struct { __u32 uLowPart; __u32 uHighPart; } BaseMemoryAddress; __u32 uBoardID; __u16 usSlotNumber; __u8 bControllerClass; __u8 bIoBusType; CSMI_SAS_IO_BUS_ADDRESS BusAddress; __u8 szSerialNumber[81]; __u16 usMajorRevision; __u16 usMinorRevision; __u16 usBuildRevision; __u16 usReleaseRevision; __u16 usBIOSMajorRevision; __u16 usBIOSMinorRevision; __u16 usBIOSBuildRevision; __u16 usBIOSReleaseRevision; __u32 uControllerFlags; __u16 usRromMajorRevision; __u16 usRromMinorRevision; __u16 usRromBuildRevision; __u16 usRromReleaseRevision; __u16 usRromBIOSMajorRevision; __u16 usRromBIOSMinorRevision; __u16 usRromBIOSBuildRevision; __u16 usRromBIOSReleaseRevision; __u8 bReserved[7]; } CSMI_SAS_CNTLR_CONFIG, *PCSMI_SAS_CNTLR_CONFIG; typedef struct _CSMI_SAS_CNTLR_CONFIG_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_CNTLR_CONFIG Configuration; } CSMI_SAS_CNTLR_CONFIG_BUFFER, *PCSMI_SAS_CNTLR_CONFIG_BUFFER; // CC_CSMI_SAS_CNTLR_STATUS typedef struct _CSMI_SAS_CNTLR_STATUS { __u32 uStatus; __u32 uOfflineReason; __u8 bReserved[28]; } CSMI_SAS_CNTLR_STATUS, *PCSMI_SAS_CNTLR_STATUS; typedef struct _CSMI_SAS_CNTLR_STATUS_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_CNTLR_STATUS Status; } CSMI_SAS_CNTLR_STATUS_BUFFER, *PCSMI_SAS_CNTLR_STATUS_BUFFER; // CC_CSMI_SAS_FIRMWARE_DOWNLOAD typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD { __u32 uBufferLength; __u32 uDownloadFlags; __u8 bReserved[32]; __u16 usStatus; __u16 usSeverity; } CSMI_SAS_FIRMWARE_DOWNLOAD, *PCSMI_SAS_FIRMWARE_DOWNLOAD; typedef struct _CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_FIRMWARE_DOWNLOAD Information; __u8 bDataBuffer[1]; } CSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER, *PCSMI_SAS_FIRMWARE_DOWNLOAD_BUFFER; // CC_CSMI_SAS_RAID_INFO typedef struct _CSMI_SAS_RAID_INFO { __u32 uNumRaidSets; __u32 uMaxDrivesPerSet; __u32 uMaxRaidSets; __u8 bMaxRaidTypes; __u8 bReservedByteFields[7]; struct { __u32 uLowPart; __u32 uHighPart; } ulMinRaidSetBlocks; struct { __u32 uLowPart; __u32 uHighPart; } ulMaxRaidSetBlocks; __u32 uMaxPhysicalDrives; __u32 uMaxExtents; __u32 uMaxModules; __u32 uMaxTransformationMemory; __u32 uChangeCount; __u8 bReserved[44]; } CSMI_SAS_RAID_INFO, *PCSMI_SAS_RAID_INFO; typedef struct _CSMI_SAS_RAID_INFO_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_RAID_INFO Information; } CSMI_SAS_RAID_INFO_BUFFER, *PCSMI_SAS_RAID_INFO_BUFFER; // CC_CSMI_SAS_GET_RAID_CONFIG typedef struct _CSMI_SAS_RAID_DRIVES { __u8 bModel[40]; __u8 bFirmware[8]; __u8 bSerialNumber[40]; __u8 bSASAddress[8]; __u8 bSASLun[8]; __u8 bDriveStatus; __u8 bDriveUsage; __u16 usBlockSize; __u8 bDriveType; __u8 bReserved[15]; __u32 uDriveIndex; struct { __u32 uLowPart; __u32 uHighPart; } ulTotalUserBlocks; } CSMI_SAS_RAID_DRIVES, *PCSMI_SAS_RAID_DRIVES; typedef struct _CSMI_SAS_RAID_DEVICE_ID { __u8 bDeviceIdentificationVPDPage[1]; } CSMI_SAS_RAID_DEVICE_ID, *PCSMI_SAS_RAID_DEVICE_ID; typedef struct _CSMI_SAS_RAID_SET_ADDITIONAL_DATA { __u8 bLabel[16]; __u8 bRaidSetLun[8]; __u8 bWriteProtection; __u8 bCacheSetting; __u8 bCacheRatio; __u16 usBlockSize; __u8 bReservedBytes[11]; struct { __u32 uLowPart; __u32 uHighPart; } ulRaidSetExtentOffset; struct { __u32 uLowPart; __u32 uHighPart; } ulRaidSetBlocks; __u32 uStripeSizeInBlocks; __u32 uSectorsPerTrack; __u8 bApplicationScratchPad[16]; __u32 uNumberOfHeads; __u32 uNumberOfTracks; __u8 bReserved[24]; } CSMI_SAS_RAID_SET_ADDITIONAL_DATA, *PCSMI_SAS_RAID_SET_ADDITIONAL_DATA; typedef struct _CSMI_SAS_RAID_CONFIG { __u32 uRaidSetIndex; __u32 uCapacity; __u32 uStripeSize; __u8 bRaidType; __u8 bStatus; __u8 bInformation; __u8 bDriveCount; __u8 bDataType; __u8 bReserved[11]; __u32 uFailureCode; __u32 uChangeCount; union { CSMI_SAS_RAID_DRIVES Drives[1]; CSMI_SAS_RAID_DEVICE_ID DeviceId[1]; CSMI_SAS_RAID_SET_ADDITIONAL_DATA Data[1]; }; } CSMI_SAS_RAID_CONFIG, *PCSMI_SAS_RAID_CONFIG; typedef struct _CSMI_SAS_RAID_CONFIG_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_RAID_CONFIG Configuration; } CSMI_SAS_RAID_CONFIG_BUFFER, *PCSMI_SAS_RAID_CONFIG_BUFFER; // CC_CSMI_SAS_GET_RAID_FEATURES typedef struct _CSMI_SAS_RAID_TYPE_DESCRIPTION { __u8 bRaidType; __u8 bReservedBytes[7]; __u32 uSupportedStripeSizeMap; __u8 bReserved[24]; } CSMI_SAS_RAID_TYPE_DESCRIPTION, *PCSMI_SAS_RAID_TYPE_DESCRIPTION; typedef struct _CSMI_SAS_RAID_FEATURES { __u32 uFeatures; __u8 bReservedFeatures[32]; __u8 bDefaultTransformPriority; __u8 bTransformPriority; __u8 bDefaultRebuildPriority; __u8 bRebuildPriority; __u8 bDefaultSurfaceScanPriority; __u8 bSurfaceScanPriority; __u16 usReserved; __u32 uRaidSetTransformationRules; __u32 uReserved[11]; CSMI_SAS_RAID_TYPE_DESCRIPTION RaidType[24]; __u8 bCacheRatiosSupported[104]; __u32 uChangeCount; __u32 uFailureCode; __u8 bReserved[120]; } CSMI_SAS_RAID_FEATURES, *PCSMI_SAS_RAID_FEATURES; typedef struct _CSMI_SAS_RAID_FEATURES_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_RAID_FEATURES Information; } CSMI_SAS_RAID_FEATURES_BUFFER, *PCSMI_SAS_RAID_FEATURES_BUFFER; // CC_CSMI_SAS_SET_RAID_CONTROL typedef struct _CSMI_SAS_RAID_CONTROL { __u8 bTransformPriority; __u8 bRebuildPriority; __u8 bCacheRatioFlag; __u8 bCacheRatio; __u8 bSurfaceScanPriority; __u8 bReservedBytes[15]; __u8 bClearConfiguration[8]; __u32 uChangeCount; __u8 bReserved[88]; __u32 uFailureCode; __u8 bFailureDescription[80]; } CSMI_SAS_RAID_CONTROL, *PCSMI_SAS_RAID_CONTROL; typedef struct _CSMI_SAS_RAID_CONTROL_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_RAID_CONTROL Information; } CSMI_SAS_RAID_CONTROL_BUFFER, *PCSMI_SAS_RAID_CONTROL_BUFFER; // CC_CSMI_SAS_GET_RAID_ELEMENT typedef struct _CSMI_SAS_DRIVE_EXTENT_INFO { __u32 uDriveIndex; __u8 bExtentType; __u8 bReservedBytes[7]; struct { __u32 uLowPart; __u32 uHighPart; } ulExtentOffset; struct { __u32 uLowPart; __u32 uHighPart; } ulExtentBlocks; __u32 uRaidSetIndex; __u8 bReserved[96]; } CSMI_SAS_DRIVE_EXTENT_INFO, *PCSMI_SAS_DRIVE_EXTENT_INFO; typedef struct _CSMI_SAS_RAID_MODULE_INFO { __u8 bReserved[128]; } CSMI_SAS_RAID_MODULE_INFO, *PCSMI_SAS_RAID_MODULE_INFO; typedef struct _CSMI_SAS_DRIVE_LOCATION { __u8 bConnector[16]; __u8 bBoxName[16]; __u32 uBay; __u8 bReservedBytes[4]; __u8 bAttachedSASAddress[8]; __u8 bAttachedPhyIdentifier; __u8 bReserved[79]; } CSMI_SAS_DRIVE_LOCATION, *PCSMI_SAS_DRIVE_LOCATION; typedef struct _CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA { __u8 bNegotiatedLinkRate[2]; __u8 bReserved[126]; } CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA, *PCSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA; typedef struct _CSMI_SAS_DRIVE_INFO { CSMI_SAS_RAID_DRIVES Device; CSMI_SAS_RAID_DRIVES_ADDITIONAL_DATA Data; CSMI_SAS_DRIVE_LOCATION Location; __u8 bReserved[16]; } CSMI_SAS_DRIVE_INFO, *PCSMI_SAS_DRIVE_INFO; typedef struct _CSMI_SAS_RAID_ELEMENT { __u32 uEnumerationType; __u32 uElementIndex; __u32 uNumElements; __u32 uChangeCount; __u32 uSubElementIndex; __u8 bReserved[32]; __u32 uFailureCode; __u8 bFailureDescription[80]; union { CSMI_SAS_DRIVE_INFO Drive; CSMI_SAS_RAID_MODULE_INFO Module; CSMI_SAS_DRIVE_EXTENT_INFO Extent; } Element; } CSMI_SAS_RAID_ELEMENT, *PCSMI_SAS_RAID_ELEMENT; typedef struct _CSMI_SAS_RAID_ELEMENT_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_RAID_ELEMENT Information; } CSMI_SAS_RAID_ELEMENT_BUFFER, *PCSMI_SAS_RAID_ELEMENT_BUFFER; // CC_CSMI_SAS_SET_RAID_OPERATION typedef struct _CSMI_SAS_RAID_SET_LIST { __u32 uRaidSetIndex; __u8 bExistingLun[8]; __u8 bNewLun[8]; __u8 bReserved[12]; } CSMI_SAS_RAID_SET_LIST, *PCSMI_SAS_RAID_SET_LIST; typedef struct _CSMI_SAS_RAID_SET_DRIVE_LIST { __u32 uDriveIndex; __u8 bDriveUsage; __u8 bReserved[27]; } CSMI_SAS_RAID_SET_DRIVE_LIST, *PCSMI_SAS_RAID_SET_DRIVE_LIST; typedef struct _CSMI_SAS_RAID_SET_SPARE_INFO { __u32 uRaidSetIndex; __u32 uDriveCount; __u8 bApplicationScratchPad[16]; __u8 bReserved[104]; } CSMI_SAS_RAID_SET_SPARE_INFO, *PCSMI_SAS_RAID_SET_SPARE_INFO; typedef struct _CSMI_SAS_RAID_SET_ONLINE_STATE_INFO { __u32 uRaidSetIndex; __u8 bOnlineState; __u8 bReserved[123]; } CSMI_SAS_RAID_SET_ONLINE_STATE_INFO, *PCSMI_SAS_RAID_SET_ONLINE_STATE_INFO; typedef struct _CSMI_SAS_RAID_SET_CACHE_INFO { __u32 uRaidSetIndex; __u8 bCacheSetting; __u8 bCacheRatioFlag; __u8 bCacheRatio; __u8 bReserved[121]; } CSMI_SAS_RAID_SET_CACHE_INFO, *PCSMI_SAS_RAID_SET_CACHE_INFO; typedef struct _CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO { __u32 uRaidSetIndex; __u8 bWriteProtectSetting; __u8 bReserved[123]; } CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO, *PCSMI_SAS_RAID_SET_WRITE_PROTECT_INFO; typedef struct _CSMI_SAS_RAID_SET_DELETE_INFO { __u32 uRaidSetIndex; __u8 bReserved[124]; } CSMI_SAS_RAID_SET_DELETE_INFO, *PCSMI_SAS_RAID_SET_DELETE_INFO; typedef struct _CSMI_SAS_RAID_SET_MODIFY_INFO { __u8 bRaidType; __u8 bReservedBytes[7]; __u32 uStripeSize; struct { __u32 uLowPart; __u32 uHighPart; } ulRaidSetBlocks; struct { __u32 uLowPart; __u32 uHighPart; } ulRaidSetExtentOffset; __u32 uDriveCount; __u8 bReserved[96]; } CSMI_SAS_RAID_SET_MODIFY_INFO, *PCSMI_SAS_RAID_SET_MODIFY_INFO; typedef struct _CSMI_SAS_RAID_SET_TRANSFORM_INFO { __u8 bTransformType; __u8 bReservedBytes[3]; __u32 uRaidSetIndex; __u8 bRaidType; __u8 bReservedBytes2[11]; __u32 uAdditionalRaidSetIndex; __u32 uRaidSetCount; __u8 bApplicationScratchPad[16]; CSMI_SAS_RAID_SET_MODIFY_INFO Modify; __u8 bReserved[80]; } CSMI_SAS_RAID_SET_TRANSFORM_INFO, *PCSMI_SAS_RAID_SET_TRANSFORM_INFO; typedef struct _CSMI_SAS_RAID_SET_LABEL_INFO { __u32 uRaidSetIndex; __u8 bLabel[16]; __u8 bReserved[108]; } CSMI_SAS_RAID_SET_LABEL_INFO, *PCSMI_SAS_RAID_SET_LABEL_INFO; typedef struct _CSMI_SAS_RAID_SET_CREATE_INFO { __u8 bRaidType; __u8 bReservedBytes[7]; __u32 uStripeSize; __u32 uTrackSectorCount; struct { __u32 uLowPart; __u32 uHighPart; } ulRaidSetBlocks; struct { __u32 uLowPart; __u32 uHighPart; } ulRaidSetExtentOffset; __u32 uDriveCount; __u8 bLabel[16]; __u32 uRaidSetIndex; __u8 bApplicationScratchPad[16]; __u32 uNumberOfHeads; __u32 uNumberOfTracks; __u8 bReserved[48]; } CSMI_SAS_RAID_SET_CREATE_INFO, *PCSMI_SAS_RAID_SET_CREATE_INFO; typedef struct _CSMI_SAS_RAID_SET_OPERATION { __u32 uOperationType; __u32 uChangeCount; __u32 uFailureCode; __u8 bFailureDescription[80]; __u8 bReserved[28]; union { CSMI_SAS_RAID_SET_CREATE_INFO Create; CSMI_SAS_RAID_SET_LABEL_INFO Label; CSMI_SAS_RAID_SET_TRANSFORM_INFO Transform; CSMI_SAS_RAID_SET_DELETE_INFO Delete; CSMI_SAS_RAID_SET_WRITE_PROTECT_INFO Protect; CSMI_SAS_RAID_SET_CACHE_INFO Cache; CSMI_SAS_RAID_SET_ONLINE_STATE_INFO State; CSMI_SAS_RAID_SET_SPARE_INFO Spare; } Operation; union { CSMI_SAS_RAID_SET_DRIVE_LIST DriveList[1]; CSMI_SAS_RAID_SET_LIST RaidSetList[1]; } Parameters; } CSMI_SAS_RAID_SET_OPERATION, *PCSMI_SAS_RAID_SET_OPERATION; typedef struct _CSMI_SAS_RAID_SET_OPERATION_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_RAID_SET_OPERATION Information; } CSMI_SAS_RAID_SET_OPERATION_BUFFER, *PCSMI_SAS_RAID_SET_OPERATION_BUFFER; /* * * * * * * * * * SAS HBA Class Structures * * * * * * * * * */ // CC_CSMI_SAS_GET_PHY_INFO typedef struct _CSMI_SAS_IDENTIFY { __u8 bDeviceType; __u8 bRestricted; __u8 bInitiatorPortProtocol; __u8 bTargetPortProtocol; __u8 bRestricted2[8]; __u8 bSASAddress[8]; __u8 bPhyIdentifier; __u8 bSignalClass; __u8 bReserved[6]; } CSMI_SAS_IDENTIFY, *PCSMI_SAS_IDENTIFY; typedef struct _CSMI_SAS_PHY_ENTITY { CSMI_SAS_IDENTIFY Identify; __u8 bPortIdentifier; __u8 bNegotiatedLinkRate; __u8 bMinimumLinkRate; __u8 bMaximumLinkRate; __u8 bPhyChangeCount; __u8 bAutoDiscover; __u8 bPhyFeatures; __u8 bReserved; CSMI_SAS_IDENTIFY Attached; } CSMI_SAS_PHY_ENTITY, *PCSMI_SAS_PHY_ENTITY; typedef struct _CSMI_SAS_PHY_INFO { __u8 bNumberOfPhys; __u8 bReserved[3]; CSMI_SAS_PHY_ENTITY Phy[32]; } CSMI_SAS_PHY_INFO, *PCSMI_SAS_PHY_INFO; typedef struct _CSMI_SAS_PHY_INFO_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_PHY_INFO Information; } CSMI_SAS_PHY_INFO_BUFFER, *PCSMI_SAS_PHY_INFO_BUFFER; // CC_CSMI_SAS_SET_PHY_INFO typedef struct _CSMI_SAS_SET_PHY_INFO { __u8 bPhyIdentifier; __u8 bNegotiatedLinkRate; __u8 bProgrammedMinimumLinkRate; __u8 bProgrammedMaximumLinkRate; __u8 bSignalClass; __u8 bReserved[3]; } CSMI_SAS_SET_PHY_INFO, *PCSMI_SAS_SET_PHY_INFO; typedef struct _CSMI_SAS_SET_PHY_INFO_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_SET_PHY_INFO Information; } CSMI_SAS_SET_PHY_INFO_BUFFER, *PCSMI_SAS_SET_PHY_INFO_BUFFER; // CC_CSMI_SAS_GET_LINK_ERRORS typedef struct _CSMI_SAS_LINK_ERRORS { __u8 bPhyIdentifier; __u8 bResetCounts; __u8 bReserved[2]; __u32 uInvalidDwordCount; __u32 uRunningDisparityErrorCount; __u32 uLossOfDwordSyncCount; __u32 uPhyResetProblemCount; } CSMI_SAS_LINK_ERRORS, *PCSMI_SAS_LINK_ERRORS; typedef struct _CSMI_SAS_LINK_ERRORS_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_LINK_ERRORS Information; } CSMI_SAS_LINK_ERRORS_BUFFER, *PCSMI_SAS_LINK_ERRORS_BUFFER; // CC_CSMI_SAS_SMP_PASSTHRU typedef struct _CSMI_SAS_SMP_REQUEST { __u8 bFrameType; __u8 bFunction; __u8 bReserved[2]; __u8 bAdditionalRequestBytes[1016]; } CSMI_SAS_SMP_REQUEST, *PCSMI_SAS_SMP_REQUEST; typedef struct _CSMI_SAS_SMP_RESPONSE { __u8 bFrameType; __u8 bFunction; __u8 bFunctionResult; __u8 bReserved; __u8 bAdditionalResponseBytes[1016]; } CSMI_SAS_SMP_RESPONSE, *PCSMI_SAS_SMP_RESPONSE; typedef struct _CSMI_SAS_SMP_PASSTHRU { __u8 bPhyIdentifier; __u8 bPortIdentifier; __u8 bConnectionRate; __u8 bReserved; __u8 bDestinationSASAddress[8]; __u32 uRequestLength; CSMI_SAS_SMP_REQUEST Request; __u8 bConnectionStatus; __u8 bReserved2[3]; __u32 uResponseBytes; CSMI_SAS_SMP_RESPONSE Response; } CSMI_SAS_SMP_PASSTHRU, *PCSMI_SAS_SMP_PASSTHRU; typedef struct _CSMI_SAS_SMP_PASSTHRU_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_SMP_PASSTHRU Parameters; } CSMI_SAS_SMP_PASSTHRU_BUFFER, *PCSMI_SAS_SMP_PASSTHRU_BUFFER; // CC_CSMI_SAS_SSP_PASSTHRU typedef struct _CSMI_SAS_SSP_PASSTHRU { __u8 bPhyIdentifier; __u8 bPortIdentifier; __u8 bConnectionRate; __u8 bReserved; __u8 bDestinationSASAddress[8]; __u8 bLun[8]; __u8 bCDBLength; __u8 bAdditionalCDBLength; __u8 bReserved2[2]; __u8 bCDB[16]; __u32 uFlags; __u8 bAdditionalCDB[24]; __u32 uDataLength; } CSMI_SAS_SSP_PASSTHRU, *PCSMI_SAS_SSP_PASSTHRU; typedef struct _CSMI_SAS_SSP_PASSTHRU_STATUS { __u8 bConnectionStatus; __u8 bSSPStatus; __u8 bReserved[2]; __u8 bDataPresent; __u8 bStatus; __u8 bResponseLength[2]; __u8 bResponse[256]; __u32 uDataBytes; } CSMI_SAS_SSP_PASSTHRU_STATUS, *PCSMI_SAS_SSP_PASSTHRU_STATUS; typedef struct _CSMI_SAS_SSP_PASSTHRU_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_SSP_PASSTHRU Parameters; CSMI_SAS_SSP_PASSTHRU_STATUS Status; __u8 bDataBuffer[1]; } CSMI_SAS_SSP_PASSTHRU_BUFFER, *PCSMI_SAS_SSP_PASSTHRU_BUFFER; // CC_CSMI_SAS_STP_PASSTHRU typedef struct _CSMI_SAS_STP_PASSTHRU { __u8 bPhyIdentifier; __u8 bPortIdentifier; __u8 bConnectionRate; __u8 bReserved; __u8 bDestinationSASAddress[8]; __u8 bReserved2[4]; __u8 bCommandFIS[20]; __u32 uFlags; __u32 uDataLength; } CSMI_SAS_STP_PASSTHRU, *PCSMI_SAS_STP_PASSTHRU; typedef struct _CSMI_SAS_STP_PASSTHRU_STATUS { __u8 bConnectionStatus; __u8 bReserved[3]; __u8 bStatusFIS[20]; __u32 uSCR[16]; __u32 uDataBytes; } CSMI_SAS_STP_PASSTHRU_STATUS, *PCSMI_SAS_STP_PASSTHRU_STATUS; typedef struct _CSMI_SAS_STP_PASSTHRU_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_STP_PASSTHRU Parameters; CSMI_SAS_STP_PASSTHRU_STATUS Status; __u8 bDataBuffer[1]; } CSMI_SAS_STP_PASSTHRU_BUFFER, *PCSMI_SAS_STP_PASSTHRU_BUFFER; // CC_CSMI_SAS_GET_SATA_SIGNATURE typedef struct _CSMI_SAS_SATA_SIGNATURE { __u8 bPhyIdentifier; __u8 bReserved[3]; __u8 bSignatureFIS[20]; } CSMI_SAS_SATA_SIGNATURE, *PCSMI_SAS_SATA_SIGNATURE; typedef struct _CSMI_SAS_SATA_SIGNATURE_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_SATA_SIGNATURE Signature; } CSMI_SAS_SATA_SIGNATURE_BUFFER, *PCSMI_SAS_SATA_SIGNATURE_BUFFER; // CC_CSMI_SAS_GET_SCSI_ADDRESS typedef struct _CSMI_SAS_GET_SCSI_ADDRESS_BUFFER { IOCTL_HEADER IoctlHeader; __u8 bSASAddress[8]; __u8 bSASLun[8]; __u8 bHostIndex; __u8 bPathId; __u8 bTargetId; __u8 bLun; } CSMI_SAS_GET_SCSI_ADDRESS_BUFFER, *PCSMI_SAS_GET_SCSI_ADDRESS_BUFFER; // CC_CSMI_SAS_GET_DEVICE_ADDRESS typedef struct _CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER { IOCTL_HEADER IoctlHeader; __u8 bHostIndex; __u8 bPathId; __u8 bTargetId; __u8 bLun; __u8 bSASAddress[8]; __u8 bSASLun[8]; } CSMI_SAS_GET_DEVICE_ADDRESS_BUFFER, *PCSMI_SAS_GET_DEVICE_ADDRESS_BUFFER; // CC_CSMI_SAS_TASK_MANAGEMENT typedef struct _CSMI_SAS_SSP_TASK_IU { __u8 bHostIndex; __u8 bPathId; __u8 bTargetId; __u8 bLun; __u32 uFlags; __u32 uQueueTag; __u32 uReserved; __u8 bTaskManagementFunction; __u8 bReserved[7]; __u32 uInformation; } CSMI_SAS_SSP_TASK_IU, *PCSMI_SAS_SSP_TASK_IU; typedef struct _CSMI_SAS_SSP_TASK_IU_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_SSP_TASK_IU Parameters; CSMI_SAS_SSP_PASSTHRU_STATUS Status; } CSMI_SAS_SSP_TASK_IU_BUFFER, *PCSMI_SAS_SSP_TASK_IU_BUFFER; // CC_CSMI_SAS_GET_CONNECTOR_INFO typedef struct _CSMI_SAS_GET_CONNECTOR_INFO { __u32 uPinout; __u8 bConnector[16]; __u8 bLocation; __u8 bReserved[15]; } CSMI_SAS_CONNECTOR_INFO, *PCSMI_SAS_CONNECTOR_INFO; typedef struct _CSMI_SAS_CONNECTOR_INFO_BUFFER { IOCTL_HEADER IoctlHeader; CSMI_SAS_CONNECTOR_INFO Reference[32]; } CSMI_SAS_CONNECTOR_INFO_BUFFER, *PCSMI_SAS_CONNECTOR_INFO_BUFFER; // CC_CSMI_SAS_GET_LOCATION typedef struct _CSMI_SAS_LOCATION_IDENTIFIER { __u32 bLocationFlags; __u8 bSASAddress[8]; __u8 bSASLun[8]; __u8 bEnclosureIdentifier[8]; __u8 bEnclosureName[32]; __u8 bBayPrefix[32]; __u8 bBayIdentifier; __u8 bLocationState; __u8 bReserved[2]; } CSMI_SAS_LOCATION_IDENTIFIER, *PCSMI_SAS_LOCATION_IDENTIFIER; typedef struct _CSMI_SAS_GET_LOCATION_BUFFER { IOCTL_HEADER IoctlHeader; __u8 bHostIndex; __u8 bPathId; __u8 bTargetId; __u8 bLun; __u8 bIdentify; __u8 bNumberOfLocationIdentifiers; __u8 bLengthOfLocationIdentifier; CSMI_SAS_LOCATION_IDENTIFIER Location[1]; } CSMI_SAS_GET_LOCATION_BUFFER, *PCSMI_SAS_GET_LOCATION_BUFFER; // CC_CSMI_SAS_PHY_CONTROL typedef struct _CSMI_SAS_CHARACTER { __u8 bTypeFlags; __u8 bValue; } CSMI_SAS_CHARACTER, *PCSMI_SAS_CHARACTER; typedef struct _CSMI_SAS_PHY_CONTROL { __u8 bType; __u8 bRate; __u8 bReserved[6]; __u32 uVendorUnique[8]; __u32 uTransmitterFlags; __i8 bTransmitAmplitude; __i8 bTransmitterPreemphasis; __i8 bTransmitterSlewRate; __i8 bTransmitterReserved[13]; __u8 bTransmitterVendorUnique[64]; __u32 uReceiverFlags; __i8 bReceiverThreshold; __i8 bReceiverEqualizationGain; __i8 bReceiverReserved[14]; __u8 bReceiverVendorUnique[64]; __u32 uPatternFlags; __u8 bFixedPattern; __u8 bUserPatternLength; __u8 bPatternReserved[6]; CSMI_SAS_CHARACTER UserPatternBuffer[16]; } CSMI_SAS_PHY_CONTROL, *PCSMI_SAS_PHY_CONTROL; typedef struct _CSMI_SAS_PHY_CONTROL_BUFFER { IOCTL_HEADER IoctlHeader; __u32 uFunction; __u8 bPhyIdentifier; __u16 usLengthOfControl; __u8 bNumberOfControls; __u8 bReserved[4]; __u32 uLinkFlags; __u8 bSpinupRate; __u8 bLinkReserved[7]; __u32 uVendorUnique[8]; CSMI_SAS_PHY_CONTROL Control[1]; } CSMI_SAS_PHY_CONTROL_BUFFER, *PCSMI_SAS_PHY_CONTROL_BUFFER; //EDM #pragma CSMI_SAS_END_PACK #pragma pack() #endif // _CSMI_SAS_H_ ��������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/scsiprint.cpp��������������������������������������������������������0000644�0000000�0000000�00000213570�12134024460�017607� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * scsiprint.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * Additional SCSI work: * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #include <stdio.h> #include <string.h> #include <fcntl.h> #include <errno.h> #include "config.h" #include "int64.h" #include "scsicmds.h" #include "atacmds.h" // smart_command_set #include "dev_interface.h" #include "scsiprint.h" #include "smartctl.h" #include "utility.h" #define GBUF_SIZE 65535 const char * scsiprint_c_cvsid = "$Id: scsiprint.cpp 3807 2013-04-18 17:11:12Z chrfranke $" SCSIPRINT_H_CVSID; UINT8 gBuf[GBUF_SIZE]; #define LOG_RESP_LEN 252 #define LOG_RESP_LONG_LEN ((62 * 256) + 252) #define LOG_RESP_TAPE_ALERT_LEN 0x144 /* Log pages supported */ static int gSmartLPage = 0; /* Informational Exceptions log page */ static int gTempLPage = 0; static int gSelfTestLPage = 0; static int gStartStopLPage = 0; static int gReadECounterLPage = 0; static int gWriteECounterLPage = 0; static int gVerifyECounterLPage = 0; static int gNonMediumELPage = 0; static int gLastNErrorLPage = 0; static int gBackgroundResultsLPage = 0; static int gProtocolSpecificLPage = 0; static int gTapeAlertsLPage = 0; static int gSSMediaLPage = 0; /* Vendor specific log pages */ static int gSeagateCacheLPage = 0; static int gSeagateFactoryLPage = 0; /* Mode pages supported */ static int gIecMPage = 1; /* N.B. assume it until we know otherwise */ /* Remember last successful mode sense/select command */ static int modese_len = 0; static void scsiGetSupportedLogPages(scsi_device * device) { int i, err; if ((err = scsiLogSense(device, SUPPORTED_LPAGES, 0, gBuf, LOG_RESP_LEN, 0))) { if (scsi_debugmode > 0) pout("Log Sense for supported pages failed [%s]\n", scsiErrString(err)); return; } for (i = 4; i < gBuf[3] + LOGPAGEHDRSIZE; i++) { switch (gBuf[i]) { case READ_ERROR_COUNTER_LPAGE: gReadECounterLPage = 1; break; case WRITE_ERROR_COUNTER_LPAGE: gWriteECounterLPage = 1; break; case VERIFY_ERROR_COUNTER_LPAGE: gVerifyECounterLPage = 1; break; case LAST_N_ERROR_LPAGE: gLastNErrorLPage = 1; break; case NON_MEDIUM_ERROR_LPAGE: gNonMediumELPage = 1; break; case TEMPERATURE_LPAGE: gTempLPage = 1; break; case STARTSTOP_CYCLE_COUNTER_LPAGE: gStartStopLPage = 1; break; case SELFTEST_RESULTS_LPAGE: gSelfTestLPage = 1; break; case IE_LPAGE: gSmartLPage = 1; break; case BACKGROUND_RESULTS_LPAGE: gBackgroundResultsLPage = 1; break; case PROTOCOL_SPECIFIC_LPAGE: gProtocolSpecificLPage = 1; break; case TAPE_ALERTS_LPAGE: gTapeAlertsLPage = 1; break; case SS_MEDIA_LPAGE: gSSMediaLPage = 1; break; case SEAGATE_CACHE_LPAGE: gSeagateCacheLPage = 1; break; case SEAGATE_FACTORY_LPAGE: gSeagateFactoryLPage = 1; break; default: break; } } } /* Returns 0 if ok, -1 if can't check IE, -2 if can check and bad (or at least something to report). */ static int scsiGetSmartData(scsi_device * device, bool attribs) { UINT8 asc; UINT8 ascq; UINT8 currenttemp = 0; UINT8 triptemp = 0; const char * cp; int err = 0; print_on(); if (scsiCheckIE(device, gSmartLPage, gTempLPage, &asc, &ascq, ¤ttemp, &triptemp)) { /* error message already announced */ print_off(); return -1; } print_off(); cp = scsiGetIEString(asc, ascq); if (cp) { err = -2; print_on(); pout("SMART Health Status: %s [asc=%x, ascq=%x]\n", cp, asc, ascq); print_off(); } else if (gIecMPage) pout("SMART Health Status: OK\n"); if (attribs && !gTempLPage) { if (currenttemp) { if (255 != currenttemp) pout("Current Drive Temperature: %d C\n", currenttemp); else pout("Current Drive Temperature: <not available>\n"); } if (triptemp) pout("Drive Trip Temperature: %d C\n", triptemp); } pout("\n"); return err; } // Returns number of logged errors or zero if none or -1 if fetching // TapeAlerts fails static const char * const severities = "CWI"; static int scsiGetTapeAlertsData(scsi_device * device, int peripheral_type) { unsigned short pagelength; unsigned short parametercode; int i, err; const char *s; const char *ts; int failures = 0; print_on(); if ((err = scsiLogSense(device, TAPE_ALERTS_LPAGE, 0, gBuf, LOG_RESP_TAPE_ALERT_LEN, LOG_RESP_TAPE_ALERT_LEN))) { pout("scsiGetTapesAlertData Failed [%s]\n", scsiErrString(err)); print_off(); return -1; } if (gBuf[0] != 0x2e) { pout("TapeAlerts Log Sense Failed\n"); print_off(); return -1; } pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3]; for (s=severities; *s; s++) { for (i = 4; i < pagelength; i += 5) { parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1]; if (gBuf[i + 4]) { ts = SCSI_PT_MEDIUM_CHANGER == peripheral_type ? scsiTapeAlertsChangerDevice(parametercode) : scsiTapeAlertsTapeDevice(parametercode); if (*ts == *s) { if (!failures) pout("TapeAlert Errors (C=Critical, W=Warning, " "I=Informational):\n"); pout("[0x%02x] %s\n", parametercode, ts); failures += 1; } } } } print_off(); if (! failures) pout("TapeAlert: OK\n"); return failures; } static void scsiGetStartStopData(scsi_device * device) { UINT32 u; int err, len, k, extra, pc; unsigned char * ucp; if ((err = scsiLogSense(device, STARTSTOP_CYCLE_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { print_on(); pout("scsiGetStartStopData Failed [%s]\n", scsiErrString(err)); print_off(); return; } if ((gBuf[0] & 0x3f) != STARTSTOP_CYCLE_COUNTER_LPAGE) { print_on(); pout("StartStop Log Sense Failed, page mismatch\n"); print_off(); return; } len = ((gBuf[2] << 8) | gBuf[3]); ucp = gBuf + 4; for (k = len; k > 0; k -= extra, ucp += extra) { if (k < 3) { print_on(); pout("StartStop Log Sense Failed: short\n"); print_off(); return; } extra = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; switch (pc) { case 1: if (10 == extra) pout("Manufactured in week %.2s of year %.4s\n", ucp + 8, ucp + 4); break; case 2: /* ignore Accounting date */ break; case 3: if (extra > 7) { u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff != u) pout("Specified cycle count over device lifetime: %u\n", u); } break; case 4: if (extra > 7) { u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff != u) pout("Accumulated start-stop cycles: %u\n", u); } break; case 5: if (extra > 7) { u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff != u) pout("Specified load-unload count over device " "lifetime: %u\n", u); } break; case 6: if (extra > 7) { u = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff != u) pout("Accumulated load-unload cycles: %u\n", u); } break; default: /* ignore */ break; } } } static void scsiPrintGrownDefectListLen(scsi_device * device) { int err, dl_format, got_rd12, generation; unsigned int dl_len, div; memset(gBuf, 0, 8); if ((err = scsiReadDefect12(device, 0 /* req_plist */, 1 /* req_glist */, 4 /* format: bytes from index */, 0 /* addr desc index */, gBuf, 8))) { if (2 == err) { /* command not supported */ if ((err = scsiReadDefect10(device, 0 /* req_plist */, 1 /* req_glist */, 4 /* format: bytes from index */, gBuf, 4))) { if (scsi_debugmode > 0) { print_on(); pout("Read defect list (10) Failed: %s\n", scsiErrString(err)); print_off(); } return; } else got_rd12 = 0; } else { if (scsi_debugmode > 0) { print_on(); pout("Read defect list (12) Failed: %s\n", scsiErrString(err)); print_off(); } return; } } else got_rd12 = 1; if (got_rd12) { generation = (gBuf[2] << 8) + gBuf[3]; if ((generation > 1) && (scsi_debugmode > 0)) { print_on(); pout("Read defect list (12): generation=%d\n", generation); print_off(); } dl_len = (gBuf[4] << 24) + (gBuf[5] << 16) + (gBuf[6] << 8) + gBuf[7]; } else { dl_len = (gBuf[2] << 8) + gBuf[3]; } if (0x8 != (gBuf[1] & 0x18)) { print_on(); pout("Read defect list: asked for grown list but didn't get it\n"); print_off(); return; } div = 0; dl_format = (gBuf[1] & 0x7); switch (dl_format) { case 0: /* short block */ div = 4; break; case 1: /* extended bytes from index */ case 2: /* extended physical sector */ /* extended = 1; # might use in future */ div = 8; break; case 3: /* long block */ case 4: /* bytes from index */ case 5: /* physical sector */ div = 8; break; default: print_on(); pout("defect list format %d unknown\n", dl_format); print_off(); break; } if (0 == dl_len) pout("Elements in grown defect list: 0\n\n"); else { if (0 == div) pout("Grown defect list length=%u bytes [unknown " "number of elements]\n\n", dl_len); else pout("Elements in grown defect list: %u\n\n", dl_len / div); } } static void scsiPrintSeagateCacheLPage(scsi_device * device) { int k, j, num, pl, pc, err, len; unsigned char * ucp; unsigned char * xp; uint64_t ull; if ((err = scsiLogSense(device, SEAGATE_CACHE_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { print_on(); pout("Seagate Cache Log Sense Failed: %s\n", scsiErrString(err)); print_off(); return; } if ((gBuf[0] & 0x3f) != SEAGATE_CACHE_LPAGE) { print_on(); pout("Seagate Cache Log Sense Failed, page mismatch\n"); print_off(); return; } len = ((gBuf[2] << 8) | gBuf[3]) + 4; num = len - 4; ucp = &gBuf[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pl = ucp[3] + 4; switch (pc) { case 0: case 1: case 2: case 3: case 4: break; default: if (scsi_debugmode > 0) { print_on(); pout("Vendor (Seagate) cache lpage has unexpected parameter" ", skip\n"); print_off(); } return; } num -= pl; ucp += pl; } pout("Vendor (Seagate) cache information\n"); num = len - 4; ucp = &gBuf[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pl = ucp[3] + 4; switch (pc) { case 0: pout(" Blocks sent to initiator"); break; case 1: pout(" Blocks received from initiator"); break; case 2: pout(" Blocks read from cache and sent to initiator"); break; case 3: pout(" Number of read and write commands whose size " "<= segment size"); break; case 4: pout(" Number of read and write commands whose size " "> segment size"); break; default: pout(" Unknown Seagate parameter code [0x%x]", pc); break; } k = pl - 4; xp = ucp + 4; if (k > (int)sizeof(ull)) { xp += (k - (int)sizeof(ull)); k = (int)sizeof(ull); } ull = 0; for (j = 0; j < k; ++j) { if (j > 0) ull <<= 8; ull |= xp[j]; } pout(" = %"PRIu64"\n", ull); num -= pl; ucp += pl; } pout("\n"); } static void scsiPrintSeagateFactoryLPage(scsi_device * device) { int k, j, num, pl, pc, len, err, good, bad; unsigned char * ucp; unsigned char * xp; uint64_t ull; if ((err = scsiLogSense(device, SEAGATE_FACTORY_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { print_on(); pout("scsiPrintSeagateFactoryLPage Failed [%s]\n", scsiErrString(err)); print_off(); return; } if ((gBuf[0] & 0x3f) != SEAGATE_FACTORY_LPAGE) { print_on(); pout("Seagate/Hitachi Factory Log Sense Failed, page mismatch\n"); print_off(); return; } len = ((gBuf[2] << 8) | gBuf[3]) + 4; num = len - 4; ucp = &gBuf[0] + 4; good = 0; bad = 0; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pl = ucp[3] + 4; switch (pc) { case 0: case 8: ++good; break; default: ++bad; break; } num -= pl; ucp += pl; } if ((good < 2) || (bad > 4)) { /* heuristic */ if (scsi_debugmode > 0) { print_on(); pout("\nVendor (Seagate/Hitachi) factory lpage has too many " "unexpected parameters, skip\n"); print_off(); } return; } pout("Vendor (Seagate/Hitachi) factory information\n"); num = len - 4; ucp = &gBuf[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pl = ucp[3] + 4; good = 0; switch (pc) { case 0: pout(" number of hours powered up"); good = 1; break; case 8: pout(" number of minutes until next internal SMART test"); good = 1; break; default: if (scsi_debugmode > 0) { print_on(); pout("Vendor (Seagate/Hitachi) factory lpage: " "unknown parameter code [0x%x]\n", pc); print_off(); } break; } if (good) { k = pl - 4; xp = ucp + 4; if (k > (int)sizeof(ull)) { xp += (k - (int)sizeof(ull)); k = (int)sizeof(ull); } ull = 0; for (j = 0; j < k; ++j) { if (j > 0) ull <<= 8; ull |= xp[j]; } if (0 == pc) pout(" = %.2f\n", ull / 60.0 ); else pout(" = %"PRIu64"\n", ull); } num -= pl; ucp += pl; } pout("\n"); } static void scsiPrintErrorCounterLog(scsi_device * device) { struct scsiErrorCounter errCounterArr[3]; struct scsiErrorCounter * ecp; struct scsiNonMediumError nme; int found[3] = {0, 0, 0}; const char * pageNames[3] = {"read: ", "write: ", "verify: "}; double processed_gb; if (gReadECounterLPage && (0 == scsiLogSense(device, READ_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { scsiDecodeErrCounterPage(gBuf, &errCounterArr[0]); found[0] = 1; } if (gWriteECounterLPage && (0 == scsiLogSense(device, WRITE_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { scsiDecodeErrCounterPage(gBuf, &errCounterArr[1]); found[1] = 1; } if (gVerifyECounterLPage && (0 == scsiLogSense(device, VERIFY_ERROR_COUNTER_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { scsiDecodeErrCounterPage(gBuf, &errCounterArr[2]); ecp = &errCounterArr[2]; for (int k = 0; k < 7; ++k) { if (ecp->gotPC[k] && ecp->counter[k]) { found[2] = 1; break; } } } if (found[0] || found[1] || found[2]) { pout("Error counter log:\n"); pout(" Errors Corrected by Total " "Correction Gigabytes Total\n"); pout(" ECC rereads/ errors " "algorithm processed uncorrected\n"); pout(" fast | delayed rewrites corrected " "invocations [10^9 bytes] errors\n"); for (int k = 0; k < 3; ++k) { if (! found[k]) continue; ecp = &errCounterArr[k]; pout("%s%8"PRIu64" %8"PRIu64" %8"PRIu64" %8"PRIu64" %8"PRIu64, pageNames[k], ecp->counter[0], ecp->counter[1], ecp->counter[2], ecp->counter[3], ecp->counter[4]); processed_gb = ecp->counter[5] / 1000000000.0; pout(" %12.3f %8"PRIu64"\n", processed_gb, ecp->counter[6]); } } else pout("Error Counter logging not supported\n"); if (gNonMediumELPage && (0 == scsiLogSense(device, NON_MEDIUM_ERROR_LPAGE, 0, gBuf, LOG_RESP_LEN, 0))) { scsiDecodeNonMediumErrPage(gBuf, &nme); if (nme.gotPC0) pout("\nNon-medium error count: %8"PRIu64"\n", nme.counterPC0); if (nme.gotTFE_H) pout("Track following error count [Hitachi]: %8"PRIu64"\n", nme.counterTFE_H); if (nme.gotPE_H) pout("Positioning error count [Hitachi]: %8"PRIu64"\n", nme.counterPE_H); } if (gLastNErrorLPage && (0 == scsiLogSense(device, LAST_N_ERROR_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) { int num = (gBuf[2] << 8) + gBuf[3] + 4; int truncated = (num > LOG_RESP_LONG_LEN) ? num : 0; if (truncated) num = LOG_RESP_LONG_LEN; unsigned char * ucp = gBuf + 4; num -= 4; if (num < 4) pout("\nNo error events logged\n"); else { pout("\nLast n error events log page\n"); for (int k = num, pl; k > 0; k -= pl, ucp += pl) { if (k < 3) { pout(" <<short Last n error events log page>>\n"); break; } pl = ucp[3] + 4; int pc = (ucp[0] << 8) + ucp[1]; if (pl > 4) { if ((ucp[2] & 0x1) && (ucp[2] & 0x2)) { pout(" Error event %d:\n", pc); pout(" [binary]:\n"); dStrHex((const char *)ucp + 4, pl - 4, 1); } else if (ucp[2] & 0x1) { pout(" Error event %d:\n", pc); pout(" %.*s\n", pl - 4, (const char *)(ucp + 4)); } else { if (scsi_debugmode > 0) { pout(" Error event %d:\n", pc); pout(" [data counter??]:\n"); dStrHex((const char *)ucp + 4, pl - 4, 1); } } } } if (truncated) pout(" >>>> log truncated, fetched %d of %d available " "bytes\n", LOG_RESP_LONG_LEN, truncated); } } pout("\n"); } static const char * self_test_code[] = { "Default ", "Background short", "Background long ", "Reserved(3) ", "Abort background", "Foreground short", "Foreground long ", "Reserved(7) " }; static const char * self_test_result[] = { "Completed ", "Aborted (by user command)", "Aborted (device reset ?) ", "Unknown error, incomplete", "Completed, segment failed", "Failed in first segment ", "Failed in second segment ", "Failed in segment --> ", "Reserved(8) ", "Reserved(9) ", "Reserved(10) ", "Reserved(11) ", "Reserved(12) ", "Reserved(13) ", "Reserved(14) ", "Self test in progress ..." }; // See SCSI Primary Commands - 3 (SPC-3) rev 23 (draft) section 7.2.10 . // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or // FAILSMART is returned. static int scsiPrintSelfTest(scsi_device * device) { int num, k, n, res, err, durationSec; int noheader = 1; int retval = 0; UINT8 * ucp; uint64_t ull=0; struct scsi_sense_disect sense_info; // check if test is running if (!scsiRequestSense(device, &sense_info) && (sense_info.asc == 0x04 && sense_info.ascq == 0x09 && sense_info.progress != -1)) { pout("Self-test execution status:\t\t%d%% of test remaining\n", 100 - ((sense_info.progress * 100) / 65535)); } if ((err = scsiLogSense(device, SELFTEST_RESULTS_LPAGE, 0, gBuf, LOG_RESP_SELF_TEST_LEN, 0))) { print_on(); pout("scsiPrintSelfTest Failed [%s]\n", scsiErrString(err)); print_off(); return FAILSMART; } if ((gBuf[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) { print_on(); pout("Self-test Log Sense Failed, page mismatch\n"); print_off(); return FAILSMART; } // compute page length num = (gBuf[2] << 8) + gBuf[3]; // Log sense page length 0x190 bytes if (num != 0x190) { print_on(); pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n",num); print_off(); return FAILSMART; } // loop through the twenty possible entries for (k = 0, ucp = gBuf + 4; k < 20; ++k, ucp += 20 ) { int i; // timestamp in power-on hours (or zero if test in progress) n = (ucp[6] << 8) | ucp[7]; // The spec says "all 20 bytes will be zero if no test" but // DG has found otherwise. So this is a heuristic. if ((0 == n) && (0 == ucp[4])) break; // only print header if needed if (noheader) { pout("SMART Self-test log\n"); pout("Num Test Status segment " "LifeTime LBA_first_err [SK ASC ASQ]\n"); pout(" Description number " "(hours)\n"); noheader=0; } // print parameter code (test number) & self-test code text pout("#%2d %s", (ucp[0] << 8) | ucp[1], self_test_code[(ucp[4] >> 5) & 0x7]); // check the self-test result nibble, using the self-test results // field table from T10/1416-D (SPC-3) Rev. 23, section 7.2.10: switch ((res = ucp[4] & 0xf)) { case 0x3: // an unknown error occurred while the device server // was processing the self-test and the device server // was unable to complete the self-test retval|=FAILSMART; break; case 0x4: // the self-test completed with a failure in a test // segment, and the test segment that failed is not // known retval|=FAILLOG; break; case 0x5: // the first segment of the self-test failed retval|=FAILLOG; break; case 0x6: // the second segment of the self-test failed retval|=FAILLOG; break; case 0x7: // another segment of the self-test failed and which // test is indicated by the contents of the SELF-TEST // NUMBER field retval|=FAILLOG; break; default: break; } pout(" %s", self_test_result[res]); // self-test number identifies test that failed and consists // of either the number of the segment that failed during // the test, or the number of the test that failed and the // number of the segment in which the test was run, using a // vendor-specific method of putting both numbers into a // single byte. if (ucp[5]) pout(" %3d", (int)ucp[5]); else pout(" -"); // print time that the self-test was completed if (n==0 && res==0xf) // self-test in progress pout(" NOW"); else pout(" %5d", n); // construct 8-byte integer address of first failure for (i = 0; i < 8; i++) { ull <<= 8; ull |= ucp[i+8]; } // print Address of First Failure, if sensible if ((~(uint64_t)0 != ull) && (res > 0) && (res < 0xf)) { char buff[32]; // was hex but change to decimal to conform with ATA snprintf(buff, sizeof(buff), "%"PRIu64, ull); // snprintf(buff, sizeof(buff), "0x%"PRIx64, ull); pout("%18s", buff); } else pout(" -"); // if sense key nonzero, then print it, along with // additional sense code and additional sense code qualifier if (ucp[16] & 0xf) pout(" [0x%x 0x%x 0x%x]\n", ucp[16] & 0xf, ucp[17], ucp[18]); else pout(" [- - -]\n"); } // if header never printed, then there was no output if (noheader) pout("No self-tests have been logged\n"); else if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec, modese_len)) && (durationSec > 0)) { pout("Long (extended) Self Test duration: %d seconds " "[%.1f minutes]\n", durationSec, durationSec / 60.0); } pout("\n"); return retval; } static const char * bms_status[] = { "no scans active", "scan is active", "pre-scan is active", "halted due to fatal error", "halted due to a vendor specific pattern of error", "halted due to medium formatted without P-List", "halted - vendor specific cause", "halted due to temperature out of range", "waiting until BMS interval timer expires", /* 8 */ }; static const char * reassign_status[] = { "Reserved [0x0]", "Require Write or Reassign Blocks command", "Successfully reassigned", "Reserved [0x3]", "Reassignment by disk failed", "Recovered via rewrite in-place", "Reassigned by app, has valid data", "Reassigned by app, has no valid data", "Unsuccessfully reassigned by app", /* 8 */ }; // See SCSI Block Commands - 3 (SBC-3) rev 6 (draft) section 6.2.2 . // Returns 0 if ok else FAIL* bitmask. Note can have a status entry // and up to 2048 events (although would hope to have less). May set // FAILLOG if serious errors detected (in the future). static int scsiPrintBackgroundResults(scsi_device * device) { int num, j, m, err, pc, pl, truncated; int noheader = 1; int firstresult = 1; int retval = 0; UINT8 * ucp; if ((err = scsiLogSense(device, BACKGROUND_RESULTS_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) { print_on(); pout("scsiPrintBackgroundResults Failed [%s]\n", scsiErrString(err)); print_off(); return FAILSMART; } if ((gBuf[0] & 0x3f) != BACKGROUND_RESULTS_LPAGE) { print_on(); pout("Background scan results Log Sense Failed, page mismatch\n"); print_off(); return FAILSMART; } // compute page length num = (gBuf[2] << 8) + gBuf[3] + 4; if (num < 20) { print_on(); pout("Background scan results Log Sense length is %d, no scan " "status\n", num); print_off(); return FAILSMART; } truncated = (num > LOG_RESP_LONG_LEN) ? num : 0; if (truncated) num = LOG_RESP_LONG_LEN; ucp = gBuf + 4; num -= 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; // pcb = ucp[2]; pl = ucp[3] + 4; switch (pc) { case 0: if (noheader) { noheader = 0; pout("Background scan results log\n"); } pout(" Status: "); if ((pl < 16) || (num < 16)) { pout("\n"); break; } j = ucp[9]; if (j < (int)(sizeof(bms_status) / sizeof(bms_status[0]))) pout("%s\n", bms_status[j]); else pout("unknown [0x%x] background scan status value\n", j); j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; pout(" Accumulated power on time, hours:minutes %d:%02d " "[%d minutes]\n", (j / 60), (j % 60), j); pout(" Number of background scans performed: %d, ", (ucp[10] << 8) + ucp[11]); pout("scan progress: %.2f%%\n", (double)((ucp[12] << 8) + ucp[13]) * 100.0 / 65536.0); pout(" Number of background medium scans performed: %d\n", (ucp[14] << 8) + ucp[15]); break; default: if (noheader) { noheader = 0; pout("\nBackground scan results log\n"); } if (firstresult) { firstresult = 0; pout("\n # when lba(hex) [sk,asc,ascq] " "reassign_status\n"); } pout(" %3d ", pc); if ((pl < 24) || (num < 24)) { if (pl < 24) pout("parameter length >= 24 expected, got %d\n", pl); break; } j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; pout("%4d:%02d ", (j / 60), (j % 60)); for (m = 0; m < 8; ++m) pout("%02x", ucp[16 + m]); pout(" [%x,%x,%x] ", ucp[8] & 0xf, ucp[9], ucp[10]); j = (ucp[8] >> 4) & 0xf; if (j < (int)(sizeof(reassign_status) / sizeof(reassign_status[0]))) pout("%s\n", reassign_status[j]); else pout("Reassign status: reserved [0x%x]\n", j); break; } num -= pl; ucp += pl; } if (truncated) pout(" >>>> log truncated, fetched %d of %d available " "bytes\n", LOG_RESP_LONG_LEN, truncated); pout("\n"); return retval; } // See SCSI Block Commands - 3 (SBC-3) rev 27 (draft) section 6.3.6 . // Returns 0 if ok else FAIL* bitmask. Note can have a status entry // and up to 2048 events (although would hope to have less). May set // FAILLOG if serious errors detected (in the future). static int scsiPrintSSMedia(scsi_device * device) { int num, err, pc, pl, truncated; int retval = 0; UINT8 * ucp; if ((err = scsiLogSense(device, SS_MEDIA_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) { print_on(); pout("scsiPrintSSMedia Failed [%s]\n", scsiErrString(err)); print_off(); return FAILSMART; } if ((gBuf[0] & 0x3f) != SS_MEDIA_LPAGE) { print_on(); pout("Solid state media Log Sense Failed, page mismatch\n"); print_off(); return FAILSMART; } // compute page length num = (gBuf[2] << 8) + gBuf[3] + 4; if (num < 12) { print_on(); pout("Solid state media Log Sense length is %d, too short\n", num); print_off(); return FAILSMART; } truncated = (num > LOG_RESP_LONG_LEN) ? num : 0; if (truncated) num = LOG_RESP_LONG_LEN; ucp = gBuf + 4; num -= 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; // pcb = ucp[2]; pl = ucp[3] + 4; switch (pc) { case 1: if (pl < 8) { print_on(); pout("Percentage used endurance indicator too short (pl=%d)\n", pl); print_off(); return FAILSMART; } pout("SS Media used endurance indicator: %d%%\n", ucp[7]); default: /* ignore other parameter codes */ break; } num -= pl; ucp += pl; } return retval; } static void show_sas_phy_event_info(int peis, unsigned int val, unsigned thresh_val) { unsigned int u; switch (peis) { case 0: pout(" No event\n"); break; case 0x1: pout(" Invalid word count: %u\n", val); break; case 0x2: pout(" Running disparity error count: %u\n", val); break; case 0x3: pout(" Loss of dword synchronization count: %u\n", val); break; case 0x4: pout(" Phy reset problem count: %u\n", val); break; case 0x5: pout(" Elasticity buffer overflow count: %u\n", val); break; case 0x6: pout(" Received ERROR count: %u\n", val); break; case 0x20: pout(" Received address frame error count: %u\n", val); break; case 0x21: pout(" Transmitted abandon-class OPEN_REJECT count: %u\n", val); break; case 0x22: pout(" Received abandon-class OPEN_REJECT count: %u\n", val); break; case 0x23: pout(" Transmitted retry-class OPEN_REJECT count: %u\n", val); break; case 0x24: pout(" Received retry-class OPEN_REJECT count: %u\n", val); break; case 0x25: pout(" Received AIP (WATING ON PARTIAL) count: %u\n", val); break; case 0x26: pout(" Received AIP (WAITING ON CONNECTION) count: %u\n", val); break; case 0x27: pout(" Transmitted BREAK count: %u\n", val); break; case 0x28: pout(" Received BREAK count: %u\n", val); break; case 0x29: pout(" Break timeout count: %u\n", val); break; case 0x2a: pout(" Connection count: %u\n", val); break; case 0x2b: pout(" Peak transmitted pathway blocked count: %u\n", val & 0xff); pout(" Peak value detector threshold: %u\n", thresh_val & 0xff); break; case 0x2c: u = val & 0xffff; if (u < 0x8000) pout(" Peak transmitted arbitration wait time (us): " "%u\n", u); else pout(" Peak transmitted arbitration wait time (ms): " "%u\n", 33 + (u - 0x8000)); u = thresh_val & 0xffff; if (u < 0x8000) pout(" Peak value detector threshold (us): %u\n", u); else pout(" Peak value detector threshold (ms): %u\n", 33 + (u - 0x8000)); break; case 0x2d: pout(" Peak arbitration time (us): %u\n", val); pout(" Peak value detector threshold: %u\n", thresh_val); break; case 0x2e: pout(" Peak connection time (us): %u\n", val); pout(" Peak value detector threshold: %u\n", thresh_val); break; case 0x40: pout(" Transmitted SSP frame count: %u\n", val); break; case 0x41: pout(" Received SSP frame count: %u\n", val); break; case 0x42: pout(" Transmitted SSP frame error count: %u\n", val); break; case 0x43: pout(" Received SSP frame error count: %u\n", val); break; case 0x44: pout(" Transmitted CREDIT_BLOCKED count: %u\n", val); break; case 0x45: pout(" Received CREDIT_BLOCKED count: %u\n", val); break; case 0x50: pout(" Transmitted SATA frame count: %u\n", val); break; case 0x51: pout(" Received SATA frame count: %u\n", val); break; case 0x52: pout(" SATA flow control buffer overflow count: %u\n", val); break; case 0x60: pout(" Transmitted SMP frame count: %u\n", val); break; case 0x61: pout(" Received SMP frame count: %u\n", val); break; case 0x63: pout(" Received SMP frame error count: %u\n", val); break; default: break; } } static void show_sas_port_param(unsigned char * ucp, int param_len) { int j, m, n, nphys, t, sz, spld_len; unsigned char * vcp; uint64_t ull; unsigned int ui; char s[64]; sz = sizeof(s); // pcb = ucp[2]; t = (ucp[0] << 8) | ucp[1]; pout("relative target port id = %d\n", t); pout(" generation code = %d\n", ucp[6]); nphys = ucp[7]; pout(" number of phys = %d\n", nphys); for (j = 0, vcp = ucp + 8; j < (param_len - 8); vcp += spld_len, j += spld_len) { pout(" phy identifier = %d\n", vcp[1]); spld_len = vcp[3]; if (spld_len < 44) spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */ else spld_len += 4; t = ((0x70 & vcp[4]) >> 4); switch (t) { case 0: snprintf(s, sz, "no device attached"); break; case 1: snprintf(s, sz, "end device"); break; case 2: snprintf(s, sz, "expander device"); break; case 3: snprintf(s, sz, "expander device (fanout)"); break; default: snprintf(s, sz, "reserved [%d]", t); break; } pout(" attached device type: %s\n", s); t = 0xf & vcp[4]; switch (t) { case 0: snprintf(s, sz, "unknown"); break; case 1: snprintf(s, sz, "power on"); break; case 2: snprintf(s, sz, "hard reset"); break; case 3: snprintf(s, sz, "SMP phy control function"); break; case 4: snprintf(s, sz, "loss of dword synchronization"); break; case 5: snprintf(s, sz, "mux mix up"); break; case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA"); break; case 7: snprintf(s, sz, "break timeout timer expired"); break; case 8: snprintf(s, sz, "phy test function stopped"); break; case 9: snprintf(s, sz, "expander device reduced functionality"); break; default: snprintf(s, sz, "reserved [0x%x]", t); break; } pout(" attached reason: %s\n", s); t = (vcp[5] & 0xf0) >> 4; switch (t) { case 0: snprintf(s, sz, "unknown"); break; case 1: snprintf(s, sz, "power on"); break; case 2: snprintf(s, sz, "hard reset"); break; case 3: snprintf(s, sz, "SMP phy control function"); break; case 4: snprintf(s, sz, "loss of dword synchronization"); break; case 5: snprintf(s, sz, "mux mix up"); break; case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA"); break; case 7: snprintf(s, sz, "break timeout timer expired"); break; case 8: snprintf(s, sz, "phy test function stopped"); break; case 9: snprintf(s, sz, "expander device reduced functionality"); break; default: snprintf(s, sz, "reserved [0x%x]", t); break; } pout(" reason: %s\n", s); t = (0xf & vcp[5]); switch (t) { case 0: snprintf(s, sz, "phy enabled; unknown"); break; case 1: snprintf(s, sz, "phy disabled"); break; case 2: snprintf(s, sz, "phy enabled; speed negotiation failed"); break; case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state"); break; case 4: snprintf(s, sz, "phy enabled; port selector"); break; case 5: snprintf(s, sz, "phy enabled; reset in progress"); break; case 6: snprintf(s, sz, "phy enabled; unsupported phy attached"); break; case 8: snprintf(s, sz, "phy enabled; 1.5 Gbps"); break; case 9: snprintf(s, sz, "phy enabled; 3 Gbps"); break; case 0xa: snprintf(s, sz, "phy enabled; 6 Gbps"); break; default: snprintf(s, sz, "reserved [%d]", t); break; } pout(" negotiated logical link rate: %s\n", s); pout(" attached initiator port: ssp=%d stp=%d smp=%d\n", !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2)); pout(" attached target port: ssp=%d stp=%d smp=%d\n", !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2)); for (n = 0, ull = vcp[8]; n < 8; ++n) { ull <<= 8; ull |= vcp[8 + n]; } pout(" SAS address = 0x%" PRIx64 "\n", ull); for (n = 0, ull = vcp[16]; n < 8; ++n) { ull <<= 8; ull |= vcp[16 + n]; } pout(" attached SAS address = 0x%" PRIx64 "\n", ull); pout(" attached phy identifier = %d\n", vcp[24]); ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; pout(" Invalid DWORD count = %u\n", ui); ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39]; pout(" Running disparity error count = %u\n", ui); ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43]; pout(" Loss of DWORD synchronization = %u\n", ui); ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; pout(" Phy reset problem = %u\n", ui); if (spld_len > 51) { int num_ped, peis; unsigned char * xcp; unsigned int pvdt; num_ped = vcp[51]; if (num_ped > 0) pout(" Phy event descriptors:\n"); xcp = vcp + 52; for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { peis = xcp[3]; ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) | xcp[7]; pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) | xcp[11]; show_sas_phy_event_info(peis, ui, pvdt); } } } } // Returns 1 if okay, 0 if non SAS descriptors static int show_protocol_specific_page(unsigned char * resp, int len) { int k, num, param_len; unsigned char * ucp; num = len - 4; for (k = 0, ucp = resp + 4; k < num; ) { param_len = ucp[3] + 4; if (6 != (0xf & ucp[4])) return 0; /* only decode SAS log page */ if (0 == k) pout("Protocol Specific port log page for SAS SSP\n"); show_sas_port_param(ucp, param_len); k += param_len; ucp += param_len; } pout("\n"); return 1; } // See Serial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol Specific // log pageSerial Attached SCSI (SAS-2) (e.g. revision 16) the Protocol // Specific log page. // Returns 0 if ok else FAIL* bitmask. Note that if any of the most recent // 20 self tests fail (result code 3 to 7 inclusive) then FAILLOG and/or // FAILSMART is returned. static int scsiPrintSasPhy(scsi_device * device, int reset) { int num, err; if ((err = scsiLogSense(device, PROTOCOL_SPECIFIC_LPAGE, 0, gBuf, LOG_RESP_LONG_LEN, 0))) { print_on(); pout("scsiPrintSasPhy Log Sense Failed [%s]\n\n", scsiErrString(err)); print_off(); return FAILSMART; } if ((gBuf[0] & 0x3f) != PROTOCOL_SPECIFIC_LPAGE) { print_on(); pout("Protocol specific Log Sense Failed, page mismatch\n\n"); print_off(); return FAILSMART; } // compute page length num = (gBuf[2] << 8) + gBuf[3]; if (1 != show_protocol_specific_page(gBuf, num + 4)) { print_on(); pout("Only support protocol specific log page on SAS devices\n\n"); print_off(); return FAILSMART; } if (reset) { if ((err = scsiLogSelect(device, 1 /* pcr */, 0 /* sp */, 0 /* pc */, PROTOCOL_SPECIFIC_LPAGE, 0, NULL, 0))) { print_on(); pout("scsiPrintSasPhy Log Select (reset) Failed [%s]\n\n", scsiErrString(err)); print_off(); return FAILSMART; } } return 0; } static const char * peripheral_dt_arr[] = { "disk", "tape", "printer", "processor", "optical disk(4)", "CD/DVD", "scanner", "optical disk(7)", "medium changer", "communications", "graphics(10)", "graphics(11)", "storage array", "enclosure", "simplified disk", "optical card reader" }; static const char * transport_proto_arr[] = { "Fibre channel (FCP-2)", "Parallel SCSI (SPI-4)", "SSA", "IEEE 1394 (SBP-2)", "RDMA (SRP)", "iSCSI", "SAS", "ADT", "0x8", "0x9", "0xa", "0xb", "0xc", "0xd", "0xe", "0xf" }; /* Returns 0 on success, 1 on general error and 2 for early, clean exit */ static int scsiGetDriveInfo(scsi_device * device, UINT8 * peripheral_type, bool all) { char timedatetz[DATEANDEPOCHLEN]; struct scsi_iec_mode_page iec; int err, iec_err, len, req_len, avail_len, n; int is_tape = 0; int peri_dt = 0; int returnval = 0; int transport = -1; int form_factor = 0; int protect = 0; memset(gBuf, 0, 96); req_len = 36; if ((err = scsiStdInquiry(device, gBuf, req_len))) { print_on(); pout("Standard Inquiry (36 bytes) failed [%s]\n", scsiErrString(err)); pout("Retrying with a 64 byte Standard Inquiry\n"); print_off(); /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */ req_len = 64; if ((err = scsiStdInquiry(device, gBuf, req_len))) { print_on(); pout("Standard Inquiry (64 bytes) failed [%s]\n", scsiErrString(err)); print_off(); return 1; } } avail_len = gBuf[4] + 5; len = (avail_len < req_len) ? avail_len : req_len; peri_dt = gBuf[0] & 0x1f; if (peripheral_type) *peripheral_type = peri_dt; if (len < 36) { print_on(); pout("Short INQUIRY response, skip product id\n"); print_off(); return 1; } if (all && (0 != strncmp((char *)&gBuf[8], "ATA", 3))) { char vendor[8+1], product[16+1], revision[4+1]; scsi_format_id_string(vendor, (const unsigned char *)&gBuf[8], 8); scsi_format_id_string(product, (const unsigned char *)&gBuf[16], 16); scsi_format_id_string(revision, (const unsigned char *)&gBuf[32], 4); pout("=== START OF INFORMATION SECTION ===\n"); pout("Vendor: %.8s\n", vendor); pout("Product: %.16s\n", product); if (gBuf[32] >= ' ') pout("Revision: %.4s\n", revision); } if (!*device->get_req_type()/*no type requested*/ && (0 == strncmp((char *)&gBuf[8], "ATA", 3))) { pout("\nProbable ATA device behind a SAT layer\n" "Try an additional '-d ata' or '-d sat' argument.\n"); return 2; } if (! all) return 0; protect = gBuf[5] & 0x1; /* from and including SPC-3 */ if (! is_tape) { /* only do this for disks */ unsigned int lb_size = 0; unsigned char lb_prov_resp[8]; char cap_str[64]; char si_str[64]; char lb_str[16]; int lb_per_pb_exp = 0; uint64_t capacity = scsiGetSize(device, &lb_size, &lb_per_pb_exp); if (capacity) { format_with_thousands_sep(cap_str, sizeof(cap_str), capacity); format_capacity(si_str, sizeof(si_str), capacity); pout("User Capacity: %s bytes [%s]\n", cap_str, si_str); snprintf(lb_str, sizeof(lb_str) - 1, "%u", lb_size); pout("Logical block size: %s bytes\n", lb_str); } int lbpme = -1; int lbprz = -1; if (protect || lb_per_pb_exp) { unsigned char rc16_12[20] = {0, }; if (0 == scsiGetProtPBInfo(device, rc16_12)) { lb_per_pb_exp = rc16_12[1] & 0xf; /* just in case */ if (lb_per_pb_exp > 0) { snprintf(lb_str, sizeof(lb_str) - 1, "%u", (lb_size * (1 << lb_per_pb_exp))); pout("Physical block size: %s bytes\n", lb_str); n = ((rc16_12[2] & 0x3f) << 8) + rc16_12[3]; pout("Lowest aligned LBA: %d\n", n); } if (rc16_12[0] & 0x1) { /* PROT_EN set */ int p_type = ((rc16_12[0] >> 1) & 0x7); switch (p_type) { case 0 : pout("Formatted with type 1 protection\n"); break; case 1 : pout("Formatted with type 2 protection\n"); break; case 2 : pout("Formatted with type 3 protection\n"); break; default: pout("Formatted with unknown protection type [%d]\n", p_type); break; } int p_i_exp = ((rc16_12[1] >> 4) & 0xf); if (p_i_exp > 0) pout("%d protection information intervals per " "logical block\n", (1 << p_i_exp)); } /* Pick up some LB provisioning info since its available */ lbpme = !! (rc16_12[2] & 0x80); lbprz = !! (rc16_12[2] & 0x40); } } if (0 == scsiInquiryVpd(device, SCSI_VPD_LOGICAL_BLOCK_PROVISIONING, lb_prov_resp, sizeof(lb_prov_resp))) { int prov_type = lb_prov_resp[6] & 0x7; if (-1 == lbprz) lbprz = !! (lb_prov_resp[5] & 0x4); switch (prov_type) { case 0: pout("Logical block provisioning type unreported, " "LBPME=%d, LBPRZ=%d\n", lbpme, lbprz); break; case 1: pout("LU is resource provisioned, LBPRZ=%d\n", lbprz); break; case 2: pout("LU is thin provisioned, LBPRZ=%d\n", lbprz); break; default: pout("LU provisioning type reserved [%d], LBPRZ=%d\n", prov_type, lbprz); break; } } else if (1 == lbpme) pout("Logical block provisioning enabled, LBPRZ=%d\n", lbprz); int rpm = scsiGetRPM(device, modese_len, &form_factor); if (rpm > 0) { if (1 == rpm) pout("Rotation Rate: Solid State Device\n"); else pout("Rotation Rate: %d rpm\n", rpm); } if (form_factor > 0) { const char * cp = NULL; switch (form_factor) { case 1: cp = "5.25"; break; case 2: cp = "3.5"; break; case 3: cp = "2.5"; break; case 4: cp = "1.8"; break; case 5: cp = "< 1.8"; break; } if (cp) pout("Form Factor: %s inches\n", cp); } } /* Do this here to try and detect badly conforming devices (some USB keys) that will lock up on a InquiryVpd or log sense or ... */ if ((iec_err = scsiFetchIECmpage(device, &iec, modese_len))) { if (SIMPLE_ERR_BAD_RESP == iec_err) { pout(">> Terminate command early due to bad response to IEC " "mode page\n"); print_off(); gIecMPage = 0; return 1; } } else modese_len = iec.modese_len; if (! dont_print_serial_number) { if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_DEVICE_IDENTIFICATION, gBuf, 252))) { char s[256]; len = gBuf[3]; scsi_decode_lu_dev_id(gBuf + 4, len, s, sizeof(s), &transport); if (strlen(s) > 0) pout("Logical Unit id: %s\n", s); } else if (scsi_debugmode > 0) { print_on(); if (SIMPLE_ERR_BAD_RESP == err) pout("Vital Product Data (VPD) bit ignored in INQUIRY\n"); else pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err); print_off(); } if (0 == (err = scsiInquiryVpd(device, SCSI_VPD_UNIT_SERIAL_NUMBER, gBuf, 252))) { char serial[256]; len = gBuf[3]; gBuf[4 + len] = '\0'; scsi_format_id_string(serial, &gBuf[4], len); pout("Serial number: %s\n", serial); } else if (scsi_debugmode > 0) { print_on(); if (SIMPLE_ERR_BAD_RESP == err) pout("Vital Product Data (VPD) bit ignored in INQUIRY\n"); else pout("Vital Product Data (VPD) INQUIRY failed [%d]\n", err); print_off(); } } // print SCSI peripheral device type if (peri_dt < (int)(sizeof(peripheral_dt_arr) / sizeof(peripheral_dt_arr[0]))) pout("Device type: %s\n", peripheral_dt_arr[peri_dt]); else pout("Device type: <%d>\n", peri_dt); // See if transport protocol is known if (transport < 0) transport = scsiFetchTransportProtocol(device, modese_len); if ((transport >= 0) && (transport <= 0xf)) pout("Transport protocol: %s\n", transport_proto_arr[transport]); // print current time and date and timezone dateandtimezone(timedatetz); pout("Local Time is: %s\n", timedatetz); if ((SCSI_PT_SEQUENTIAL_ACCESS == *peripheral_type) || (SCSI_PT_MEDIUM_CHANGER == *peripheral_type)) is_tape = 1; // See if unit accepts SCSI commmands from us if ((err = scsiTestUnitReady(device))) { if (SIMPLE_ERR_NOT_READY == err) { print_on(); if (!is_tape) pout("device is NOT READY (e.g. spun down, busy)\n"); else pout("device is NOT READY (e.g. no tape)\n"); print_off(); } else if (SIMPLE_ERR_NO_MEDIUM == err) { print_on(); pout("NO MEDIUM present on device\n"); print_off(); } else if (SIMPLE_ERR_BECOMING_READY == err) { print_on(); pout("device becoming ready (wait)\n"); print_off(); } else { print_on(); pout("device Test Unit Ready [%s]\n", scsiErrString(err)); print_off(); } failuretest(MANDATORY_CMD, returnval|=FAILID); } if (iec_err) { if (!is_tape) { print_on(); pout("SMART support is: Unavailable - device lacks SMART capability.\n"); if (scsi_debugmode > 0) pout(" [%s]\n", scsiErrString(iec_err)); print_off(); } gIecMPage = 0; return 0; } if (!is_tape) pout("SMART support is: Available - device has SMART capability.\n" "SMART support is: %s\n", (scsi_IsExceptionControlEnabled(&iec)) ? "Enabled" : "Disabled"); pout("%s\n", (scsi_IsWarningEnabled(&iec)) ? "Temperature Warning: Enabled" : "Temperature Warning: Disabled or Not Supported"); return 0; } static int scsiSmartEnable(scsi_device * device) { struct scsi_iec_mode_page iec; int err; if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { print_on(); pout("unable to fetch IEC (SMART) mode page [%s]\n", scsiErrString(err)); print_off(); return 1; } else modese_len = iec.modese_len; if ((err = scsiSetExceptionControlAndWarning(device, 1, &iec))) { print_on(); pout("unable to enable Exception control and warning [%s]\n", scsiErrString(err)); print_off(); return 1; } /* Need to refetch 'iec' since could be modified by previous call */ if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { pout("unable to fetch IEC (SMART) mode page [%s]\n", scsiErrString(err)); return 1; } else modese_len = iec.modese_len; pout("Informational Exceptions (SMART) %s\n", scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled"); pout("Temperature warning %s\n", scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled"); return 0; } static int scsiSmartDisable(scsi_device * device) { struct scsi_iec_mode_page iec; int err; if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { print_on(); pout("unable to fetch IEC (SMART) mode page [%s]\n", scsiErrString(err)); print_off(); return 1; } else modese_len = iec.modese_len; if ((err = scsiSetExceptionControlAndWarning(device, 0, &iec))) { print_on(); pout("unable to disable Exception control and warning [%s]\n", scsiErrString(err)); print_off(); return 1; } /* Need to refetch 'iec' since could be modified by previous call */ if ((err = scsiFetchIECmpage(device, &iec, modese_len))) { pout("unable to fetch IEC (SMART) mode page [%s]\n", scsiErrString(err)); return 1; } else modese_len = iec.modese_len; pout("Informational Exceptions (SMART) %s\n", scsi_IsExceptionControlEnabled(&iec) ? "enabled" : "disabled"); pout("Temperature warning %s\n", scsi_IsWarningEnabled(&iec) ? "enabled" : "disabled"); return 0; } static void scsiPrintTemp(scsi_device * device) { UINT8 temp = 0; UINT8 trip = 0; if (scsiGetTemp(device, &temp, &trip)) return; if (temp) { if (255 != temp) pout("Current Drive Temperature: %d C\n", temp); else pout("Current Drive Temperature: <not available>\n"); } if (trip) pout("Drive Trip Temperature: %d C\n", trip); if (temp || trip) pout("\n"); } /* Main entry point used by smartctl command. Return 0 for success */ int scsiPrintMain(scsi_device * device, const scsi_print_options & options) { int checkedSupportedLogPages = 0; UINT8 peripheral_type = 0; int returnval = 0; int res, durationSec; struct scsi_sense_disect sense_info; bool any_output = options.drive_info; if (supported_vpd_pages_p) { delete supported_vpd_pages_p; supported_vpd_pages_p = NULL; } supported_vpd_pages_p = new supported_vpd_pages(device); res = scsiGetDriveInfo(device, &peripheral_type, options.drive_info); if (res) { if (2 == res) return 0; else failuretest(MANDATORY_CMD, returnval |= FAILID); any_output = true; } // Print read look-ahead status for disks short int wce = -1, rcd = -1; if (options.get_rcd || options.get_wce) { if (SCSI_PT_DIRECT_ACCESS == peripheral_type) res = scsiGetSetCache(device, modese_len, &wce, &rcd); else res = -1; // fetch for disks only any_output = true; } if (options.get_rcd) { pout("Read Cache is: %s\n", res ? "Unavailable" : // error rcd ? "Disabled" : "Enabled"); } if (options.get_wce) { pout("Writeback Cache is: %s\n", res ? "Unavailable" : // error !wce ? "Disabled" : "Enabled"); } if (options.drive_info) pout("\n"); // START OF THE ENABLE/DISABLE SECTION OF THE CODE if ( options.smart_disable || options.smart_enable || options.smart_auto_save_disable || options.smart_auto_save_enable) pout("=== START OF ENABLE/DISABLE COMMANDS SECTION ===\n"); if (options.smart_enable) { if (scsiSmartEnable(device)) failuretest(MANDATORY_CMD, returnval |= FAILSMART); any_output = true; } if (options.smart_disable) { if (scsiSmartDisable(device)) failuretest(MANDATORY_CMD,returnval |= FAILSMART); any_output = true; } if (options.smart_auto_save_enable) { if (scsiSetControlGLTSD(device, 0, modese_len)) { pout("Enable autosave (clear GLTSD bit) failed\n"); failuretest(OPTIONAL_CMD,returnval |= FAILSMART); } else { pout("Autosave enabled (GLTSD bit set).\n"); } any_output = true; } // Enable/Disable write cache if (options.set_wce && SCSI_PT_DIRECT_ACCESS == peripheral_type) { short int enable = wce = (options.set_wce > 0); rcd = -1; if (scsiGetSetCache(device, modese_len, &wce, &rcd)) { pout("Write cache %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg()); failuretest(OPTIONAL_CMD,returnval |= FAILSMART); } else pout("Write cache %sabled\n", (enable ? "en" : "dis")); any_output = true; } // Enable/Disable read cache if (options.set_rcd && SCSI_PT_DIRECT_ACCESS == peripheral_type) { short int enable = (options.set_rcd > 0); rcd = !enable; wce = -1; if (scsiGetSetCache(device, modese_len, &wce, &rcd)) { pout("Read cache %sable failed: %s\n", (enable ? "en" : "dis"), device->get_errmsg()); failuretest(OPTIONAL_CMD,returnval |= FAILSMART); } else pout("Read cache %sabled\n", (enable ? "en" : "dis")); any_output = true; } if (options.smart_auto_save_disable) { if (scsiSetControlGLTSD(device, 1, modese_len)) { pout("Disable autosave (set GLTSD bit) failed\n"); failuretest(OPTIONAL_CMD,returnval |= FAILSMART); } else { pout("Autosave disabled (GLTSD bit cleared).\n"); } any_output = true; } if ( options.smart_disable || options.smart_enable || options.smart_auto_save_disable || options.smart_auto_save_enable) pout("\n"); // END OF THE ENABLE/DISABLE SECTION OF THE CODE // START OF READ-ONLY OPTIONS APART FROM -V and -i if ( options.smart_check_status || options.smart_ss_media_log || options.smart_vendor_attrib || options.smart_error_log || options.smart_selftest_log || options.smart_vendor_attrib || options.smart_background_log || options.sasphy ) pout("=== START OF READ SMART DATA SECTION ===\n"); if (options.smart_check_status) { scsiGetSupportedLogPages(device); checkedSupportedLogPages = 1; if ((SCSI_PT_SEQUENTIAL_ACCESS == peripheral_type) || (SCSI_PT_MEDIUM_CHANGER == peripheral_type)) { /* tape device */ if (gTapeAlertsLPage) { if (options.drive_info) pout("TapeAlert Supported\n"); if (-1 == scsiGetTapeAlertsData(device, peripheral_type)) failuretest(OPTIONAL_CMD, returnval |= FAILSMART); } else pout("TapeAlert Not Supported\n"); } else { /* disk, cd/dvd, enclosure, etc */ if ((res = scsiGetSmartData(device, options.smart_vendor_attrib))) { if (-2 == res) returnval |= FAILSTATUS; else returnval |= FAILSMART; } } any_output = true; } if (options.smart_ss_media_log) { if (! checkedSupportedLogPages) scsiGetSupportedLogPages(device); res = 0; if (gSSMediaLPage) res = scsiPrintSSMedia(device); if (0 != res) failuretest(OPTIONAL_CMD, returnval|=res); any_output = true; } if (options.smart_vendor_attrib) { if (! checkedSupportedLogPages) scsiGetSupportedLogPages(device); if (gTempLPage) { scsiPrintTemp(device); } if (gStartStopLPage) scsiGetStartStopData(device); if (SCSI_PT_DIRECT_ACCESS == peripheral_type) { scsiPrintGrownDefectListLen(device); if (gSeagateCacheLPage) scsiPrintSeagateCacheLPage(device); if (gSeagateFactoryLPage) scsiPrintSeagateFactoryLPage(device); } any_output = true; } if (options.smart_error_log) { if (! checkedSupportedLogPages) scsiGetSupportedLogPages(device); scsiPrintErrorCounterLog(device); if (1 == scsiFetchControlGLTSD(device, modese_len, 1)) pout("\n[GLTSD (Global Logging Target Save Disable) set. " "Enable Save with '-S on']\n"); any_output = true; } if (options.smart_selftest_log) { if (! checkedSupportedLogPages) scsiGetSupportedLogPages(device); res = 0; if (gSelfTestLPage) res = scsiPrintSelfTest(device); else { pout("Device does not support Self Test logging\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } if (0 != res) failuretest(OPTIONAL_CMD, returnval|=res); any_output = true; } if (options.smart_background_log) { if (! checkedSupportedLogPages) scsiGetSupportedLogPages(device); res = 0; if (gBackgroundResultsLPage) res = scsiPrintBackgroundResults(device); else { pout("Device does not support Background scan results logging\n"); failuretest(OPTIONAL_CMD, returnval|=FAILSMART); } if (0 != res) failuretest(OPTIONAL_CMD, returnval|=res); any_output = true; } if (options.smart_default_selftest) { if (scsiSmartDefaultSelfTest(device)) return returnval | FAILSMART; pout("Default Self Test Successful\n"); any_output = true; } if (options.smart_short_cap_selftest) { if (scsiSmartShortCapSelfTest(device)) return returnval | FAILSMART; pout("Short Foreground Self Test Successful\n"); any_output = true; } // check if another test is running if (options.smart_short_selftest || options.smart_extend_selftest) { if (!scsiRequestSense(device, &sense_info) && (sense_info.asc == 0x04 && sense_info.ascq == 0x09)) { if (!options.smart_selftest_force) { pout("Can't start self-test without aborting current test"); if (sense_info.progress != -1) { pout(" (%d%% remaining)", 100 - sense_info.progress * 100 / 65535); } pout(",\nadd '-t force' option to override, or run 'smartctl -X' " "to abort test.\n"); return -1; } else scsiSmartSelfTestAbort(device); } } if (options.smart_short_selftest) { if (scsiSmartShortSelfTest(device)) return returnval | FAILSMART; pout("Short Background Self Test has begun\n"); pout("Use smartctl -X to abort test\n"); any_output = true; } if (options.smart_extend_selftest) { if (scsiSmartExtendSelfTest(device)) return returnval | FAILSMART; pout("Extended Background Self Test has begun\n"); if ((0 == scsiFetchExtendedSelfTestTime(device, &durationSec, modese_len)) && (durationSec > 0)) { time_t t = time(NULL); t += durationSec; pout("Please wait %d minutes for test to complete.\n", durationSec / 60); pout("Estimated completion time: %s\n", ctime(&t)); } pout("Use smartctl -X to abort test\n"); any_output = true; } if (options.smart_extend_cap_selftest) { if (scsiSmartExtendCapSelfTest(device)) return returnval | FAILSMART; pout("Extended Foreground Self Test Successful\n"); } if (options.smart_selftest_abort) { if (scsiSmartSelfTestAbort(device)) return returnval | FAILSMART; pout("Self Test returned without error\n"); any_output = true; } if (options.sasphy) { if (scsiPrintSasPhy(device, options.sasphy_reset)) return returnval | FAILSMART; any_output = true; } if (!any_output) pout("SCSI device successfully opened\n\n" "Use 'smartctl -a' (or '-x') to print SMART (and more) information\n\n"); return returnval; } ����������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/ChangeLog-5.0-6.0����������������������������������������������������0000644�0000000�0000000�00000615720�12035317436�017453� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������CHANGELOG for smartmontools 5.0 to 6.0 $Id: ChangeLog-5.0-6.0 3645 2012-10-10 16:15:26Z chrfranke $ Maintainers / Developers Key (alphabetic order): [AS] Alex Samorukov [BA] Bruce Allen [OB] Oliver Bock [EB] Erik Inge Bolsø [SB] Stanislav Brabec [PC] Peter Cassidy [MC] Matthieu Castet [YD] Yuri Dario [CD] Casper Dik [CF] Christian Franke [GF] Guilhem Frézou [DG] Douglas Gilbert [GG] Guido Guenther [JPH] Jordan Powell Hargrave [JH] Joerg Hering [GK] Geoff Keating [DK] Dr. David Kirkby [DL] Dan Lukes [KM] Kai Mäkisara [EM] Eduard Martinescu [FM] Frédéric L. W. Meunier [GP] Gabriele Pohl [AR] Adam Radford [KS] Keiji Sawada [MS] Manfred Schwarb [TS] Tomas Smetana [DS] David Snyder [SS] Sergey Svishchev [PW] Phil Williams [LW] Leon Woestenberg [SZ] Shengfeng Zhou [RZ] Richard Zybert <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE> smartmontools 6.0 2012-10-10 [CF] do_release: Fix for minor rev number 0. [CF] drivedb.h updates: - SandForce Driven SSDs: Corsair Force 115GB - Hitachi Ultrastar 7K4000 - Seagate Barracuda 7200.7 and 7200.7 Plus: IBM OEM variants - Western Digital Caviar Black (AF) [CF] man pages: Update introduction. Update ATA standards. Remove some outdated info. [CF] man pages: Unify license headers. [CF] smartctl: Do not abort SCT status output on unknown temperature history format version. [CF] smartctl: Remove duplicate note about selective self-test log version. [CF] smartctl: Add '-l devstat' to '-x, --xall' output. [CF] smartctl: Rework ATA error messages and 'not supported' messages. Avoid misleading warnings on unsupported features (ticket #182). Avoid duplicate error messages. [CF] atacmds.h: Remove nonexistent functions. [CF] Windows installer: Add support for /S(ilent) install/uninstall. [CF] Windows installer: Update examples. Remove some doc shortcuts. [CF] Prepare release 6.0. Change Copyright output line. Change AUTHORS sections on man pages. [CF] smartctl: Rework "ATA Version" output. Print major and minor revision in one output line. Remove "ATA Standard" line. [CF] drivedb.h updates: - Add firmware warnings for various Seagate series (ticket #239): DiamondMax 23, Barracuda 7200.12, 7200.14 (AF), LP, Green (AF) - Seagate Barracuda 7200.14 (AF): 2.5TB [CF] drivedb.h updates: - SandForce Driven SSDs: SanDisk Extreme - Indilinx Everest/Martini based SSDs: OCZ-VERTEX4, fix Attribute 232 - STEC Mach2 CompactFlash Cards - Toshiba 2.5" HDD MK..55GSX: *55GSXF variants - Western Digital VelociRaptor (AF) [CF] Windows: Remove EXPERIMENTAL notes for 64-bit version. [CF] autogen.sh: automake 1.11.6 and 1.12.3 are OK. [CF] smartctl: Fix '--identify' for big-endian CPUs. [CF] ataidentify.cpp: Document some older (now obsolete) features. [CF] ataidentify.cpp: Add some recent ACS-3 features. [CF] smartctl: Support '-l sataphy' also for Packet interface devices. [CF] atacmds.cpp: Add new ATA ACS-3 minor revision. [CF] smartctl: Print SATA version and speed in '-i' output. [CF] drivedb.h: Minor reordering of Seagate entries. [CF] drivedb.h: Use "AF" for Advanced Format (4KiB LPS). [CF] drivedb.h updates: - Seagate Barracuda SpinPoint F3 - SAMSUNG SpinPoint F3 RE - Seagate Barracuda 7200.12: ST3750525AS - Seagate Barracuda 7200.14 (AF): change name, add -v options - Western Digital Red (AF) - USB: Seagate Backup Plus USB 3.0 (0x0bc2:0xa013) (ticket #235) - USB: Seagate Backup Plus Desktop USB 3.0 (0x0bc2:0xa0a4) [CF] os_win32.cpp: Add support for SAS disks behind Areca SAS controllers. This includes SAS/SATA autodetection. Patch was provided by Hank Wu from Areca. [CF] ataidentify.cpp: Add some recent SATA features. [CF] smartctl: Add '--identify[=wnvb]' option. Add new source files ataidentify.h/cpp. [CF] Makefile.am: Reformat lists of sources. [CF] Do not print HDD/SSD specific default attribute names if identify data reports SSD/HDD device. [CF] drivedb.h updates: - Intel 320 and 710 Series SSDs: Set '-F nologdir' - Seagate Barracuda ES.2: Set '-F xerrorlba' [CF] Create branches RELEASE_5_4[0-3]_DRIVEDB with last drivedb.h file compatible with smartmontools 5.4[0-3]. [CF] drivedb.h updates: - SAMSUNG SpinPoint M40/60/80: HM120IC - USB: Oxford (0x0928:0x0010) - USB: Seagate External Drive/Cypress (0x0bc2:0x0503) - USB: 0x1f75:0x0888 is Innostor IS888 [CF] smartctl: Print nominal media rotation rate in '-i' output (ATA). [CF] knowndrives.cpp: Fix missing '-F xerrorlba' in '-P show' output. [CF] os_win32.cpp: Use WMI to get serial number if IOCTL_STORAGE_QUERY_PROPERTY is used. [CF] os_win32.cpp: Remove more Win9x/ME/NT4 specific code: ATA drive number, GetDevicePowerState() handling. [CF] Add '-F xerrorlba' option/directive. [CF] Rework '-F' option handling. Add support for multiple '-F' options and directives. [CF] Makefile.am: Fix typo in ACLOCAL_AMFLAGS. [CF] smartd.cpp: MailWarning(): Move variable declarations, use sizeof() instead of numbers. [CF] smartd.cpp: Rework dnsname(). Print "[None]" instead of "[Unknown]" if domain is not set. Print NIS domain only if supported. [CF] Windows smartd: Use gethostname/gethostbyname() from winsock. Remove os_win32/hostname_win32.*. [CF] smartd: Include device identify info in warning emails (ticket #185). Add SMARTD_DEVICEINFO environment variable. [CF] Add '-F nologdir' option/directive. Prevents freeze of some Intel SSDs (ticket #214). [CF] smartd: Don't log ignored -W directive as critical. [CF] drivedb.h updates: - Smart Storage Systems Xcel-10 SSDs: Move entry, change name - Samsung: Remove very old and already commented out entries - Seagate Momentus XT (Adv. Format) - WD My Passport: 3 -> 2 entries, add 2TB - USB: Imation (0x0718:0x1000) (ticket #231) - USB: Initio (0x13fd:0x1040): unsupported - USB: ASMedia USB 3.0 (0x174c:0x55aa): unsupported -> -d sat - USB: PQI H560 (0x3538:0x0902) (ticket #232) [CF] smartctl: Override SMART disabled state with '-T permissive'. [CF] os_win32/daemon_win32.cpp: Drop remaining WinNT4 compatibility. [CF] Windows smartd: Add smartd.conf directives '-m console', '-m active', '-m connected'. Send warning messages via WTSSendMessage(). Remove use of MessageBox() which does no longer work for services since Vista/2008. [CF] Fix 'smartctl -P show'. Regression from r3249. [CF] smartd.cpp: Fix setting of temporary environment in MailWarning(). Stack space was passed to putenv() but variable was not unset before return. Very old bug introduced 2003 in r1114. [CF] smartd.cpp: Add fflush() to support redirection of debug output (Debian bug 681349). [CF] os_generic.cpp: Add missing int64.h (Debian bug 619208) This obsoletes Debian patch fix-generic.diff. [CF] cciss.cpp: Fix build on GNU/kFreeBSD (Debian bug 676142). This obsoletes Debian kfreebsd.patch. [CF] Windows: Drop backward compatibility with WinNT4. [CF] Windows: Drop backward compatibility with Win9x/ME. smartmontools 5.43 2012-06-30 [CF] drivedb.h USB updates: - Toshiba Canvio Basics (0x0480:0xa006) - A-DATA DashDrive (0x125f:0xa94a) [CF] drivedb.h: Hitachi Travelstar 7K500: *A362/3 variants [CF] Windows: Add Windows Server 2012 to get_os_version_str(). [CF] drivedb.h updates: - Sandforce Driven SSDs: OWC Mercury Electra 3/6G SSD - Seagate Momentus SpinPoint M8 - Hitachi Deskstar 5K4000 - Toshiba 2.5" HDD MK..61GSYN - Seagate Barracuda (SATA 3Gb/s, 4K Sectors): 1TB, *DM003-* variant [CF] smartctl.8.in: Note performance impact of self-tests. [CF] os_win32.cpp: Add support for older Areca drivers which used a different target id. Patch was provided by Hank Wu from Areca. [CF] smartctl.8.in: Add info about HP Smart Array controllers. Original patch was provided by Don Brace from HP. [CF] os_freebsd.cpp: add SAT autodetection to '-d cciss,N' device type (ticket #202). Add missing freebsd_areca_device::m_encnum (regression from r3542). Patch was provided by Don Brace from HP. [CF] os_linux.cpp: add SAT autodetection to '-d cciss,N' device type (ticket #202). [CF] Makefile.am: FIXHTML modified for newer man2html versions. [CF] autogen.sh: automake 1.11.5 is OK. [CF] man pages: Minor updates and syntax fixes. [CF] smartd.service.in: Add ExecReload and StandardOutput. Make EnvironmentFile optional (ticket #194). [CF] drivedb.h USB updates: - HP Desktop HD BD07 (0x03f0:0xbd07) - Iomega Prestige Desktop USB 3.0 (0x059b:0x0070) - Prolific PL2507 (0x067b:0x2507): unsupported -> -d usbjmicron,0 - WD My Passport USB 3.0 (0x1058:0x0748) - WD My Book Essential USB 3.0 (0x1058:0x1140) - Sharkoon SATA QuickDeck Pro (0x1f75:0x0888): unsupported - Hitachi Touro Desk (0x4971:0x1015) [CF] Move function str_starts_with() to utility.h. [CF] smartctl.8.in, smartd.conf.5.in: Note required Areca SAS firmware version. [CF] INSTALL, smartctl.8.in: Announce OS X SAT SMART Driver (ticket #25). [CF] Add smart_device::is_syscall_unsup(). [CF] os_win32.cpp: Avoid ENOTSUP which is not provided by some versions of MinGW. [DG] os_linux.cpp: Fix scsi pass-through SG_INFO_CHECK mask logic (ticket #225) [CF] drivedb.h updates: - Sandforce Driven SSDs: OCZ-NOCTI - Intel 330 Series SSDs (ticket #227) [CF] smartctl.8.in, smartd.conf.5.in: Document '-d areca N[/E]' support for Windows. [CF] os_win32.cpp: Add help text and error messages for '-d areca,N[/E]'. [CF] os_win32.cpp win_areca_device: Disable full 48-bit ATA support. Add missing set_err() calls. Remove unused function and parameter. [CF] os_win32.cpp: Add support for SATA disks behind Areca SATA and SAS controllers. Requires '-d areca,N[/E]' as type and '[/dev/]arcmsrX' as device name. Patch was provided by Hank Wu from Areca. [CF] Windows installer: Make name of checksum file 32-/64-bit specific. [CF] Windows installer: Add support for combined 32-/64-bit installer. [CF] Windows installer: Drop support for UBCD4Win. [AS] os_freebsd.cpp: sync Areca code with linux version by adding optional enclosure number. [CF] smartctl.8.in, smartd.conf.5.in: Add brief doc for '-d areca N/E'. [CF] os_linux.cpp: Add optional enclosure number to '-d areca' option. This adds support for SATA disks behind Areca SAS controllers. Patch was provided by Hank Wu from Areca. [CF] smartctl: Add log addresses and statistics value from ACS-3 revision 2. [CF] drivedb.h updates: - Crucial/Micron RealSSD C300/C400/m4: m4 512GB - Indilinx Everest/Martini based SSDs: OCZ-PETROL - SAMSUNG SpinPoint F4 EG (AFT): Fix link - Seagate Momentus 4200.2: ST960812A - Seagate Momentus 5400.2: ST960821A (from 4200.2) - Seagate Barracuda 7200.12: ST3500413AS - Western Digital RE3 Serial ATA: WD7502ABYS - Western Digital AV-GP: WD....AV[CD]S, split entry - Western Digital AV-GP (Adv. Format): WD10EU[CR]X [CF] autogen.sh: Set svn:eol-style=LF to be compatible with Cygwin bash. [CF] autogen.sh: automake 1.11.3 is OK. [CF] drivedb.h updates: - Sandforce Driven SSDs: Smart Storage Systems XceedSTOR, XceedIOPS2, Xcel-200 - Smart Storage Systems XceedSecure2 SSDs - Smart Storage Systems XceedUltraX/Adtron A25FBX SSDs - Smart Storage Systems Adtron A25FB 2xN SSDs - Smart Storage Systems Adtron A25FB 3xN SSDs Original patch was provided by Rusty Carruth [CF] drivedb.h updates: - Remove outdated IBM links - Update all links to Seagate Knowledge Base - Hitachi Deskstar 7K1000.D [CF] drivedb.h USB update: - Seagate Expansion External (0x0bc2:0x3332) (ticket #223) [CF] drivedb.h USB updates: - Samsung Story Station (0x04e8:0x5f05) - Toshiba STOR.E (0x0930:0x0b1b) [CF] smartctl: Add options '-f hex' and '-f hex,[id|val]' to print attribute IDs and/or values as hex. [CF] smartd.8.in: Fix signal name (Debian bug 661801). [CF] Add 'raw56', 'hex56', 'raw24(raw8)' attribute print formats. Change default for Power_On_Hours to 'raw24(raw8)'. This provides more reasonable output for SandForce based devices missing in drivedb.h. [CF] configure.in, Makefile.am: Support new SVN 1.7 working copy format. [CF] drivedb.h update: - Intel 520 Series SSDs: Add units to attributes 241, 242, 249. [AS] drivedb.h: fixed identifier for Seagate SV35 series. [CF] Print command duration in ATA debug output. Add smart_interface::get_timer_usec(). [CF] drivedb.h updates: - SandForce Driven SSDs: G.SKILL Phoenix Pro - Intel 520 Series SSDs - SAMSUNG SpinPoint F4 EG: Update firmware download link [CF] drivedb.h updates: - Add comment with default settings. - Samsung based SSDs: Fix attribute 240 [CF] Windows: Add Win8 to get_os_version_str(). [CF] Windows: Remove MSVC specific pragma, disable warning in project file. [CF] Add '-d sat,auto[,N]' option for controller independent SAT detection. [CF] dev_interface.h: Replace this_is_ata/scsi(*) by hide_ata/scsi(bool). [CF] smartctl: Allow '-d test' in conjunction with other '-d TYPE' options. [AS] FreeBSD: sync init script with one from ports repository. [CF] drivedb.h updates: - SandForce Driven SSDs: ADATA S510 - JMicron based SSDs: Toshiba THNSNC128GMLJ - Samsung based SSDs: 830 Series - Hitachi Deskstar E7K1000 - Hitachi Ultrastar A7K1000: Fix name, allow trailing characters - Hitachi Ultrastar A7K2000: Remove duplicate entry - Toshiba 2.5" HDD MK..55GSX - Western Digital AV-GP: WD..EURS variants [CF] drivedb.h USB updates: - Buffalo MiniStation HD-PCTU2 (0x0411:0x01d9) (ticket #211) - Philips SDE3273VC/97 (0x0471:0x2021) (ticket #212) - Samsung M2 Portable 3.0 (0x04e8:0x60c5) - Iomega GDHDU2 (0x059b:0x0475) - LaCie minimus USB 3.0 (0x059f:0x104a) - Seagate FreeAgent GoFlex Desk USB 3.0 (0x0bc2:0x50a5) - Maxtor BlackArmor Portable (0x0d49:0x7550) - WD My Passport Essential SE USB 3.0 (0x1058:0x0742) - Initio (0x13fd:0x1e40) - Verbatim External Hard Drive 2TB (0x18a5:0x022a) - Hitachi Touro Desk (0x4971:0x1011) [CF] smartd: Add smartd.conf directive '-e' to set ATA settings on startup: aam, apm, lookahead, security-freeze, standby, wcache. [CF] drivedb.h updates: - SandForce Driven SSDs: Corsair Force GT - Indilinx Barefoot based SSDs: Corsair Nova - SAMSUNG SpinPoint M8 - Seagate SV35.5 [CF] smartctl: Change short option for '--set' from '-e' to '-s'. Keep backward compatibility with short option for '--smart'. [CF] smartctl: Print description of APM level. [CF] smartctl: Add option '-e standby,[N|off|now]' to set standby timer or standby mode. [CF] smartctl: Add options '-g security' and '-e security-freeze' to get/freeze ATA security settings. [CF] smartctl: Add options '-g/e lookahead' and '-g/e wcache' to get/set read look-ahead and write cache feature. [CF] smartctl: Add options '-g aam' and '-e aam,[N|off]' to get/set ATA Automatic Acoustic Management feature. Add '-g all'. [CF] os_win32.cpp: Prevent warnings from gcc option -Wformat-security. [CF] smartctl: Add options '-g, --get apm' and '-e, --set apm,[N|off]' to get/set ATA Advanced Power Management feature. Original patch was provided by Marcus Sorensen. [AS] os_freebsd.cpp - do not skip ATA devices from cam list. Starting from FreeBSD 9.0 such devices are exported ONLY as camdev`s, so DEVICESCAN was broken. Its possible to get duplicates now on some old systems. [CF] drivedb.h updates: - SandForce Driven SSDs: Add OCZ Solid 3, OCZ Deneva 2 C/R - Seagate Momentus 5400.7 [CF] Happy New Year! Update copyright year in version info. [CF] drivedb.h updates: - SandForce Driven SSDs: Add Patriot Pyro - Intel 320 Series SSDs: Fix 40GB - Seagate Barracuda XT: Add 4TB [CF] drivedb.h updates: - SandForce Driven SSDs: Add Corsair Force 3 - Hitachi Travelstar 5K320: Add SA00 and SA02 models - Western Digital Caviar SE SATA: Add 300GB [CF] Cygwin smartd: Remove SIGQUIT workaround, no longer needed with current Cygwin tty emulation. [CF] smartd: Disable auto standby also after start of scheduled self-test. [CF] smartd: Add smartd.conf DEFAULT directive. Allows to set default settings for multiple devices. [CF] smartd: Re-enable auto standby if smartd.conf is re-read. [AS] drivedb.h update: Seagate Barracuda (SATA 3Gb/s, 4K Sectors) [AS] drivedb.h update: Seagate Constellation ES.2 (SATA 6Gb/s) [CF] drivedb.h updates: - Sandforce Driven SSDs: Add OCZ Vertex 3 Max IOPS (ticket #209) - Seagate ST1.2 CompactFlash (found in ticket #125) [CF] Fix GPL version reported by '-V' option. Now reports GPLv2+ which is consistent with file headers. Patch was provided by Stanislav Brabec. [CF] drivedb.h updates: - Sandforce Driven SSDs: Add OCZ Deneva 2 Async variant, 60GB, 480GB - Indilinx Martini based SSDs: OCZ VERTEX-PLUS only [CF] smartd: Add '-l offlinests,ns' and '-l selfteststs,ns' directives. dev_interface: Add smart_interface::disable_system_auto_standby(). os_win32.cpp: Implement disable_system_auto_standby(). [CF] dev_interface: Let smart_interface::set_err() return false. [CF] drivedb.h updates: - SAMSUNG SpinPoint M8U (USB) - Toshiba 3.5" HDD MKx002TSKB: Fix typo [CF] smartctl: Print average temperature from SCT status only if value is reasonable. Field is not part of ATA-8. [CF] smartd: Report ignored '-r' and '-R' directives. [CF] smartctl: Use 16-bit value (ATA-8) for extended self-test polling time if 8-bit value is 0xff (ticket #207). [CF] drivedb.h updates: - SandForce Driven SSDs: Add OCZ-REVODRIVE3, OCZ Z-DRIVE R4 - Hitachi Travelstar Z7K320 - Toshiba 2.5" HDD MK..56GSY - Toshiba 2.5" HDD MKx002TSKB - Seagate U9 - Seagate U*: sort entries, unify names, remove duplicate - Seagate Constellation ES (SATA 6Gb/s) - Seagate DB35 - Seagate DB35.2 - Western Digital Scorpio Black: Add 500GB - Western Digital Scorpio Black (Adv. Format) [CF] drivedb.h USB updates: - Samsung S2 (0x04e8:0x1f05) - Toshiba Stor.E (0x0939:0x0b16) (ticket #206) - Seagate FreeAgent (0x0bc2:0x5040) - Initio/Thermaltake BlacX (0x13fd:0x0840) [DG] [SCSI] smartd: skip non-storage devices (e.g. SES devices) [AS] drivedb.h updates: Added Seagate SV35 Series [CF] smartctl: Don't start ATA self-test if another test is already running (ticket #40). Add option '-t force' to allow override. [CF] atacmds.h: Remove bogus ataSmart*Test*() prototypes. [CF] Define __attribute_format_printf() for functions with printf() style arguments. Allow MinGW build with __USE_MINGW_ANSI_STDIO enabled. [CF] Makefile.am: Replace sed compound command in MAN_FILTER. This fixes build on Solaris (ticket #203). [AS] os_freebsd.cpp: Dereference symlinks before guess of device type (problem reported by email). [CF] drivedb.h USB updates: - LG Mini HXD5 (0x043e:0x70f1) - Freecom/Intel (0x07ab:0xfc8e) - Dura Micro (0x0c0b:0xb001) (Debian bug 643928) - Initio 6Y120L0 (0x13fd:0x1150): unsupported [CF] drivedb.h USB update: - Seagate FreeAgent GoFlex Desk USB 3.0 (0x0bc2:0x50a1): Revert to -d sat,12 (ticket #151). [AS] os_freebsd.cpp - fixed crash on FreeBSD9-RC1 caused by r225950 [AS] smartctl.8 - added information about -d areca on FreeBSD [AS] os_freebsd.cpp: backport quirks for the LSI controllers with SATA disks to the FreeBSD. Tested with DELL Perc/6i controller. [AS] os_freebsd.cpp: disable SAT autodetection on megaraid controllers [AS] drivedb.h update: - Hitachi Ultrastar 7K2000 [CF] drivedb.h update: - Seagate Momentus XT: Add bug warning for firmware SD24 and SD25 [CF] Don't include pkg-config macros in aclocal.m4, copy to m4/pkg.m4 instead. Allow builds from SVN without pkg-config installed but prevent 'make dist' when pkg-config support is missing. [CF] Move automake --foreign option from autogen.sh to configure.in. This fixes autoreconf support. [CF] Replace COPYING file with current (2010-03-24) version from http://www.gnu.org/licenses/gpl-2.0.txt smartmontools 5.42 2011-10-20 [CF] Windows installer: Add install dir to PATH in CMD shortcut. [CF] drivedb.h updates: - SAMSUNG SpinPoint MP5 - Seagate Barracuda 7200.11: Change warning text, Seagate apparently released fixed firmware without changing version number (Debian bug 632758) - Western Digital RE4 GP - Western Digital VelociRaptor: Add 150GB, 300GB LHX variants - Western Digital Scorpio Blue Serial ATA (Adv. Format): Add 1TB JPVT variant [CF] drivedb.h USB update: - WD Elements SE USB 3.0 (0x1058:0x1042) [CF] Windows installer: Rework to support UAC. Replace *-run.bat files by runcmd?.exe wrappers. Run drive menu entries elevated (ticket #173). [CF] smartctl.8.in: Add example script which prints all status bits (ticket #191). [CF] Cygwin smartd: Remove '--service' option, update man page. [CF] smartd: Require absolute path name also for '-p' option. Allow relative path names for '-A', '-s', '-p' in Windows version only. [CF] smartd: Log model family from drive database if known. [CF] drivedb.h update: - SMART Xcel-10 2.5 SATA SSD: Shorten names, document supported default attributes. [CF] smartctl -P showall: Report error if attribute name is too long. [AS] freebsd: use system ciss header if available, it is added to the base system by recent commit. [CF] smartd.conf.5.in: Update Windows 'msgbox' info. Add missing IF/ENDIF for Solaris and Windows. [CF] man pages: Remove reference to T13 web site. It does no longer provide links to the ATA documents. [CF] smartctl: Replace '-t scttempint,N[,p]' option by '-l scttempint,N[,p]'. [CF] drivedb.h USB update: - Oxford (0x0928:0x0000): unsupported, see https://bugs.freedesktop.org/show_bug.cgi?id=24951 [CF] Minor cleanup to prevent warnings from new gcc 4.6 options -Wunused-but-set-parameter/variable. [CF] Windows smartd: Fix format string for 64-bit version. [CF] Remove EXPERIMENTAL notes for features already present in 5.40. [CF] smartctl: Add new log addresses from ACS-3 revision 1. [CF] smartctl: Print ATA ACS-x versions properly (ticket #183). [CF] smartctl: Add option '-l devstat[,PAGE]', print ATA Device Statistics log pages (ticket #106). Thanks to David Boreham for providing access to a machine for testing. [AS] man pages: trivial man page syntax fixes (ticket #199) [CF] drivedb.h update: - SMART Xcel-10 2.5 SATA SSD: Fix syntax error (ticket #200) [AS] drivedb.h update: - SMART Xcel-10 2.5 SATA SSD [DG] [SCSI] document 'ssd' list option in man page and smartctl usage. [CF] Windows: Fix device type detection for Intel ICHxR RAID Volumes. [CF] smartd: Resend warning emails if problem reappears (ticket #167). [CF] smartd: Add separate directives '-l offlinests' and '-l selfteststs' to enable tracking of status changes. Disable '-l offlinests' by default to avoid misleading messages (see Debian bug 636078). [CF] drivedb.h updates: - Crucial/Micron RealSSD C300/C400: Add m4 series (ticket #192) - SandForce Driven SSDs: Add OCZ-AGILITY3 - Indilinx Barefoot based SSDs: Add RENICE Z2 - Intel 710 Series SSDs [CF] Windows smartd: Fix quoting of service command line. [CF] Cygwin smartd: Remove FreeConsole() after fork(). No longer needed for recent versions of Cygwin DLL. [CF] smartd: Add some sleep() time after machine standby mode. Some drivers (Intel ICHxR Windows driver) report failures if pass-through is accessed immediately after wake up. [AS] -d hpt on linux/freebsd - increased max channel number to 16, fixed documentation. (see http://permalink.gmane.org/gmane.linux.utilities.smartmontools/7846) [AS] os_linux.cpp - disabling SMART WRITE LOG SECTOR command on megaraid interface for SATA disks. [AS] os_freebsd.cpp: -l scterc was broken on FreeBSD, fixed for atacam and ata drivers (bug #198). [CF] drivedb.h updates: - Crucial/Micron RealSSD C300/C400: Add C400 - SandForce Driven SSDs: Add Kingston HyperX, OCZ-REVODRIVE, OCZ Deneva 2 - Intel X18-M/X25-M/X25-V G2 SSDs: Add 120GB - Hitachi Travelstar 7K200: Match capital letters also - Hitachi Ultrastar 7K3000 - Seagate Barracuda Green: Add ST2000DL001-* (ticket #195) - WD My Passport Essential SE: Add WD10TMVW-* [CF] drivedb.h USB updates: - Seagate FreeAgent GoFlex USB 3.0 (0x0bc2:0x5071) (ticket #195) - Seagate FreeAgent GoFlex Desk USB 3.0 (0x0bc2:0x50a1): Enable -d sat,16 (ticket #151). - Oyen Digital MiniPro USB 3.0 (0x0dc4:0x020a) (ticket #193) - WD My Passport Essential SE USB 3.0 (0x1058:0x0740) [CF] Windows: Add MSVC10 support, remove MSVC8 project files. [DG] [SCSI] smartctl output Solid State Media (SSD) percentage used endurance indicator. Add '-l ssd', useful for SATA SSDs? [CF] atacmds.cpp: Rework search for temperature min/max values in attributes 190/194. This fixes temperature tracking for recent WDC drives. [CF] drivedb.h USB updates: - LaCie rikiki USB 3.0 (0x059f:0x1057) - Freecom Mobile Drive XXS (0x07ab:0xfc88) - WD Elements SE (0x1058:0x1023) [CF] drivedb.h updates: - Indilinx Barefoot based SSDs: Add G.Skill Falcon - JMicron based SSDs (JMF61x): Add Kingston SSDNow V100 Series - Transcend CompactFlash Cards: Add 8, 16GB - Toshiba 1.8" HDD MD..29GSG - SAMSUNG SpinPoint M7U - Western Digital Caviar Green (Adv. Format): Add SATA 6Gb/s variants - Western Digital My Passport USB: Shorten names [DG] [SCSI] smartd initial log entry for each drive now shows INQUIRY strings and optionally the LU (logical unit) id and capacity [AS] os_freebsd.cpp: fixed return type in autodetect_smart_device. [CF] drivedb.h USB updates: - WD My Book Essential (0x1058:0x0910, Debian bug 633724) - Atech (0x11b0:0x6298) [CF] drivedb.h update: - Seagate Barracuda ES.2: Add Dell firmware versions (ticket #189) [CF] drivedb.h updates: - Seagate Maxtor DiamondMax 21: Add STM380215AS - Seagate Barracuda 7200.12: Add ST3250312AS, ST31000524AS - Toshiba 2.5" HDD MK..50GACY - Toshiba 2.5" HDD MK..76GSX [AS] smartd.8 - removed configuration file information from this manual, added reference to smartd.conf.5. [AS] smartd.conf.5 - added more platform-specific sections, corrected "areca" device information, corrected sample configuration. [AS] os_freebsd.cpp: detecting access to /dev/mfidX devices to show help (#97) [CF] Update configure options in INSTALL file, remove outdated info. [CF] int64.h: Remove outdated uint64_to_double() workaround for MSVC6. [CF] os_win32/update-smart-drivedb.nsi: Add support for /S(ilent) option. [CF] configure.in: Don't search for initddir and systemdsystemunitdir when cross-compiling. [CF] Makefile.am: Use same syntax also for ENABLE_* man page sections. [CF] Add experimental support for platform-specific man pages. [CF] Windows: Move '-I os_win32' from configure.in to Makefile.am. [CF] configure.in: Fix check for __attribute__((packed)). [CF] drivedb.h USB update: - Verbatim Portable Hard Drive (0x18a5:0x0214) [CF] drivedb.h update: - SandForce Driven SSDs: Add OWC Mercury Extreme Pro RE (ticket #168) [CF] os_linux.cpp: Let MegaRAID autodetect_open() fail for SATA devices. MegaRAID SAT layer has serious bugs as reported by AS. [AS] os_freebsd.cpp: Implement 48bit support for the new "atacam" interface. Tested on FreeBSD 8.2 and works fine. [CF] os_win32.cpp: Fix USB ID detection if two devices with the same name exist (ticket #178). [AS] os_freebsd.cpp: including ciss headers to the base, we can not rely on the header sources in the build time. Also this file was changed last time > 2 yrs. ago and it is unlikely that it will be changed in the feature. This will fix FreeBSD PR 150235. [AS] drivedb.h update: Added Samsung Story Station 3.0 USB. [AS] os_linux.cpp: Areca code converted to the new interface. Patch is based on os_freebsd.cpp patch and is not tested yet. [AS] os_freebsd.cpp: Areca code converted to the new interface. [AS] os_freebsd.cpp: Added support for the Areca RAID controllers. Support is basesd on Linux code, but using IOCTL on areca control device instead of SCSI commands to talk with the drives. Hardware access was provided by Andrej Binder. [CF] Don't use isprint() for ASCII character check as it may be affected by setlocale(). [AS] os_freebsd.cpp: Remove all referenced to the FreeBSD 5.0. It is unsupported for a very long time and probably will not compile and work anyway. Also this will fix bug #154. smartmontools 5.41 2011-06-09 [MS] drivedb.h: revert attribute 190 to default for Samsung SSD controllers, some 470 series SSDs seem to have some temperature information at this location. [MS] drivedb.h update: add attribute details for Samsung controllers, centralize entries [MS] drivedb.h update: add attribute details for JMicron JMF61x controllers [CF] drivedb.h update: - SandForce Driven SSDs: Add OCZ DENEVA [CF] os_win32.cpp: Ignore vendor ID "ATA" if returned by IOCTL_STORAGE_QUERY_PROPERTY. [CF] Add ATA NCQ commands to error register decoding. [CF] Re-enable '--with-initscriptdir=auto' as default. Change search for initddir and systemdsystemunitdir such that default ./configure does never overwrite system files. [MS] drivedb.h update: disentangle Transcend SSD versions [MS] drivedb.h update: add attribute details for Crucial C300 [MS] smartd.initd.in: fix for debian, cleanup. Based on patch of CF. [AS] --with-initscriptdir default changed to "no" from "auto" to avoid filesystem pollution. [MS] drivedb.h cleanup: harmonize family names, add AF information into name [MS] drivedb.h update: - OCZ Vertex 3 - Seagate Barracuda Green 1TB variant [CF] Windows: Avoid '%n' printf format specifier because it is always disabled in recent versions of msvcrt.dll. This fixes truncation of smartd warning email (ticket #174). [MS] smartd.initd.in: cleanup, provide targets "reload" and "report" for all platforms [CF] drivedb.h update: - JMicron based SSD (JMicron JMF602?): rename from Kingston SSDNow V Series, move Transcend IDE and SATA entries to here. [CF] Support ':BYTEORDER' for all attribute print formats. [CF] drivedb.h update: - Kingston SSDNow V Series SSDs (ticket #171) [CF] Increase size of drive database option parse buffer to allow long '-v N,FORMAT:BYTEORDER,NAME' options. [MS] drivedb.h update: - Western Digital Scorpio Blue Advanced Format variants [MS] drivedb.h update: correct typo for Cowon iAudio X5 [MS] drivedb.h USB updates: - Maxtor OneTouch 200GB (unsupported) - LaCie Little Disk [AS] FreeBSD: Added native rc.conf style script to the package. Modifications to the configure script to use correct template and path. [AS] freebsd_os.cpp: Fix memory leak in the ata detection code (added free()) Using bzero in cam code to clear structure (fixing varnish varning) [MS] drivedb.h update: Kingston SSDNow S100 Series [MS] drivedb.h USB update: - Samsung S1 Portable - LaCie rikiki USB 3.0 - Seagate FreeAgent GoFlex USB 3.0 - Cowon iAudio X5 - Oxford OXU921DS chip (unsupported) [CF] Windows: Add debug output of SCSI sense data. [CF] Add 'smartd.service' file for systemd. Add configure option '--with-systemdsystemunitdir'. Disable initd script if systemd is used. [MS] drivedb.h update: - Western Digital AV-25 family [MS] drivedb.h update: JMicron based SSDs: Add Kingston SSDNow V, Kingston SSDNow V+100, TOSHIBA THNS128GG4BBAA, APPLE SSD TS*, ADATA S596 Turbo [CF] drivedb.h update: - Intel 510 Series SSDs (ticket #170) [CF] smartctl: Don't issue SMART DISABLE command to 3ware controllers when the port number was not specified (ticket #165). [CF] Use get_errmsg() from device instead of errno or syserror() for printing error messages. [MS] drivedb.h updates: - G.Skill FALCON II SSD (Indilinx) - HP 250GB SATA disk VB0250EAVER - SAMSUNG SpinPoint M5 HM160HC - SAMSUNG SpinPoint MT2 HM100UI - SAMSUNG HM100UX - Hitachi Deskstar 5K3000 Series - Seagate Barracuda Green (Adv. Format) - Seagate Barracuda XT 3TB variant - Western Digital RE4 Serial ATA family - Western Digital Caviar Green WD20EACS - Western Digital Caviar Black family, SATA 3.0 variants - QUANTUM FIREBALLlct20 10 - QUANTUM FIREBALLP AS60.0 [CF] drivedb.h update: - SandForce Driven SSDs: Add more OCZ SF-1200 and SF-1500 based drives Thanks to Sudhir Verman from OCZ Technology for providing this info. [CF] drivedb.h USB updates: - Seagate Expansion External (0x0bc2:0x3300) (Debian bug 621411) - ASMedia USB 3.0 (0x174c:0x55aa) (unsupported) [CF] smartctl.8.in: Clarify '-t vendor,N' (ticket #169). Update Intel info (ticket #168). [CF] drivedb.h update: - Intel 320 Series SSDs (ticket #168) [CF] smartctl: Always print sector size in '-i' output (ticket #166). [CF] os_linux.cpp: Shorten version string. [CF] smartctl: Add option '-f brief' to select new attribute output format. This format includes additional attribute flags (ticket #109) and fits in 80 columns (ticket #158). This format is now the default for '-x'. [CF] smartd: Log changes of offline data collection status if '-l selftest' is specified. [CF] drivedb.h updates: - SandForce Driven SSDs: Add ADATA S599 64GB, OWC Mercury Extreme Pro - Kingston branded X25-V SSDs (ticket #156) - Transcend SATA Solid State Drive: Truncate attribute name [CF] drivedb.h USB updates: - LaCie (0x059f:0x1029) (ticket #153) - WD My Book Office Edition (0x1058:0x1101) - JMicron USB 3.0 (0x152d:0x0539) [CF] drivedb.h USB update: - Verbatim Pocket Hard Drive (0x18a5:0x0227) (ticket #159) [CF] drivedb.h update: - SAMSUNG SpinPoint N3U-3 (USB, 4KiB LLS) (ticket #159) [CF] Add support for ATA Long Logical Sectors (LLS) (ticket #159). [DG] [SCSI] smartctl: (re-)use capacity formatting in utility.cpp [CF] configure.in: Remove '-Wno-format' for MinGW. Recent MinGW versions support MSVCRT printf format strings. [CF] Print ATA disk capacity with SI prefix. Add/move capacity formatting to utility.cpp [CF] Add error messages if ATA pass-through does not return required ATA output registers (for SMART RETURN STATUS, GET POWER MODE). This prevents misleading 'SMART Status command failed' messages (see ticket #155). [CF] Fix WWN support check for older ATA-7 disks. [DG] [SCSI] smartctl: add 'Logical Unit id' from the Device Identification VPD page (0x83) [DG] [SCSI] smartctl: add 'User Capacity' (disk size) in human readable form [CF] smartctl, smartd: Print World Wide Name (WWN) of ATA device. [CF] smartctl: Print more specific error message if IDENTIFY DEVICE failed (ticket #61). Add check for empty IDENTIFY data. [CF] Windows installer: Add help message box. [CF] Windows installer: Request admin rights, select 'All Users' section. This fixes shortcut removal under Vista and later. Add '/SO' option to select components for unattended install. Patch was provided by József Fejes. [CF] Windows: Add update-smart-drivedb.nsi NSIS script to build drivedb.h update tool. [CF] Windows: Move search for NSIS compiler from Makefile.am to configure.in. [CF] update-smart-drivedb.in: Move DRIVEDB_BRANCH name creation from script to configure.in. [CF] os_linux.cpp: Replace printf() by pout(). Disable unused function dumpdata(). [CF] Windows: Include CSMI (for Intel RAID) in default DEVICESCAN. [CF] configure.in: Remove info messages about old defaults. [CF] drivedb.h: Set unneeded USB bcdDevice patterns to empty. [CF] Rework USB ID drivedb search. Stop search at first matching entry with empty bcd_device pattern. [CF] Move handling of '-F swapid' from formatting to identity read function. Remove unneeded 'fix_swapped_id' parameters. [CF] smartd: Log warning from drive database if present. smartctl: Do not search drive database twice. [MS] drivedb.h USB updates: - Samsung S2 Portable variant (0x04e8:0x1f08) - Lacie rikiki (0x059f:0x102a) - Toshiba Stor.E Steel series (0x0930:0x0b11) - Super Top generic enclosure (0x14cd:0x6116) [CF] Let constructor of regular_expression throw on error by default. [CF] smartd: Preserve last selective self-test span in '.state' file and use it if the selective self-test log was cleared (ticket #88). [CF] smartctl --scan-open: Make output compatible with smartd.conf (ticket #108). Fix possible crash if autodetect_open() returns new object. [CF] do_release: Re-add signing of tarball. [CF] os_linux.cpp: Change '-d sat' to '-d sat,12' for USB only if kernel is older than 2.6.29. Add kernel release to version info. [CF] smartd: Add '-l scterc,READTIME,WRITETIME' directive (ticket #150). [CF] smartctl: Fix exit status of '-l xerror' and '-l xselftest' (ticket #144). [CF] smartd: Use '-M daily' as default if state persistence is enabled. This avoids that emails are suppressed forever (ticket #35). [CF] smartd: Log identify information of each ATA device. [CF] smartd: Disable '-C' and '-U' monitoring if raw values are very large (ticket #148). [CF] smartd: Write reserved attribute byte to '.state' file (ticket #118). [MS] drivedb.h USB updates: - Seagate FreeAgent Go Flex Desk USB 3.0 - Toshiba Canvio 500GB [MS] drivedb.h USB updates: - Freecom HD 500GB (0x07ab:0xfcda) - Generic JMicron adapter (0x152d:0x2337) - RaidSonic ICY BOX IB-110StU3-B (0x1759:0x500[02]) - Connectland BE-USB2-35BP-LCM (0x040d:0x6204) - Freecom Classic HD 120GB (0x07ab:0xfccd) - OCZ THROTTLE OCZESATATHR8G (0x152d:0x0602) - Vantec NST-400MX-SR (0x1a4a:0x1670) - Intenso Memory Station 2.5" (0x13fd:0x1840) [CF] Don't report failed self-tests outdated by a newer successful extended self-test as errors (ticket #147). This affects smartctl exit status and smartd syslog output and warning email. Only implemented for ATA. [CF] os_linux.cpp: Don't use buffer of size PATH_MAX for the result of realpath(). This also fixes compilation on Debian Lenny. [CF] smartd man pages: Add some missing [ATA only]. [CF] os_linux.cpp: Dereference symlinks before guess of device type (ticket #146). Minor rework of autodetect_smart_device(). [CF] smartctl -l scterc: Don't get ERC if only set is requested. This prevent misleading error messages if ATA output registers are not supported. [CF] Windows: Prevent warnings from gcc 4.5.1. [CF] os_netbsd.cpp, os_openbsd.cpp: Add missing <errno.h> [CF] os_freebsd.cpp: Add missing <errno.h> [CF] dev_legacy.cpp: Add missing <errno.h> [CF] Linux megaraid: Fix pass-through of non-data ATA commands (ticket #149). Only reject commands which require ATA output registers. [CF] configure.in: Remove '-fno-strict-aliasing' from CXXFLAGS. This reverts r2992 (see ticket #23). [CF] Linux megaraid: Avoid strict-aliasing warnings. Patch was provided by Stanislav Brabec (2009-06-03). [MS] Make functions without prototypes static. [MS] Remove unnecessary includes, move inclusion of errno.h from scsicmds.h to the appropriate *.cpp files. Add cciss.h to cciss.cpp. [MS] os_linux.cpp: rename variables to please "-Wshadow" utility.cpp: remove unused variable "start" os_win32/syslogevt.c: plug resource leak [CF] Rename variables to prevent warnings if '-Wshadow' is set. Remove unnecessary includes. Fix some comments. [CF] drivedb.h updates: - Intel X18-M/X25-M/X25-V G2 SSDs: Add firmware bug warning - Samsung SpinPoint M6 - Samsung SpinPoint M7E (AFT) - Samsung PM800 SSDs - Samsung PM810 (470 series) SSDs [CF] Windows: Add experimental CSMI support for disks behind Intel Matrix RAID driver. Accessed through new device names '/dev/csmi[0-9],N'. Experimental DEVICESCAN can be enabled by '-d csmi'. [MS] - ataprint.cpp: adjust print format for insanely large offline data collection times (e.g. WD drives). - getopt: change config.h #include format from angle brackets to quotes [MS] drivedb.h update: - Fujitsu MJA2 BH series - Toshiba MK..59GSXP series (Adv. Format) - Toshiba MK..59GSM series (Adv. Format) - Western Digital Caviar Blue SATA 3.0 variants - Seagate Barracuda XT [CF] smartctl: Print help message if no option is specified (ticket #39). Don't issue any other ATA command if only '-n POWERMODE' is specified. [CF] smartd: Output multiple lines via separate syslog(3) calls (ticket #135). [CF] smartctl: Add new ATA minor revisions and log addresses from ACS-2 revision 4a. Replace runtime asserts by compile time asserts. [CF] smartd: Remove "default: /var/log/messages" hint from warning mail. This obsoletes Debian patch 60_remove-redhatism.diff. [CF] Windows: Include USB devices in DEVICESCAN (ticket #116). [CF] Windows: Use direct WMI access to detect USB IDs (ticket #115). This replaces 'wmic' runs and speeds up USB detection. [CF] configure.in: Rework platform-specific settings. [CF] configure.in: Remove some no longer used settings: -lselinux (duplicate), NEED_SOLARIS_ATA_CODE, OS_FREEBSD. [CF] Makefile.am: Remove SUBDIRS. Recursive targets are no longer used. [CF] Use log directory to check for old error and self-test log support (ticket #89). [CF] drivedb.h USB update: - WD My Book Essential 3TB USB 3.0 [CF] Fix usb header includes for DragonFly BSD (ticket #141). [CF] smartctl: Print physical and logical sector sizes (ticket #62). [CF] drivedb.h updates: - Fujitsu MHT: Add AC variant - Fujitsu MHW2 AC - Samsung SpinPoint T166: Needs '-v 197,increasing' - Seagate Barracuda 7200.11: Add firmware SD81 as buggy - WD Scorpio Blue EIDE: Add 320GB [CF] drivedb.h USB updates: - Samsung S2 Portable (ticket #136) - Move Verbatim 0x152d:0x2351 to JMicron section [AS] drivedb.h updates: - Verbatim Portable Hard Drive eSATA & USB 2.0 Combo 500GB [CF] Happy New Year! Update copyright year in version info. [CF] drivedb.h updates: - Hitachi Deskstar 7K3000 - Hitachi Travelstar 7K320: Add ...362 variant - Seagate Maxtor DiamondMax 21: Add STM3250310AS - Toshiba 2.5" HDD MK..65GSX - WD Caviar Green (Adv. Format): Add 750GB, 2.5TB, 3TB [CF] drivedb.h USB updates: - Micron USB SSD (unsupported, ticket #133) - Samsung G2 Portable (ticket #132) - Samsung Story Station 3.0 (ticket #130) - Seagate FreeAgent GoFlex (ticket #131) [CF] update-smart-drivedb.in: Add workaround for OpenBSD shell bug: 'set -e; if eval false; ...' aborts script (ticket #128). [CF] update-smart-drivedb.in: Add platform specific download tools: 'fetch' on FreeBSD (ticket #127), 'ftp' on OpenBSD. [CF] drivedb.h USB updates: - JMicron 0x152d:0x2509 - WD My Passport 0730 [CF] drivedb.h updates: - Samsung SpinPoint F3 EG: Add 2TB - SandForce Driven SSDs: Add ADATA S599, SuperTalent TeraDrive CT - Seagate Constellation (SATA) - Seagate Constellation ES (SATA) - WDC My Passport: Add WD5000BMVW [CF] drivedb.h update: - Samsung SpinPoint F4 EG: Add 1.5TB, update firmware bug warning. [DG] [SCSI] Fix log page sanity check problem if the DS bit set in response. Caused '-l background' to fail. [CF] drivedb.h updates: - Samsung SpinPoint F4 EG: Warning about bad blocks [CF] update-smart-drivedb.in: Replace ERE by BRE. Script does no longer require GNU sed (Ticket #126). [DG] In '-r ioctl' show vendor specific SCSI commands as such rather than 'unknown'. [CF] Add check for CompactFlash Signature in ATA IDENTIFY data. This avoids that older CF microdrives are detected as ATAPI devices (Ticket #125). [CF] drivedb.h updates: - Apple SSDs TS* - Crucial RealSSD C300 Series - Kingston SSDNow V Series - Indilinx Barefoot based SSDs: Add OCZ-ONYX - SandForce Driven SSDs: Add OCZ VERTEX2-PRO - Transcend CompactFlash Cards: Add TS4GCF133 [CF] Windows installer: Add missing quotes in smartctl-run.bat and smartd-run.bat (Ticket #124). [CF] OpenBSD: Fix DEVICESCAN for OpenBSD >= 4.8 (Ticket #123). [CF] daemon_win32.cpp: Remove duplicate assignment (Ticket #120). [CF] Makefile.am: Do not overwrite existing smartd.conf file (Ticket #122). If smartd.conf exists and differs from the default then smartd.conf.sample is installed instead If smartd.conf.sample exists on uninstall then smartd.conf is preserved. [CF] Linux megaraid: Fix segfault on non-data commands (Ticket #78). The /dev/megaraid_sas_ioctl_node driver does not allow sge_count = 1 and sgl[0].iov_len = 0. [CF] Remove EXPERIMENTAL notes for features already present in 5.39. [CF] Rework '-d TYPE' documentation on man pages. [CF] drivedb.h updates: - Seagate Maxtor DiamondMax 21: Add 80GB - Western Digital Caviar Black: Add 1TB/64MB [CF] drivedb.h USB updates: - iRiver iHP-120/140 (Ticket #119) - ASMedia ASM1051 [CF] Makefile.am: Handle examplescripts in main Makefile. Remove 'examplescripts/Makefile.am'. [CF] configure.in: New option '--with-exampledir' allows to change path of 'DOCDIR/examplescripts' directory. (Debian package uses '/usr/share/doc/smartmontools/examples') [CF] Replace global 'con->dont_print/...' variables by 'printing_is_*'. Remove global 'con'trol pointer. Remove file 'extern.h'. [CF] Replace global 'con->reportata/scsiioctl' variables by '*_debugmode'. [CF] Replace global 'con->conservative/permissive' variables by 'failuretest_*'. Move failuretest() function to smartctl.cpp. [CF] Remove unused CONTROLLER_* defines. [CF] Remove unused controller support from dev_legacy adapter module. [CF] Make 'debugmode' variable local to smartd.cpp. smartmontools 5.40 2010-10-16 [CF] examplescripts/Example3: Use stdin to pass message to 'wall' command (ticket #114). [CF] smartd: Fix setting of SMARTD_DEVICE and SMARTD_DEVICETYPE environment variables (ticket #113). Regression was introduced by rework of smartd data structures. SMARTD_DEVICE is now set to the plain device name. SMARTD_DEVICETYPE is now set to 'auto' if no '-d' directive is specified. Smartctl now accepts '-d auto' for this purpose. [CF] Remove "Lifetime" from Min/Max temperature attribute output (ticket #111). Interval is device specific. [CF] configure.in: Print resource/message compiler info for Windows only. [CF] FreeBSD: Rework get_dev_names_cam() to support more than 26 devices. [CF] drivedb.h updates: - Seagate Barracuda 7200.10: Add 360GB - USB: Iomega MDHD-UE Patch provided by Rob Marissen. [DL] Standby mode not detected properly on FreeBSD (ticket #91). [MS] os_linux.cpp: fix "gcc -flto" build error by including stddef.h [CF] drivedb.h update: - Indilinx Barefoot based SSDs: Add OCZ-VERTEX 1199 and -TURBO [CF] TODO file: Move open entries to tickets #106, #107, #108, #109, #110. Remove outdated entries. [CF] drivedb.h USB update: - SunPlus 0x04fc:0x0c05 [CF] drivedb.h update: - SandForce Driven SSDs: Add Corsair Force, fix typo [CF] Print hex values of unknown self-test type or status. [CF] drivedb.h updates: - SandForce Driven SSDs: Fix regex for Unigen UG99SGC - Seagate Momentus XT series - Quantum Bigfoot: Add 12.7GB [CF] drivedb.h updates: - SandForce Driven SSDs: Add 11 attributes of new FW, add Unigen UG99PGC - WD AV ATA family: Add 250GB, 320GB - WD AV SATA family [CF] Windows: Build syslogevt.exe with MinGW. Now possible because binutils provides windmc. [CF] Makefile.am: Remove install message about smartd startup. It might be misleading because it is not correct for all platforms. [CF] configure.in: Minor fix of '--enable-drivedb' new defaults detection. [CF] Update links, configure and OS info in INSTALL file. Replace tabs by spaces. [CF] configure.in: Fix '--enable-sample' and '--with-selinux'. Fix obsolete use of AC_DEFINE(). [CF] drivedb.h updates: - IBM Deskstar 60GXP, 40GV & 75GXP: Update link (ticket #99) - Seagate Barracuda 7200.12: Add ST31000523AS and others - WD Caviar Black: Add 2TB - WD VelociRaptor: Add 6 Gb/s models [CF] Windows installer: Fix smartctl-run.bat for drive menu (ticket #31). [CF] Windows: Create md5/sha1/sha256 checksums of the binaries. Add checksums.txt file to binary distribution. [CF] Windows: Include drivedb.h into binary distribution. [CF] drivedb.h updates: - Intel X18-M/X25-M/X25-V G2: Add X25-V 40GB - Transcend CompactFlash Cards [CF] drivedb.h updates: - Seagate Momentus 7200 FDE.2: Add ST9160414ASG - Seagate Pipeline HD 5900.1 and 5900.2 Based on patch provided by Marcin Falkiewicz. [CF] Remove unused variable 'reportbug'. [CF] Make function PrintOut() local to smartd.cpp, remove it from smartctl.cpp. [CF] Windows: Improve compatibility with MinGW variants. Add configure check for DDK include files. Drop support for '-mno-cygwin' from old Cygwin gcc. [AS] smartctl.8.in minor update: adding FreeBSD ahci/scsi device hints [CF] Fix build if SVN Id keywords are not expanded (ticket #94). [CF] Windows: Remove "." from DLL search path to prevent DLL preloading attacks. [CF] drivedb.h USB update: - JMicron 0x152d:0x0551 (ticket #95) Add note about port multipliers to smartctl man page. [CF] drivedb.h updates: - SandForce Driven SSDs: Add Unigen drives - Indilinx Barefoot based SSDs: Add ASAX Leopard Hunt II [CF] drivedb.h update: - Intel X18-M/X25-M G2: Add names of timed workload attributes. Document attribute clear command '-t vendor,0x40' on smartctl man page. Thanks to Artem Danielov from Intel for providing the required information and drives for testing. [CF] drivedb.h update: - SandForce Driven SSDs: Add OCZ drives with form factor info. [CF] drivedb.h update: - Intel X25-E, X18-M/X25-M (add X18-M, update attributes) [CF] configure.in: '--enable-drivedb' is now the default. [CF] drivedb.h update: - Indilinx Barefoot based SSDs (combine and update 5 SSD entries using this controller) [CF] drivedb.h update: - SandForce Driven SSDs (Demo Drive, OCZ-Agility2/Vertex2/Vertex-LE) Thanks to Jeremy Werner (jwerner@sandforce.com) from SandForce for providing the required information and a demo drive for testing. [CF] drivedb.h update: - Add 1.5TB drive to SAMSUNG SpinPoint F3 EG series [CF] Add print formats '-v ID,msec24hour32' and '-v ID,raw24/raw32'. Used by SSDs with SandForce controller. [CF] Allow SMART threshold entries at positions different from attribute table. This fixes attribute output for recent SSDs with SandForce controller. [CF] smartctl: Add option '-t vendor,N' to issue ATA command SMART EXECUTE OFF-LINE IMMEDIATE with a vendor specific subcommand. [CF] drivedb.h update: - SAMSUNG SpinPoint V80 series (ticket #85) [CF] Linux: Support SATA drives on LSI 3ware 9750 controllers. Patch provided by Victor Payno (ticket #86). Modified to avoid duplicate code. [CF] drivedb.h update: - SAMSUNG SpinPoint M7 series [CF] drivedb.h USB update: - Buffalo JustStore Portable HD-PVU2 [CF] drivedb.h USB updates: - Iomega LDHD-UP (ticket #83) - WD Elements Desktop 2TB - Maxtor OneTouch (0x0d49:0x7300) [MS] drivedb.h updates: - Intel X25-M SSD first Generation - ExcelStor J8160 - OCZ Agility2 [CF] drivedb.h updates: - Transcend Solid State Drives (ticket #80) [CF] drivedb.h USB update: - LaCie Rugged Hard Drive [CF] smartctl: Add options '--scan, --scan-open'. [CF] Windows: Use also VendorId from IOCTL_STORAGE_QUERY_PROPERTY. [CF] smartd: Change defaults of '-C' and '-U' directives to 0 (disabled) if attribute name is changed by '-v 19[78],...' directive. [CF] configure.in: Fix include path for MinGW. [CF] Move 'posix/reg*' to 'regex/reg*'. Add configure check for regex. [MS] cciss.cpp: avoid redefining be32toh megaraid.h: replace use of undefined preprocessor macro BITS_PER_LONG by union construct (thanks to [DL]). Add assert for sizeof(ptr_t) == 8 (thanks to [CF]). [CF] Makefile.am: Add os_qnxnto.* to EXTRA_smart*_SOURCES. [MS] drivedb.h update: - WD My Passport Essential SE 1TB variant (USB interface) [CF] Use getopt_long() from getopt/getopt* if necessary. Add missing cast to os_qnxnto.cpp. This fixes build on QNX (ticket #1). Thanks to Stefan (stevestereo) for testing. [CF] drivedb.h update: - WD Caviar Green (Adv. Format) family [CF] drivedb.h USB update: - Verbatim External Hard Drive 47519 [DL] Fix regression in smartctl option '-t select,M-N' which prevents that more than one test span can be specified (ticket #75). [CF] drivedb.h updates: - Add raw64 attributes 1, 210-213 to all SSD drives with 64-bit attribute format. [CF] Support smartd '-l xerror' also for disks which use reserved byte as log index. [CF] Fix initialization of values missing in smartd '.state' files. [CF] Add smartd directive '-l xerror' to check error count from the Extended Comprehensive SMART Error Log (ticket #34). [CF] Fix max number of cciss devices, 128 devices are supported again (ticket #49). Regression was introduced during migration to new interface. [CF] Update man pages (include Debian patch 60_remove-redhatism.diff and Debian Bug 570892). [CF] Add SVN revision number to man pages. [CF] Windows: Read default drivedb.h and smartd.conf from exe directory instead of current directory. [CF] drivedb.h update: - SAMSUNG SpinPoint M series [CF] Replace runtime check of byte ordering by compile time check. [CF] drivedb.h USB updates: - ALi M5621 (unsupported) - LaCie with JMicron (ticket #69) - JMicron (0x2352) - Enable 48-bit commands for Hitachi drive [CF] Read USB ID info from drivedb.h (ticket #44). [CF] Create branch RELEASE_5_39_DRIVEDB with last drivedb.h file compatible with smartmontools 5.39[.1]. [MS] drivedb.h updates: - WD Raptor 80GB variant - correct Regex for some WD AV-GP variants - Hitachi Ultrastar A7K2000 - Hitachi Travelstar 5K500.B - Hitachi Deskstar 7K1000.C - adjust naming of Hitachi Travelstar and Deskstar drives [CF] Move 'posix/getopt*' to 'getopt/getopt*'. Can be used for platforms with regex() but without getopt_long() (QNX, ticket #1). [CF] smartd '-l selftest' directive: Print info if error count decreased. Avoid misleading warning if error count decreased to zero (ticket #67). [CF] smartctl: Rework ataPrintMain(). Issue ATA SMART commands only if necessary. Improve handling of SMART STATUS command failure when ATA output registers are missing (ticket #27). [CF] USB ID updates: - A-DATA SH93 - Hitachi/SimpleTech 1TB [CF] configure.in: Print configuration summary. [CF] smartctl -l xselftest,selftest: Print old log if extended self-test log index is out of range. Workaround for bad log data from Intel X25-M G2 (ticket #66). [CF] USB ID updates: - LaCie Desktop Hard Drive - Prolific PL2507 (unsupported) - Seagate FreeAgent Go FW - WD My Book Essential [CF] Linux: Add '/dev/sd[a-c][a-z]' to smartd DEVICESCAN. [CF] smartd: Other config entries may precede DEVICESCAN. Very first step towards a more flexible device scanning. [CF] Windows: Use '.win64' in names of 64-bit binary packages. Use correct 'strip' program when cross-compiling. [CF] Add update script to make targets 'dist' and 'clean', set +x permission, update svn:ignore. [CF] Add 'update-smart-drivedb' script (ticket #59). The script updates the drive database from SVN. It is installed if '--enable-drivedb' is configured. [MS] drivedb.h updates: - Seagate Medalist 1720 - SuperTalent UltraDrive GX SSD - Intel X25-M SSD [CF] Makefile.am: Fix unix2dos and makensis parameters to allow to build the Windows installer on Linux also. [CF] Makefile.am: Use a separate build rule for each man page to avoid compatibility problems with BSD make. [AS] drivedb.h updates: - Fujitsu MHZ2 BK series [MS] drivedb.h updates: - SAMSUNG SpinPoint F3 series - SAMSUNG SpinPoint F3 EG series - SAMSUNG SpinPoint M5 series - Western Digital Caviar Green 6400AADS - more Western Digital VelociRaptor variants [AS] FreeBSD: disable 48-bit commands in the ata_pass_through interface, there is no 48-bit support in the IOCATAREQUEST ioctl. [CF] smartctl: Add option '-l scterc[,READTIME,WRITETIME]' to get/set the SCT Error Recovery Control time limit (ticket #50). Patch was provided by Richard Gregory: http://www.csc.liv.ac.uk/~greg/projects/erc/ Modified for new ata_pass_through() interface. Linux HPT fixes ommitted for now. [CF] Fix SCT temperature table commands on big endian CPUs. [MS] drivedb.h updates: - more Seagate Momentus 5400.6 drives - HP 500GB drive MM0500EANCR [CF] Windows: Cleanup I/O-control declarations, rely on include files if possible. [CF] Windows: Compile fixes for 64-bit exe (EXPERIMENTAL). Update build info in INSTALL file. [CF] drivedb.h update: - Patriot Torqx SSD (patch provided by Gianpaolo Cugola) [CF] Makefile.am: Avoid duplication of man page filter script. [CF] smartd: Add option '-C, --capabilities' if libcap-ng is available (ticket #45). Support is added if libcap-ng is found during build. This can be overridden by configure option '--with-libcap-ng=[auto|yes|no]'. Based on Debian patch: http://patch-tracker.debian.org/patch/series/view/smartmontools/5.39-3/62_lowcap.patch Modified to fix regression (ticket #41, Debian bug 564876). [CF] Bugfix release 5.39.1. [CF] Linux: Fix spin-up of SATA drive if '-n standby' is used (ticket #37). For some reason, this happens if the SCSI/SAT device is opened with O_RDWR instead of O_RDONLY. [CF] Windows: Fix parsing of 'tw_cli' output for 3ware 9.5.x release (ticket #43). [CF] Add USB IDs of Seagate FreeAgent Go, Seagate Expansion Portable and WD My Passport (IDE). [CF] autogen.sh: Fix version regexp, allow automake 1.11.1. [CF] Linux: Allow smartd 'DEVICESCAN -d sat' (ticket #13). Detects (S)ATA devices behind a standard SAT layer (Vendor ID: "ATA "), but not USB bridges with SAT support. Only added for backward compatibility with 5.38. No longer needed as 'DEVICESCAN' without '-d' includes these devices. [CF] Add USB ID of Seagate FreeAgent Desktop. [CF] smartd: Fix directive '-l selftest' (ticket #36) Regression was introduced with r2773. [CF] smartd: Don't disable attribute tracking if read thresholds fails. Windows: Don't return dummy thresholds if IOCTL_STORAGE_QUERY_PROPERTY or 3ware CLI is used to read SMART data. [CF] Windows: Print warning if admin rights are missing. [CF] Replace some 'EXIT(status)' calls by 'return status'. Remove unnecessary casts from 'nonempty()' calls. [CF] Windows: Set ata_device::ata_identify_is_cached() return value according to I/O-control actually used. [CF] Print ATA output registers if SMART status command returns bogus register values. [CF] Windows: Don't return false ATA version info if IDENTIFY data is build from IOCTL_STORAGE_QUERY_PROPERTY result or from 3ware CLI output. smartctl: Handle missing info about ATA version in '-i' output. [CF] smartctl: Don't print log directory if '-q errorsonly' is specified. [CF] smartctl: Fix option '-q, --quietmode' (ticket #11). Regression was introduced with r2807. [CF] drivedb.h update: - SAMSUNG SpinPoint F2 EG series [CF] Add USB ID of Samsung Story Station. [MS] drivedb.h update: - Hitachi Travelstar 5K320: some EA models miss last 2 "0" in model string - Seagate Barracuda LP series [CF] drivedb.h update: - Crucial M225 SSD [CF] drivedb.h updates: - WDC Scorpio Blue Serial ATA (640GB, 750GB, 1TB) - WDC My Passport Essential SE [CF] Add USB ID of Toshiba PX1270E-1G16. [CF] Happy New Year! Update copyright year in version info. [CF] drivedb.h update: - SAMSUNG SpinPoint M40/60/80 series [CF] Add direct access to 48-bit LBA register in 'ata_in/out_regs_48bit'. [DL] drivedb.h updates: - WDC My Passport Essential/USB (capacity 250GB, 400GB & 500GB) [DL] -r ataioctl,2: print text representation of data also (ticket #32) [DL] FreeBSD: freebsd_ata_device::ata_pass_through implemented (part of ticket #18) [CF] drivedb.h updates: - Hitachi Travelstar 7K320 (ticket #28) - Hitachi Travelstar 7K500 [DL] -l gpllog,...: print text representation of data also (ticket #30) [DL] FreeBSD: check reallocf() result for failures [AS] FreeBSD: fixing crash on kFreeBSD (#29), patch provided by Petr Salinger [CF] Makefile.am: 'make check' now tests the syntax of drivedb.h. [CF] Cygwin: Open drive database files in text mode. [CF] Cygwin: Check for 'syslogd' and 'syslog-ng' in initd script. [CF] Windows: Disable Win9x/ME specific code if no longer supported by compiler. [CF] Add '-v ID,FORMAT:BYTEORDER[,NAME]' to specify byte order of attribute raw value. [CF] configure.in: Change --with-docdir default from 'PREFIX/share/doc/smartmontools-VERSION' to 'DATADIR/doc/smartmontools' to make it consistent with --docdir option added in autoconf 2.6x (ticket #24). Autoconf 2.5x is still supported. [CF] Move drive database entries from 'knowndrives.cpp' to new file 'drivedb.h'. This allows to update the drive database from SVN if installation was configured with '--enable-drivedb'. Remove the Makefile target to create 'drivedb.h'. [CF] do_release: Add support to release from a dir below 'branches'. Accept partial checkouts. smartmontools 5.39.1 2010-01-28 [CF] Linux: Fix spin-up of SATA drive if '-n standby' is used (ticket #37). For some reason, this happens if the SCSI/SAT device is opened with O_RDWR instead of O_RDONLY. [CF] Windows: Fix parsing of 'tw_cli' output for 3ware 9.5.x release (ticket #43). [CF] Linux: Allow smartd 'DEVICESCAN -d sat' (ticket #13). Detects (S)ATA devices behind a standard SAT layer (Vendor ID: "ATA "), but not USB bridges with SAT support. Only added for backward compatibility with 5.38. No longer needed as 'DEVICESCAN' without '-d' includes these devices. [CF] smartd: Fix directive '-l selftest' (ticket #36) Regression was introduced with r2773. [CF] smartctl: Don't print log directory if '-q errorsonly' is specified. [CF] smartctl: Fix option '-q, --quietmode' (ticket #11). Regression was introduced with r2807. [CF] Happy New Year! Update copyright year in version info. [DL] FreeBSD: check reallocf() result for failures [AS] FreeBSD: fixing crash on kFreeBSD (#29), patch provided by Petr Salinger [CF] do_release: Add support to release from a dir below 'branches'. Accept partial checkouts. smartmontools 5.39 2009-12-09 [CF] do_release: Commit CHANGELOG and NEWS also. Allow to review changes. [CF] Linux: Add workaround for Adaptec series 2, 5 and 5Z controllers with firmware >= 17380. Patch was provided by Phil Wilson, see: http://linux.adaptec.com/2009/07/24/using-smartmontools-538-with-series-255z-controllers-with-firmware-17380-onwards [CF] configure.in: Add '-fno-strict-aliasing' to CXXFLAGS if supported. This suppresses gcc 4.4.1 warnings on Linux and avoids possible unsafe optimizations (ticket #23). Patch was provided by Manfred Schwarb. [CF] Avoid truncation of configure arguments in '-V' output. [AS] Added USB IDs of WD Passport USB Portable [CF] Linux: Fix segfault in 3ware interface (ticket #22). [MS] knowndrives.cpp updates: - Hitachi Deskstar 7K2000 - Seagate Momentus 7200 FDE.2 series [CF] Add USB ID of WD My Passport 070A. knowndrives.cpp update: - WD My Passport hard drive (USB interface) [CF] smartd: Write 'worst' attribute value to '.state' file also. This allows to use state persistence with 'raw64' attributes. [CF] Rework ATA SMART attribute check in smartctl and smartd. smartd: Ignore normalized attribute value and threshold if 'raw64' or 'hex64' format is selected. [CF] Add USB IDs of Iomega LPHD080-0, 2 Genesys Logic bridges and Initio 316000. [MS] knowndrives.cpp update: Hitachi Travelstar 5K320 series [CF] smartctl: Ignore normalized attribute value and threshold if 'raw64' or 'hex64' format is selected. [CF] knowndrives.cpp updates: - add OCZ-Vertex raw64 attributes - add OCZ-Agility Thanks to Marcin Marszalek for the patch. [CF] Add '-v ID,hex*' print formats. Fix '-v N,FORMAT,NAME' parsing. [CF] Add '-v ID,raw64[,...]' print format based on a patch provided by Marcin Marszalek. [CF] Add '-v ID,RAW_FORMAT[,ATTR_NAME]' option. This allows to add new attributes without the need to enhance the '-v' option. Rework attribute name and raw value formatting. [CF] Fix auto_ptr initialization in linux_scsi_device::autodetect_open(). [CF] Remove duplicate function smart_device_list::add(). Replace calls with push_back(). [MS] attribute update: trim attribute names to 23 chars [CF] Add smart pointer class template to manage device object pointers. Remove related 'delete' calls and 'try/catch' blocks. [CF] do_release: Replace generation of '*.asc' by '*.md5' and '*.sha1'. [MS] attribute updates: - change attributes 202,204,205 to the meanings as found in wdidle3.exe retain old entries as comments (possible Fujitsu use) - add attribute 240 as found in Fujitsu MHY2xxxBH [MS] attributes updates: - attributes 225, 232 and 233 for Intel X25-E SSD - non-conflicting attributes extracted from wdidle3.exe (thanks to Franc Zabkar and Dan Lukes) [CF] Update Windows and ./configure info in INSTALL file. [CF] Update 'do_release' script for SVN. [MS] knowndrives.cpp updates: - Western Digital MyPassport Essential hard drive (USB interface) - Seagate Momentus 7200.4 series - Western Digital Raptor X - Intel X25-E SSD [CF] knowndrives.cpp updates: - New Seagate 7200.11 firmware version - Update IBM link [CF] smartctl: Use printf() instead of pout() for exception error messages to avoid access to bogus 'con->dont_print'. [CF] smartd: Add missing help texts for '-A', '-B' and '-s'. [CF] Add missing check for log page 0x11 support to smartctl '-l sataphy' option. [CF] Add USB ID of Freecom Hard Drive XS. [AS] Linux: Autodetect DELL PERC and MegaRAID controllers. Hiding debug messages coming from megaraid code. [AS] Linux: Fixed SATA drives support on megaraid device (see ticket #15). [AS] FreeBSD: Removed all old detection code, moving everything to the objects. Now we are using CAM/ATA enumerators to guess device type. [AS] FreeBSD: Added autodetection for the ada disks (untested). Code for USB device detection refactored. [AS] FreeBSD: cam_get_umassno rewritten using XPT_PATH_INQ [AS] FreeBSD: do not open/close cam device on every request for SCSI disks. Use com->camdev both for SCSI and ATAPICAM. [AS] FreeBSD: added support for the ada disks, based on agapon patch [CF] Add names for attributes 184 and 188, see ticket #17. [CF] configure.in: Change configure date syntax. Add message to '-mno-cygwin' option check. [GK] Add names for some attributes used in MLC flash drives: 175, 176, 177, 181, 182 [CF] Windows: Check support of gcc '-mno-cygwin' option in configure. This option has been removed in Cygwin gcc 4.x. Update INSTALL instructions accordingly. [CF] Increase SCSI_TIMEOUT_DEFAULT from 6 to 20 seconds to avoid timeouts when a disk spins up from standby mode. [CF] Add USB ID of AcomData 504 (OnSpec USB bridge). [AS] Correcting manual pages (FreeBSD related) [AS] FreeBSD: fix FTBFS on GNU/kFreeBSD (reported by derevko). [AS] FreeBSD: Add USB autodetection to smartd DEVICESCAN directive. [CF] Add USB ID of Myson Century CS8818, add some comments. [CF] Return info strings from 'smart_interface::get_*()' functions as 'std::string' instead of 'const char *'. Static buffers are no longer needed. [SZ] FreeBSD: Fix highpoint type detection and ioctl failed for parameter error. [CF] Linux: Add USB autodetection to smartd DEVICESCAN directive. [CF] Add USB IDs of Maxtor Basics Desktop and ISD-300A1. [AS] Use malloc() to ensure that the read buffer lands on a single page. This avoids some bugs seen on LSI controlers under FreeBSD. [CF] Add missing help text for '-d usb*' options. [CF] Linux: Dereference '/dev/disk/by-*/*' symlink before device type autodetection. [AS] FreeBSD: Support SATA disks attached to a SAS controller (based on patch from freebsd ports tree). [AS] FreeBSD: Added FreeBSD 8 libusb2 device autodetecion, new configure check for -lusb. [AS] FreeBSD: Added USB device autodetection and fixed -d switch behavior. [AS] FreeBSD: Migrate os_freebsd.cpp to new interface. [CF] Fix max number of 3ware devices, 128 devices are supported again. Regression was introduced during migration to new interface. Thanks to Michael Holweg for the problem report. [CF] Windows installer: Add 'DisplayVersion' to uninstall registry key. [MS] knowndrives.cpp updates: - Marvell SSD SD88SA024BA0 - Fujitsu MHZ2 BH series - Fujitsu MHZ2 BJ series - Seagate Maxtor DiamondMax 23 - WD Caviar Green: Add some 32MB cache variants - relax OCZ-Vertex pattern [CF] Add USB ID of Verbatim FW/USB160. [CF] Fix data type bug in checksum test for multi sector logs. [CF] Add USB ID of Seagate FreeAgent Go. [MS] Add experimental feature to log attribute values at each check cycle (ATA only), activated with the smartd option "-A PREFIX" / "--attributelog=PREFIX". Introduce configure options "--enable-attributelog" and "--with-attributelog=PREFIX" to enable feature by default. [DG] [SAT] Heads up about a non backwardly compatible change introduced in draft SAT-2 (sat2r8b.pdf) that will break our existing SAT processing code. Action needed if change stands. [MS] smartd.cpp: Adjust umask [CF] Makefile.am: Remove 'uninstall-docsDATA' target to fix 'make distcheck' with automake 1.11. The 'make uninstall' of examplescripts fails if docdir does no longer exist. [CF] Remove 'scsiata.h'. The 'scsiata.cpp' module now implements parts of 'dev_interface.h'. [CF] smartctl: Don't report an attribute as failed if threshold is 0. [CF] Print only one warning on checksum errors in multi sector log. Remove casts from calls of checksum(). [DG] minor changes to SCSI background scan strings [MS] knowndrives.cpp updates: - Fujitsu MHW2 BJ series - WD Caviar Black family [MS] Makefile.am: Make creation of svnversion.h independent of locale settings [CF] Require to specify PORT parameter of '-d usbjmicron' if two disks are connected. [CF] smartctl: Limit default number of printed entries for '-l xerror' to 8, for '-l xselftest' to 25. [CF] smartctl: Fix number of entries in '-l xselftest' output. [CF] Add USB IDs of a SunplusIT bridge, three WD drives, and an unsupported Iomega drive. [CF] Makefile.am: Use 'svnversion' instead of 'svn info' to get the revision number. This also checks for mixed and modified working copies. [CF] Remove CVS Id strings from '-V, --version' output. [CF] Update CONTRIBUTORS section on man pages. [CF] Makefile.am: 'make maintainer-clean' now removes also files generated by './autogen.sh'. [CF] Invalidate 'do_release' script, it needs some rework for SVN. [CF] Update documentation files for SVN. [CF] Rename trunk/sm5 to trunk/smartmontools. [CF] Print SVN revision number instead of time in version info line. Get SVN revision number from svn (if available) or guess from Id strings. Rename generated file to svnversion.h. [CF] Makefile.am: Modify generation of cvsversion.h for SVN. [GP] Convert CVS repository to SVN. [CF] smartd: Fix size of monitor flag array from previous commit. [CF] Makefile.am: Add missing 'megaraid.h'. [CF] smartd: Add '!' flag to '-r' and '-R' directives. If specified, message is logged as LOG_CRIT and warning mail is sent if attribute normalized or raw value changes. [CF] Replace global 'con->...' variables used for selective self-tests by local variables. [GK] Add names for some attributes used in Samsung MLC drives: 178-180 & 183 [CF] smartctl: Add option '-x, --xall' to print all info including extended SMART logs and non-SMART info. [CF] smartctl: Add '-l xerror,error' and '-l xselftest,selftest' to print the old logs if the extended logs are not supported. [MS] knowndrives.cpp updates: - Western Digital AV-GP series - Transcend Solid-State Drive and Transcend Solid-State Drive V series - Seagate Momentus 5400.5 series [CF] Disable 48-bit ATA commands for JMicron USB bridges by default because these commands do not work with all devices. Add '-d usbjmicron,x' to enable 48-bit commands. Thanks to Alexander Shaduri for the problem report. [CF] smartd: Don't ignore the '-n' directive when a self-test is scheduled. Start the self-test later when the disk is active again. [DG] SCSI (SAS): implement '-l sasphy,reset' (reset part was stub prior to this) [DG] add 'ATA, SCSI command sets and SAT' section to smartctl.8 . [SCSI] add 'number of background medium scans' field [DG] SCSI (SAS): add '-l sasphy' and '-l sasphy,reset' into smartctl to output SAS device phy information (from the Protocol specific log page) [CF] autogen.sh: Remove 'CYGWIN=check_case:strict', this does no longer work on Cygwin 1.7. Print warning if Automake version cannot handle case insensitive filesystems. [CF] Remove '#define TRUE/FALSE', use 'bool' and 'true/false'. [CF] Add 'options' parameter to SCSI printing routine. Move global 'con->...' smartctl variables to 'options' parameters of printing routines. [CF] Windows: Remove outdated entry about undocumented system calls from WARNINGS file. [CF] Print General Purpose Logs even if GPL feature bit is missing. Needed for some older disks which implement READ LOG EXT but do not report the GPL feature set. Change order of the extended log outputs ('-l xerror', '-l xselftest', '-l sataphy'). Extended logs are now printed before their old versions. [CF] autogen.sh: automake 1.10.2 and 1.11 are OK. [CF] Fix syntax error in prototype of 'safe_snprintf()'. Thanks to Alexander Shaduri for bug report and patch. [DG] SCSI: Fetch load-unload cycle counts. [CF] Windows: Add Win-7 and Win2008 to get_os_version_str(). [CF] smartd: Fix '-M test' directive in conjunction with '-s' option. Thanks to Matthias Becher for the problem report. [MS] knowndrives.cpp updates: - Add Seagate Barracuda 7200.12 series - Add Seagate Momentus 5400.4 series - Add Hitachi Deskstar 7K1000.B series - Add Transcend SSD TS32GSSD25-M - Add OCZ Vertex 1199 [CF] knowndrives.cpp updates: Add Samsung S250 series. Add '-v 198,increasing' to Samsung P80. Replace '#if/#endif' by comment to fix configure option '--enable-drivedb'. [CF] knowndrives.cpp update: Add Seagate 7200.11 with 'CC' firmware which is unaffected by the bug. Thanks to Bas Mevissen for the patch. [CF] Replace global 'con->...' variables used for drive presets by local variables. [CF] Simplify '-v' vendor attribute option parsing. Add '-v 197,increasing' and '-v 198,increasing' options to specifiy that an uncorrectable count is never reset. This modifies the printed attribute names and smartd's default setting of '-C' and '-U' directives. Both '-v' options can also be preset in the drive database. [CF] Add '+' modifier to smartd '-C' and '-U' directives. If specified, a warning is only printed if the raw value increases. [CF] Add smartctl option '-l xselftest[,NUM]' to print ATA SMART Extended Self-test Log (GP Log 0x07). [CF] Add experimental option '-d usbsunplus' for drives behind SunplusIT USB bridges. Tested on WinXP with SPIF215(?) in TrekStor DataStation maxi m.u.. Many thanks to SunplusIT tech support for providing the required information. [CF] Windows: Provide a non-console version of smartctl.exe as smartctl-nc.exe. This prevents that a new console is opened when smartctl is run from a GUI program with stdio redirected. Used by GSmartControl (http://gsmartcontrol.berlios.de/). [CF] Remove support for platforms without getopt_long() in smartctl.cpp and smartd.cpp. If getopt_long() is missing, ./configure aborts with an explanatory message. For now, short option help texts are only removed from os_linux.cpp and os_win32.cpp. HAVE_GETOPT_LONG is still defined in config.h. [CF] Add smartctl '-d test' option to print the result of the device type detection. [CF] Enhance USB device type autodetection, use bcdDevice if known. Add Cypress CY7C68300B/C (AT2LP) to the table. [CF] Linux: Add experimental USB device type autodetection. Uses USB ID info found through symlink "/sys/block/sdX/device". [CF] Windows: Add experimental USB device type autodetection. Uses WMI command line tool 'wmic' to query USB ID. [CF] Add function smart_interface::get_usb_dev_type_by_id() to map USB vendor:product IDs to '-d type' names. Can be used by platform dependent layer to autodetect USB devices if ID of USB bridge is known. [CF] smartd: Log changes of self-test execution status if '-l selftest'is specified. [CF] knowndrives.cpp update: Samsung SpinPoint F1 RE series [MS] knowndrives.cpp update: Seagate Momentus 5400.6 series [CF] Add forgotten SCSI sense checks to class usbjmicron_device. [CF] Add new SMART STATUS check command for JMicron USB bridges. Should support also older chip versions and prevents a race condition. [CF] Windows: Fix win_scsi_device::scsi_pass_through() for single byte data transfers. Required for JMicron SMART STATUS check. [MS] knowndrives.cpp update: Add Hitachi Travelstar C4K60 family (1.8" slim drives) [MS] Workaround for huge raw values of attribute 9, needed for Hitachi Travelstar C4K60. For the Power_On_Minutes case, clip the display to 4 bytes and show the remaining part, if existent, in parens. [CF] Add experimental option '-d usbjmicron[,PORT]' for drives behind JMicron USB bridges. Tested on WinXP with JM20336 in AixCase AIX-ESU35CD. Many thanks to JMicron tech support for providing the required information. [MS] knowndrives.cpp update: Add WD Caviar Green 8MB and 32MB cache variants, stretch to 2TB. [CF] knowndrives.cpp updates: Add more entries for Samsung P80 disks with old and unknown firmware. Remove old entries which would match any new Samsung model reusing old firmware version number. [CF] Windows: Add a workaround for missing multi-sector support for ATA READ LOG EXT command. [CF] Fix Extended Comprehensive Error Log index base. Add workaround for Samsung disks using reserved byte as index. [CF] knowndrives.cpp updates: Update bug warnings for Seagate 7200.11, ES.2 and DiamondMax 22. Add new entries for fixed firmware versions. [CF] Add smartctl option '-l xerror[,NUM]' to print ATA SMART Extended Comprehensive Error Log (GP Log 0x03). [MS] knowndrives.cpp update: Added remaining WD Scorpio Blue SATA II drives [CF] Minor fix to remove ID 0 from 'smartctl -l sataphy ...' output. [CF] knowndrives.cpp updates: Add warnings about possible firmware bugs to Seagate 7200.11, ES.2 and DiamondMax 22 entries. [CF] knowndrives.cpp updates: Add Samsung SpinPoint F1 series. [CF] Windows: Fix return value of scsi_pass_through(). Regression was introduced during migration to new interface. SAT over USB now works on XP (both '-d sat,12' and '-d sat,16'). [MS] knowndrives.cpp updates: - Added Western Digital RE2-GP family - Added Hitachi Travelstar E5K160 family - Allow uppercase variants of Hitachi 5K160 drives [CF] Fix smartctl crash on '-l directory,[gs]'. Allow to override missing GPL feature bit or missing log dir entry with '-T permissive' option. [SZ] os_freebsd.cpp, os_freebsd.h updates: Support HighPoint RocketRAID controller under FreeBSD [MS] knowndrives.cpp updates: - Added Western Digital RE3 32MB cache variants - Added WD Caviar Green 32MB cache variant (WD10EADS) - Added WD Scorpio Black family [DG] Accept half healthy (and half unhealthy) indication from the SMART RETURN STATUS. This makes allowance for SAT implementations (e.g. via USB) that truncate the SCSI sense buffer to 18 bytes. This truncation causes the SMART RETURN STATUS indication to be half health or unhealthy. If the half indication is used, then warn if '-r ioctl' is given. [MS] knowndrives.cpp updates: - Added Apple SSD - Added Seagate U8 family [DL] os_freebsd.cpp: Added support for CHECK_POWER_MODE and WRITE_LOG commands [MS] knowndrives.cpp update: There seem to exist WD Raptors with SATA II interface, add them. [MS] knowndrives.cpp updates: - Added remaining Seagate Barracuda 7200.11 drives - Added HP 1TB SATA disk [MS] knowndrives.cpp updates: - Added Maxtor 92040U6 (DiamondMax Plus 6800) - Added Seagate Maxtor DiamondMax 21 500GB version - Added QUANTUM FIREBALLlct15 22 - Added QUANTUM FIREBALL CR6.4A - Added QUANTUM FIREBALLP LM20.4 - Added SUN branded Toshiba MK4019GAX - Added TOSHIBA MK1016GAP and relatives: MK1[05]1[67]GAP - Added Western Digital WD800AB and WD2500AB - Some Hitachi 7K160 drives have garbage at end of name: permit it [CF] Add smartd '-n powermode,N' directive parameter to limit the number of skipped checks. Thanks to Michal Hlavinka for the patch. [MS] knowndrives.cpp updates: - Added Hitachi Endurastar J4K30/N4K30 - Added Hitachi Travelstar 4K120 series - Some Hitachi 7K80 drives have garbage at end of name: permit it - IBM Travelstar 6GN series [MS] knowndrives.cpp updates: - Added Quantum Fireball ST4300A - Added Asus-Phison SSD (solid state disk) - Added Seagate DB35.3 Series - Added remaining disks of the Seagate SV35.2 Series [MS] Fix trivial compile error with "-pedantic" [MS] Workaround for huge raw values of Reallocated_Sector_Ct and Reallocated_Event_Ct for newer Fujitsu disks (only the lower 16 bits seem to be meaningful). Clip the display to 16 bits and show the remaining part, if existent, in parens. Patch by [CF]. [CF] smartd DEVICESCAN: Fix autodetection of SAT devices. Thanks to Stanislav Brabec for bug report and testing. [MS] knowndrives.cpp update: Convert file to full string regex: remove "^$" from pattern [MS] knowndrives.cpp updates: - Added Seagate Momentus 5400 PSD series (hybrid drives) - Added Seagate Momentus 7200.3 series - Added Hitachi Deskstar 7K250 (SUN branded) - There are Hitachi Travelstar 5K250 drives with capital "HITACHI" - Correct regex for Maxtor VL 30 drives [CF] Add configure options '--enable-savestates' and '--with-savestates=PREFIX' to enable smartd persistence ('-s' option) by default. [CF] smartd: Add '-s ([cnr]/../.././..)' directive to run scheduled selective self-tests. Useful to perform full tests of large disks not running 24x7. [CF] Allow to read local drive database entries from optional file '${sysconfdir}/smart_drivedb.h'. Add configure options '--enable-drivedb' and '--with-drivedbdir=DIR'. If specified, drive database is read from '${drivedbdir}/drivedb.h'. (default '${prefix}/share/smartmontools/drivedb.h'). This file is build from knowndrives.cpp. [MS] knowndrives.cpp updates: - Added 640GB variants of Western Digital AAKS and AACS drives - Added Western Digital AV ATA family - Added 160GB variant of Hitachi P7K500 - Added 500GB variant of Hitachi 7K1000 - Some cleanup for Quantum disks - Added Seagate Maxtor DiamondMax 22 family [CF] Use full string match for regexp in drive database. [CF] Add option '-d sat+TYPE' to use SAT with controllers which require option '-d TYPE'. Should work with '-d sat+megaraid,N'. As a side effect, '-d usbcypress+TYPE' is also supported. [CF] Add parser to read drive database from a file. Add '-B' option to smartctl and smartd to specify database file name. File syntax is identical to the C/C++ syntax used to inialize the internal database array. [CF] New syntax for drive database: Specify presets by strings with '-v' and '-F' options. Use empty strings instead of NULL. [JPH] Added Linux support for viewing disks behind MegaRAID controllers [CF] smartd: Improve min/max temperature recording in conjunction with '-s' option. [CF] Add a wrapper class for FILE *. [CF] smartd: Add experimental support for state persistence (ATA only). Add option '-s' to specify path prefix for state files. Rework scheduled self-test detection to support persistence. If any test schedules are within downtime, the highest priority test is run after next startup. [CF] Remove casts from 'format_ata_string()' calls. [CF] Minor changes to fix errors and warnings from Cygwin gcc 4.3.0. [CF] smartd: Remove SCSITIMEOUT code. According to smartd.h 1.54 CVS log from 2003-10-27, it did never work. [CF] Remove dependencies ataprint.cpp and scsiprint.cpp from smartd. Move common ATA functions from ataprint.cpp to atacmds.cpp. Module scsiprint.cpp was apparently never used in smartd. [CF] Move smartd local declarations from smartd.h and utility.h to smartd.cpp. Remove smartd.h. [CF] Fixed extra '\n' in "Offline data collection status" output. Thanks to Alexander Shaduri for the patch. [CF] smartd: Separate device configuration data from device state data. Use references instead of pointers for configuration and state data. [CF] Add const-correctness and static to ATA support functions. [CF] Add a wrapper class for regex. [CF] Simplify 'create_vendor_attribute_arg_list()'. [CF] smartd: Rework of main data structures. Remove explicit memory allocations, use STL containers and structs with value semantics instead. Remove old malloc/free based memory management helper functions unless old interface is still in use. [CF] Linux: Cleanup device scan, remove name list, create objects directly. [CF] Linux: Cleanup smart_device::open(), type strings are no longer used. [CF] Remove CONTROLLER_* defines and variables unless old interface is still in use. [CF] Linux: Migrate 3ware interface to 'ata_pass_through()'. Multi-sector support is not complete yet. 48-bit commands possibly work. WARNING: Not tested, please review code before first test! [CF] Linux: Migrate os_linux.cpp to new interface. [CF] Add direct access to 16-bit registers in 'ata_in/out_regs_48bit'. [CF] Add 'ata_cmd_is_ok()' parameter check, remove 'ata_pass_through_28/48bit()' functions. [CF] Add CVS date/time from cvsversion.h to man pages also. [CF] Add configure option '--with-os-deps='os_module.o ...' to specify alternate OS interface modules. Useful for testing during migration. [CF] Remove declarations of 'optarg', 'optind', ..., include <unistd.h> instead. This fixes 'auto-importing' linker warnings on Cygwin. [CF] Add '-l sataphy[,reset]' to print SATA Phy Event Counters. [CF] Add '-l gplog,ADDR[,FIRST[-LAST|+SIZE]]' and '-l smartlog,...' to dump any log page accessible via GP or SMART read log commands. [CF] Enhance '-l directory' to print both GP and SMART Log directories. Add '-l directory[,gs]' modifiers to select GP or SMART log. Enhance 'ata_cmd_in' parameter struct for 48-bit commands. [CF] Windows: Add full ATA pass through support including 48-bit commands. [CF] Windows: Migrate os_win32.cpp to new interface. [CF] SAT: Add full ATA pass through support including 48-bit commands. [MS] knowndrives.cpp update - Added FUJITSU MHZ2250BS G2 and family [MS] knowndrives.cpp updates - Added Maxtor DiamondMax 60 94098H6 - Added Maxtor DiamondMax 1280 84000A6 and family - Added Maxtor DiamondMax VL 30 31536H2 (ATA100) and family - Some Seagate Barracuda 7200.9 have garbage at end of name: permit it - Added Seagate Barracuda ATA ST320430A and family - Regression from previous checkin: add WD RE2 WD...0ABYS again - Added WD RE3 WD5002ABYS and family - Added Quantum Fireball CR13.0A - Added Hitachi Travelstar 5K250 HTS542525K9SA00 and family - Added WD AC420400D and add whole range of AC.... which have 5400rpm or higher (i.e. PIO-only drives omitted) [MS] knowndrives.cpp updates - WD: Separated entries for EIDE and SATA - WD: Separated entries for Caviar SE, SE16, RE, RE2 - WD Named: WD Caviar AC series - WD Renamed: WD Caviar RE/RE2 -> WD RE/RE2 - WD Renamed: WD Caviar SE/SE16 WD....AA[A-Z][A-Z] -> WD Caviar Blue - WD Renamed: WD Scorpio WD....BEV[A-Z] -> WD Scorpio Blue - Added WD Scorpio Blue WD3200BEVT - Added WD RE2 WD5001ABYS and family - Added WD Caviar Green WD5000AACS and family - Added WD VelociRaptor WD3000GLFS and family - Added Seagate Barracuda ES.2 ST31000340NS and family - Added Samsung SP80A4H - Added Maxtor DiamondMax 21 STM3160215AS and STM3320620AS - Added Seagate Barracuda 7200.7 ST380819AS - Added Maxtor DiamondMax 10 6B100P0 - Added Seagate SV35.2 Series - Added Fujitsu MHY2120BH and family - Added Fujitsu MHW2080BH PL (PL variant) - Added Toshiba MK3252GSX and family [BA] Fix smartctl bug: when running in silent mode '-q errorsonly' do not print the Selective Self-test log. Any errors will ALREADY appear in the SMART Self-test log. [CF] Add missing 'const' and other minor fixes to prevent gcc warnings. [OB] Added information message about supported Areca firmware versions. It's displayed in case the ATA device identification fails. [CF] Add configuration file for Doxygen. [CF] Add new object oriented interface to access ATA and SCSI devices. smartctl and smartd are modified to use the new classes in 'dev_interface.{h,cpp}'. The template class in 'dev_tunnelled.h' is used in 'scsiata.cpp'. The code in 'dev_ata_cmd_set.{h,cpp}' supports migration from old function 'ata_command_interface()'. All existing 'os_*.cpp' modules should still work without any changes. The required adapter classes from 'dev_legacy.cpp' are automatically added by configure if necessary. [BA] Updated smartd and smartctl and smartd.conf man-page documentation to reflect support for Areca SATA RAID controller cards. [OB] Added support for Areca controllers to smartd. Extensive tests as well as documentation are still pending however. [OB] Implemented device locking for Areca controllers in smartctl [BA] Fixed selective self-test code. Data structure revision number may be != 1 if no selective self-test has ever been run. Host MUST set this value (at least at the first selective self-test instance). Thanks to Curtis Stevens of WDC for clarification. [MC] usbcypress autodetection [BA] Starting to commit Areca code. For now just smartctl. More changes and documentation coming soon. Need Areca firmware version 1.45 dated 10 June 2008 or later. May need changes in opening /dev/sg and file locking. Many thanks to Hank Wu! [CF] smartd: Fix too small name buffer for 3ware with >100 devices. [JH] now C++ Support for QNX Target already tested for QNX 6.3.2 on x86 and armle target [CF] Allow to set BUILD_INFO from make command line. [CF] Windows: Add MSVC8 support, remove MSVC6 project files. [MC] Add usbcypress device support for smartd. [CF] Add output of latest CVS date/time stamp to version info. New file cvsversion.h is generated by Makefile. Move formatting of version info to utility.cpp. [AR] Fix bug in 3ware node creation where nodes would be created then deleted, then recreated. [BA] Add missing CCISS cvs version tags to '-V' printouts. [TS] Linux: Ensure the 3ware device nodes are created with a correct SELinux security context. [AR] Add support for up to 128 devices on 3ware controllers. [CF] C++: Added new main() with exception handlers, replaced exit(x) with throw(x), removed global variable 'exitstatus'. Necessary for future changes, because exit() does not call any destructors. [SS] FreeBSD: plug file descriptor leak in smartd (only happens with CISS devices). Reported by Vadim Ostranitsyn. [SS] FreeBSD: allow smartctl to interact with SCSI /dev/pass devices, thus enabling it to work with RAID controllers that expose disks via these devices. From scottl@ via FreeBSD ports. [MC] Add usbcypress device support for smartctl. [KS] INSTALL on Solaris: updated description to use C++ compiler. [KS] configure.in on Solaris: added options for Sun's compiler to suppress trivial warnings. [KS] configure.in on Solaris: added direction to search suitable libraries for getaddrinfo(). [TS] smartd on Linux: remove forgotten return from deviceopen(); SCSI device descriptors had the FD_CLOEXEC flag unset. [CF] Added 'const' to avoid warning on depreciated string constant to 'char *' conversion. [CF] autogen.sh: automake 1.10.1 is OK. Updated message texts. [BA] removed smartmontools.spec file (now in CVS Attic). This was not being used by RH or FC anyhow, and was out of date and not maintained. [BA] smartd on Linux: sets FD_CLOEXEC on the opened device file descriptor. The descriptor is otherwise leaked to other applications (mail sender) which may be considered a security risk and may result in AVC messages on SELinux-enabled systems. Thanks to: Tomá Smetana" <tsmetana@redhat.com>. [BA] smartd: when sending email, to gather information about the host for the body of the email, eliminate gethostbyname() in favor of the IPv6-friendly function getaddrinfo() if the latter is available. Info may be found here http://udrepper.livejournal.com/16116.html and here http://people.redhat.com/drepper/userapi-ipv6.html Thanks to: Tomá Smetana" <tsmetana@redhat.com>. Smartmontools developers: please check that smartd still LINKS properly on your systems. [BA] Fix ugly syntax bug in os_freebsd.cpp. How did this go undetected for so long?? SMARTMONTOOLS STABLE RELEASE 5.38 2008/03/10 [KS] Solaris/x86: modified configure.in for Sun's compiler. [BA] smartd.initd.in addition from Erwan Velu <erwan@seanodes.com> [BA] smartd fixes: - On Linux, DEVICESCAN now automatically recognizes SATA devices behind libata, and SATA devices behind the Marvell driver, and treats them correctly. - On Linux, a '-d sat' or '-d marvell' is automatically added if libata or the marvell driver are recognized behind a SCSI device type [SS] (Maybe) fix attribute autosave in FreeBSD. [SS] Major NetBSD-specific bugfixes: - handle actual SCSI and ATA errors and not only ioctl() errors; - set up I/O request properly for AUTO_OFFLINE and AUTOSAVE commands (inspired by similar change in os_freebsd.cpp); - handle AUTO_OFFLINE and AUTOSAVE like STATUS_CHECK (like os_linux.cpp does). [GG] add kfreebsd gnu support to configure.in [BA] Fix auto-offline support in FreeBSD. Thanks to Cyrus Rahman <crahman@gmail.com> for the patch, and Eduard Martinescu for blessing it. [DG] smartd re-opens "SCSI" devices as ATA devices if a SAT layer is detected (smartd bug IMO). In Linux this upsets scsi generic device nodes (e.g. /dev/sg0). Detect the re-open in os_linux.cpp and set the O_RDWR flag (ATA uses the O_RDONLY flag). [CF] Drive database: Added Fujitsu MHW2 BH, Maxtor DiamondMax 17, 20, 21, Hitachi Travelstar 4K40, 5K120, 7K200, Deskstar 7K160, T7K500, T7K1000, Toshiba 1.8", Seagate Momentus 5400.3, 5400.3 ED, 7200.2, Barracuda 7200.11 and ES. Updated Toshiba 2.5", Seagate Barracuda 7200.9 and 7200.10. Added missing "(Hitachi )?" to Travelstar entries. [CF] Drive database: Added several Western Digital Caviar and Scorpio drives, added Caviar RE EIDE family. [CF] Drive database: Added Samsung P80 series with *-25 firmware. [CF] Replaced 'head [-n] -1' by 'sed 1...' in autogen.sh to avoid portability issues. [BA] Fixed autogen.sh script so that it uses 'grep -n 1' if 'grep -1' fails. Needed for Mac OS X 10.4. Uck. [CF] Windows: Added IOCTL_STORAGE_PREDICT_FAILURE. This allows access to ATA SMART status and data if other calls do not work. Thanks to Jaroslaw Kowalski for pointing this out. Added support to use this function without admin rights. [CF] Added ATA-8 revision 4c message text. [CF] Added compiler.h to cciss_ioctl.h header check to prevent configure warning. [SS] DragonFly support added (using os_freebsd code; untested). [CF] smartctl: Fixed ATA identify byte swapping issue on big-endian platforms. This regression was introduced by the change for '-F swapid'. Thanks to Matthew Butch for bug report and testing. [DG] SAT/SCSI: Improve SAT error processing code. Aborted commands from ATA devices (typically because SMART was disabled) were not being properly detected. [GG] smartd: wait for the pid file to show up, return an error if it doesn't [JH] fix bad return code (get STATUS) for QNX Part [JH] initial porting to QNX Neutrino 6.3.2 need at this time a prerelease devb-eide driver and libcam.so.2 only tested for X86 Target, but devb-eide and lobcam.so.2 available for X86/ARM the officional driver coming soon with the next QNX release create two new source files os_qnxnto.[c..h] [CF] smartd: Added option '-n, --no-fork' so that smartd works better with modern init methods. Thanks to Enrico Scholz for the patch from 2005-12-24. [CF] Windows: Improved ATA/SCSI device type detection and DEVICESCAN. This also fixes a regression in 3ware DEVICESCAN. [CF] smartd: Don't start self tests in first pass to avoid performance problems during boot. https://bugzilla.novell.com/show_bug.cgi?id=192591 [CF] Fixed regression in SMART STATUS command on Win9x/ME. [BA] Fixed 3ware issue with new controllers. Documentation said that one could address up to 24 disks on a single controller, but in fact one was limited to 16 disks. This is now fixed: up to 32 disks can be addressed. Thanks to Adam Radford. NOTE1: I have patched the Linux and FreeBSD code but not modified the Win32 code (it already supports up to 32 disks). NOTE2: NOT TESTED ON LINUX. Do not use this on a production box! I will remove this NOTE2 as soon as some positive test reports are recieved. NOTE3: NOT TESTED ON FREEBSD. Do not use this on a production box! I will remove this NOTE3 as soon as some positive test reports are recieved. [CF] Windows installer: Added explorer drive menu, CMD window, UBCD4Win plugin, smartd service update and other minor improvements. [CF] Windows: Modified drive letter handling for explorer drive context menu: try SCSI if type is unknown, allow 'X:\.' syntax. [CF] Windows: Added automatic ATA/SCSI device type detection and SCSI device scanning. The device names '/dev/sdX' and '/dev/pd<n>' now work for both ATA and SCSI disks. [CF] smartctl: Added ability to parse '-r ataioctl,2' output from stdin ('-') and simulate the ATA commands for testing purposes. [BA] SMART Attributes: added 187, 189, more accurate name for 190. [CF] Windows: Added drive letters 'X:' as alternate disk device names. [CF] smartctl: Added '-F swapid' to fix ATA identify string byte ordering. Added '-q noserial' to suppress serial number output. [CF] Windows: Added '/dev/n?st<n>' as alternate device names for SCSI tapes. These names are also used by Cygwin's /dev emulation layer. Thanks to Corinna Vinschen (Cygwin project lead) for pointing this out. [CF] Windows: Added IOCTL_SCSI_MINIPORT_*SMART* for commands not handled properly by SMART_IOCTL in disk class driver. This allows to use READ_LOG, WRITE_LOG and ABORT_SELFTEST even if the driver does not support ATA_PASS_THROUGH. [CF] Added ATA-8 revision 4, fixed WRITE LOG '-r ioctl' output. [BA] Updated smartctl and smartd so that they can be used with the latest 3ware controllers which have 24 ports. Also updated docs. Thanks to Tim Bell at CERN. [GG] bit 4 in smartctl's return code might be set even when the dist check didn't return "DISK OK" [CF] Drive database: added '-F samsung3' for Samsung P80 firmware BH100-35. [SS] Applied patch from Dean Bennett to fix scheduled tests on Highpoint RAID controllers. [BA] Added patch from Tejun Heo http://thread.gmane.org/gmane.linux.ide/13222/focus=13235 to fix broken auto-offline and auto-save via libata. Very clean fix: does it "the right way". Thanks Tejun! [CF] Added message text for ATA-7 self-test execution status 8 ("... handling damage"). [GG] cciss: support more than 16 disks (patch taken from http://cciss.sourceforge.net/smartmontools_cciss_more_than_16_drives.patch and adjusted for smartd) [DG] Solaris: [SCSI] add USCSI_RQENABLE flag to uscsi pass-through so sense buffer is made available. Expand reporting at this level. [GK] Darwin: Improve handling of powered-down drives. [SS] CCISS physical drive enumeration method changed (incompatibly). [CF] Fixed smartd crash on missing '-s' directive argument. [SS] Support CCISS on FreeBSD (kernel source is required until FreeBSD PR 109813 is fixed). [DG] SCSI/TAPE: some IBM tape drives don't react properly to a LOG SENSE with an allocation length of 4; work around for that case. [CF] Applied Guido's patch to fix CCISS LUN array bounds check (openSUSE bug #239956) and remove trailing spaces in os_linux.cpp. [CF] Fixed 64-bit compilation issue in SCT status struct. [DG] SAT/SCSI: make real SCSI disks visible to DEVICESCAN in smartd again. [CF] Fixed check of SCT temperature table size. [CF] Added ATA-8 draft revisions, added SCT status format 3. [CF] Drive database: added Samsung T166 series. [CF] ATA: Added ',p' option for '-t scttempint,N' to make setting persistent. [CF] ATA: Added '-t scttempint,N' option to set SCT temperature logging interval. [CF] ATA: Added '-l scttemp[sts,hist]' options to print disk temperature information and history table provided by SMART Command Transport (SCT) Feature Set. [CF] ATA: Added '-t selective,{redo,next,cont}' commands to perform tests based on the last ranges still stored on disk. Added 'N+SIZE' and 'N-max' format for LBA range specification. [CF] Added Min/Max Temperature format used in attribute 190 of recent Maxtor disks (DiamondMax 20). [CF] Linux: Added check for <linux/cciss_ioctl.h> to allow build (without CCISS support) also when this file is missing. [CF] Added -F samsung3 option to correct firmware bug reporting completed self-tests as still in progress. Thanks to Manfred Schwarb for the patch. [CF] Added missing const specifiers (undetected by gcc 3.4 and 4.X) to fix compilation with gcc 2.X. [CF] Linux: compile fix for SuSE, config.h must be included first. smartmontools 5.37 Experimental Release [CF] Windows: Added alternate method for (limited) monitoring of 3ware controllers by parsing the output of CLI or 3DM. Either "tw_cli" can be run internally ("/dev/tw_cli/cx/py"), or data can be read from standard input ("/dev/tw_cli/stdin") or clipboard ("/dev/tw_cli/clip"). [DG] Remove linux specific libata detect code; rely on general SAT code. smartd should now generate a sensible log message for ATA devices behind a SAT layer on all architectures. [BA] Increased max line length MAXLINELEN for /etc/smartd.conf from 128 to 256 characters to handle long strings in /dev/disk/by-id. Thanks to Martin Krafft. [PW] Drive database: added missing drives from Seagate Momentus 5400.2 family [BA] Finished Christian's fix (next item below) by removing LINUX_86_64 hack from configure.in. [CF] Fixed inclusion of PRI?64 macros from inttypes.h. [CF] Windows: Added WRITE LOG to support selective self tests. [CF] Fix selective self test log revision number if '-T permissive' is specified (Tested with Samsung HD401LJ). [CF] Windows: Fixed int64 printf format for MinGW runtime. [PW] Drive database: added Seagate Barracuda 7200.10 family, Seagate Momentus 42 family, Maxtor DiamondMax 60 ATA 66 family, Maxtor DiamondMax 60 ATA 100 family, and Western Digital Caviar Serial ATA family [PW] Drive database: added missing drives from Seagate Barracuda 7200.9 family, Seagate Barracuda 7200.7 family, Seagate Momentus 7200.1 family, Toshiba 2.5" HDD family (80 GB and above), Western Digital Caviar RE Serial ATA family, Hitachi Deskstar 7K80 family, and Maxtor DiamondMax 4320 Ultra ATA family [BA] Linux: compile fix for SuSE. Check for existence of linux/compiler.h and include in os_linux.h if present. Thanks to SB. [BA] smartd: DEVICESCAN will now pick up SATA/SAT devices attached to a SCSI device tree via SAT translation. Note: this is a bit of a hack. I will document it once I know if this needs to be Linux only or can have more general application. [BA] Added a couple SATA commands to the tables -- thanks DG! Phil -- how about going through and systematically adding these new commands to atacmdnames.cpp? [BA] Linux s86_64: get rid of some compiler warnings on x86_64 Linux systems. [CF] Windows: Added missing support for READ_LOG, ABORT_SELFTEST and CHECK_POWER_STATE for 3ware 9000 controllers. Thanks to Greg de Valois for implementing this new ioctl in the driver. [PW] Drive database: added Seagate NL35 SATA family. Thanks to Kai Harrekilde-Petersen for providing a patch. [DG] [SCSI, Windows] add SPT interface for NT and later. New device names are "pd<n>", "sd<l>" and "tape<n>". [PW] Drive database: added Western Digital Scorpio family, Fujitsu MHV family, Maxtor MaXLine Pro 500 family, and Maxtor DiamondMax 11 family [PW] Drive database: added missing drives from Toshiba 2.5" HDD (30-60 GB) family, Maxtor DiamondMax 10 family, Seagate Barracuda 7200.8 family, Fujitsu MHT family, and Maxtor DiamondMax Plus 8 family [SB] Added examplescripts/Example4 using powersave-notify. [SB] More temperature monitoring examples in smartd.conf with DEVICESCAN. [SB] Minor improvements of SuSE part of init script. [CF] Drive database: added Samsung P80 series, P120 series, SP8004H and T series. [GG] Add CCISS (Compaq Smart Array Controller) support with contributions from Praveen Chidambaram, Douglas Gilbert, Guido Guenther and Frédéric BOITEUX [PW] Drive database: added Hitachi Deskstar T7K250 and Hitachi Deskstar 7K500 series. Thanks to L. J. Wu for providing a patch [PW] Drive database: added Maxtor MaXLine III family, Seagate U7 family, Seagate ST34321A, FUJITSU MHM2060AT, FUJITSU MHT2040AS, Western Digital Caviar SE16 family, IBM Travelstar 4GT family, QUANTUM FIREBALLP KA9.1, QUANTUM FIREBALL SE4.3A, TOSHIBA MK1032GAX, TOSHIBA MK4026GAX [PW] Drive database: added missing drives from Western Digital Caviar SE (Serial ATA) and WD Raptor families [CF] Windows: Added support for 3ware 9000 controllers using extended SMART functionality in new 3ware driver. This includes DEVICESCAN support for at most 2 controllers. Thanks to Greg de Valois from AMCC/3ware for new driver features, development support and hardware for testing. [SZ] smartd: Support HighPoint RocketRAID controller under GNU/linux [DG] [SCSI] First cut for '-l background' to show background scan results log [SZ] smartctl: Support HighPoint RocketRAID controller under GNU/linux [KS] C++ compile fixes for Solaris with a few cleanups. [BA] C++ compile fixes for Darwin (thanks to CF) [CF] Removed old *.c files (now in CVS Attic). [CF] Added changes for C++ to platform independent and Windows related files. [BA] Tagged last .c Version with PRE_MOVE_TO_CPP. Copied *.c,v to *.cpp,v in CVS repository to preserve history of source files. Removed sm5_Darwin repository. [CF] smartctl: Added -n option to skip checks when disk is in low-power mode. [CF] Windows: Added alternate system call for power state check because the PASS THROUGH calls may spin up the disk. [CF] smartd: Modified power state logging to report state changes instead of standby condition. [CF] smartd: Ignore -n directive on scheduled self tests. [DG] [SCSI] Make start stop cycle counter log page decoding more robust [DG] Modify smartctl (but not smartd) to detect probable ATA devices behind a SAT layer. In the absence of an explicit device type, change to device type 'sat'. [DG] Add indication that controller (device) type has been explicitly set. Preparation for automatic detection of 'sat' device type unless user specifies a device type. [SS] NetBSD: Deliver strings from ata_identify_device properly on little- and big-endian platforms. [BA] Added published ANSI ATA-7 spec to list of recognized ATA versions. [BA] Code janitor: added missing header strings for '-V' option. [DG] [SATA] Extend 'sat' device type to allow either 12 or 16 byte variant of the SAT ATA PASS THROUGH SCSI command. Syntax is '-d sat,<n>' where <n> can be 0, 12 or 16 . The ',<n>' part is optional. Currently defaults to 16 byte variant but that could be made platform or even device dependent. [DG] [SATA] Add new 'sat' device type for SATA disks behind a SCSI to ATA Translation (SAT) Layer (SATL). Uses the ATA PASS THROUGH (16) SCSI command thence the generic SCSI passthrough for each platform. [CF] Windows: Added script and make targets to create installer with NSIS (http://nsis.sourceforge.net/) [CF] Updated hostname and links for new SourceForge CVS service. [CF] smartd: Added '-W' directive to track temperature changes and warn if temperature limits are reached. [CF] Windows: Added IOCTL_ATA_PASS_THROUGH (Win2003, XP SP2) for commands unsupported by SMART_IOCTL. Added device specific options to select subset and ordering of the ATA IOCTLs actually used. These options are specified as modifiers of the device name (/dev/hd[a-j]:[saic]+) [CF] Windows: Added support for drives 4-7 (/dev/hd[e-h]) via SMARTVSE.VXD on Win9x/ME. Thanks to Dariusz Rzonca for patch and testing. [DG] [SCSI/SATA linux] from lk 2.6.17 SATA disk identification in libata will change. Expand LibAta detection to see old identifier and new variant (VPD page 0x83). [BA] Identified Attribute 190 for Western Digital disks. This stores temperature in Celsius, just like Attribute 194. But it has a failure threshold set to correspond to the maximum design operating temperature of the disk, which is 55 Celsius on the WD800JD drives that I studied. So if this Attribute has 'failed in the past' this means that the maximum disk operating temperature has been exceeded. [GK] Darwin: Add support for AHCI drivers found in Intel-based Macs. smartmontools 5.36 Stable Release [BA] Linux: smartd/smartctl issue syntax hints to user if 3ware disk controller present with EITHER 3ware OR AMCC vendor name, and user syntax incorrect. [BA] Update copyright dates to 2006. [DG] [SCSI] Loosen sanity check on Seagate/Hitachi factory information log page so it is not skipped on recent Seagate SCSI disks. [CF] Added command 'smartd -q showtests' to list test schedules. [CF] Added command 'smartctl -P showall MODEL [FIRMWARE]' to list database entries for specific drives and firmware. [PW] Automatically set -v 9,minutes and -v 194,unknown for Maxtor DiamondMax D540X-4G drives. [DG] [SCSI] suppress various outputs when data fails sanity checks. Correct 'last n error events' log page indexing. [DG] [SCSI] changed smartctl exit status to reflect any problems in the most recent 20 self test logs [Leandro Santi] [DG] [SCSI] Fix process return value when scsiGetSmartData() fails in smartctl [Leandro Santi] [BA] Updated docs and error message to reflect Linux libata support for smartmontools starting with the 2.6.15 kernel series. Also init script support for the 'tinysofa' release. [DG] [SCSI] Mask dpofua bit when changing mode pages. Fix failure of 'smartctl -l error'. [EM] Fixed a problem with FreeBSD and 3Ware 'twe' devices [CF] Fixed a regexp in knowndrives table, added regexp syntax check via 'smartctl -P showall'. [CF] Cygwin & Windows: Fixed memory leak in function calling IOCTL_IDE_PASS_THROUGH. Thanks to Fred Schmidt for the problem report. [CF] Cygwin: added cygrunsrv support and commands "install", "remove" and "status" to smartd.initd. [SS] Fix runtime problems on big-engian NetBSD platforms (patch provided by Martin Husemann) [CF] Cygwin smartd: Open smartd.conf in textmode to allow use of Windows editors. [CF] Cygwin smartd: Added option '--service' to allow smartd running as windows service via cygrunsrv. Useful in conjunction with new syslogd support added in Cygwin 1.5.15. [CF] Windows: Added patch to avoid output of non-ascii timezone names. [EM] Incorporate various patches to provide TWE support and support for multiple 3Ware cards, Power Check Support, and FreeBSD 6.x support. Thanks to Rudolf Cejka, Frank Behrens, and Jung-uk Kim. [DG] Silence gcc 4.0.1 compile warning concerning the difference in "signedness" in pointer assignments. Changes to SCSI code and os_linux.c . [PW] Additions to knowndrives table: added missing drive from Quantum Fireball Plus LM series, added QUANTUM BIGFOOT TS10.0A, added ExcelStor J680 and J880, added Western Digital Caviar RE Serial ATA series, added missing drives from Western Digital Caviar SE series, added Seagate Momentus 4200.2 series, added missing drives from Maxtor DiamondMax 10 series, added Fujitsu MHG and MHH series, and added Hitachi Travelstar 5K100 series. [PW] Additions to knowndrives table: added Fujitsu MHU2100AT, added Fujitsu M1623TAU, added missing drives from Seagate Barracuda 7200.8 series, added Seagate Momentus 5400.2 series, and added QUANTUM FIREBALL CR8.4A. [PW] Additions to knowndrives table: added missing drive from Maxtor MaxLine II series, added Maxtor DiamondMax 2880 Ultra ATA series, added Maxtor DiamondMax 17 VL series, added Hitachi Deskstar 7K80 series, and added Hitachi Deskstar 7K400 series. [CF] Windows: Fixed unsupported 'smartctl -X' on Win2000/XP by using IOCTL_IDE_PASS_THROUGH instead. smartmontools 5.34 Stable Release [NOTE: never officially released] [CF] Cygwin & Windows smartd: Increased SCSI DEVICESCAN range from ASPI adapter 0-3 to 0-9. Added diagnostic messages. [CF] Windows smartd: Added ability to run .bat files via '-M exec' directive. [CF] Cygwin smartd: Added FreeConsole() after fork() to avoid hang of terminated shell console window. [DG] [SCSI] Add code so 'smartctl -A' outputs the number of elements in the grown defect list. When this number is increasing a disk has problems. N.B. Similar logic should be added to smartd. [CF] Windows smartd: Fixed event handling to allow start of another smartd process when service is already running. Useful for testing service configuration changes in debug mode. [PW] Added following drives to knowndrives table: Western Digital Raptor family, Seagate Barracuda 7200.8 family, Maxtor DiamondMax 2160 Ultra ATA and DiamondMax 10 families, Hitachi Travelstar E7K60 family, Seagate Medalist 17240, 13030, 10231, 8420, and 4310, TOSHIBA MK4018GAP and MK6022GAX, ExcelStor Technology J360, and Western Digital Caviar AC14300. [PW] Added missing Fujitsu MHTxxxxAT and Seagate Barracuda 7200.7 drives to knowndrives table. [PW] Added QUANTUM FIREBALLP LM10.2 to knowndrives table. Thanks to Mike Fleetwood for submitting the patch. [KS] Solaris/SPARC: fixed not to disable automatic offline test and automatic save attributes incorrectly. Thanks to Roy Badami. [BA] Linux: smartd init script now recognizes 'trustix' distro. [DG] [SCSI] Medium and hardware errors were slipping through unreported. Fix linux SCSI sense reporting via SG_IO ioctl. [DG] [SCSI] Change lba of first failure in selftest output to decimal (was hex) to conform with ATA output. [GK] smartd: Detect most self-test failures even if the hour counter has wrapped. [BA] smartctl: list 'marvell' as option if user give invalid -d argument [CF] Windows: fixed SCSI timeout handling to allow long timeouts for selftests. [CF] Fixed buffer overflow issues in printone() and safe_vsnprintf() which results in crash on -V option (at least on Windows). [DG] [SCSI] Add explicit timeouts to INQUIRY and REQUEST SENSE (that were missed in an earlier patch). Could have impacted freebsd. [DG] When linux detects a sata_via_libata disk suggest that user try '-d ata' (rather then '-d libata). Anticipate kernel change. [YD] Added OS/2 and eComStation platform support. [PW] Added Seagate U4 family, Fujitsu MHJ and MHK families, Seagate Barracuda 5400.1, QUANTUM FIREBALLP KX27.3, QUANTUM FIREBALLP KA10.1, and ExcelStor J340 to knowndrives table. [DG] [SCSI] After report of Hitachi IC35L073UCDY10 disks locking up on log page 0x7 (last n error events), check log page (and some others) is supported (via log page 0x0) before probing. [CF] Added safe_v?snprintf() for platforms using v?snprintf() with non standard behaviour on overflow (Windows, old Linux) [CF] smartd: Added message if check power mode spins up disk. [CF] Windows: Added support for READ_LOG on WinNT4 using undocumented pseudo SCSI command via IOCTL_SCSI_PASS_THROUGH. [CF] smartd: Added ',q' option for '-n' directive to suppress 'skipping checks' log message. This prevents a laptop disk from spinning up due to this message. Thanks to Rob MacLachlan and Manfred Schwarb for pointing out problem & solution. [CF] Windows: Added function get_os_version_str() to show OS flavor in copyright message. [CF] Windows: Added function ata_identify_is_cached() to check for outdated SMART enabled bit in identify data. [CF] Windows: Added fix to prevent linkage of smartd specific win32 modules to smartctl. [PW] Added Fujitsu MPG3153AH, Hitachi Endurastar J4K20/N4K20 (formerly DK23FA-20J), Seagate Momentus family, and Maxtor Fireball 3 family to knowndrives table. [PW] Added missing Maxtor DiamondMax 16, Seagate Barracuda ATA IV, and Western Digital Caviar WDxxxAA/WDxxxBA drives to knowndrives table. [CF] Windows: Added ATA check power mode for smartd -n directive. [CF] Windows: Fixed use of new service status flag which causes hang of smartd service on WinNT4. [CF] Windows: Fixed error checking of IOCTL_IDE_PASS_THROUGH (used for READ_LOG on 2000/XP). Added some diagnostic messages on -r ataioctl[,2]. Thanks to Manfred Schwarb for bug report and testing. [BA] Fixed code bug that made it impossible to enable SMART on disks with failing health status. This would happen if the os_*.c author made STATUS and STATUS_CHECK work the same way. I have corrected this at a higher level; we now handle the case where STATUS and STATUS_CHECK are identical without issues. [LW] Make os_linux.c/marvell_command_interface() always return 0 on STATUS. Needed for a disk having bad SMART status. [CF] smartctl: Added drive family printing. [CF] autogen.sh: Allow automake 1.9, added message if automake version is unknown. [BA] smartctl: use locale-specific separators for printing disk capacity. Also use AC_CHECK_HEADERS not AC_CHECK_HEADER in configure.in. [BA] clean-up of #include structure so that -V options to smartd and smartctl work correctly. Please, don't #include header files into other header files. smartmontools 5.33 Experimental Release [BA] smartctl: ATA disks, if SMART ATTRIBUTE THRESHOLDS page has ID errors with some Attributes having NULL IDs, print Attribute info anyway (but issuing a warning to the user). [DG] [SCSI] Decode Last n error events log page; decode track following and positioning errors [Hitachi] [EM] FreeBSD: another tweak, __packed__ introduced in Version 5.0040 [EM] Cleaner tweak of fixes for FreeBSD 4.x. [EM] Fix compilation errors under FreeBSD 4.x, as it is still using and old GCC [EM] Remove 3ware/FreeBSD specific files and just include pieces we need [DG] Add logic in smartd to detect 3ware, Marvell controllers and SATA disks behind an ATA-SCSI simulator (in Linux). If specific device types are not given and they are picked in a general SCSI device scan then warn and skip. [GG] insert correct path to smartd into smartd's init script [BA] Changed all default paths in documentation to reflect /usr/local as default path prefix. This affects on-line man pages, primarily. [DS] Added support for OpenBSD [BA] Added another environment variable SMART_FULLMESSAGE set by the smartd mailing feature, and modified examplescripts/Example1 to illustrate it. [BA] Fixed potentially misleading messages of the form: XXX failed: success [DG] emit warning if SATA disk detected using libata in Linux; then exit [PW] Added Seagate U10 family, Hitachi Travelstar 7K60, Fujitsu MHR2020AT, and QUANTUM FIREBALLP AS20.5 to knowndrives table. [DG] Detect 3ware and Marvell controllers from SCSI INQUIRY vendor string and suggest usage of appropriate '-d' argument in smartctl. [LW] Tested the RELEASE_5_33_WITH_MARVELL_SUPPORT branch on actual Marvell 88SX5041 hardware, with success. Merged into HEAD. [BA] Fixed nasty DEVICESCAN bug [BA] Checked in RELEASE_5_33_WITH_MARVELL_SUPPORT branch with some Marvell support. [BA] Additional modifications of Ed's controller scheme. Fixed broken 3ware support under linux, problems with scanning devices in smartd, and other small problems. [CF] Added make targets to build formatted man pages (htmlman, txtman), Windows distribution (dist-win32) and MSVC6 config.h (config-vc6). [EM] Minor change to FreeBSD inclusion of 'twe' include files. Add code to check if they exising in /usr/include/sys to use those in preference to ones added here [EM] Very preliminary support attempt for 3Ware controllers under FreeBSD. Also, switched 'escalade_type/escalade_port' to 'controler_type/controller_port' and moved away from 'tryata/tryscsi' to using new 'controller*' variables to determine which controller type (ATA/SCSI/3Ware) to use. [GK] Added initscript support for Darwin. [CF] Windows smartd: Added ability to run smartd as a windows service, including new commands "smartd install ..." and "smartd remove" to install and remove the service registry entry. [BA] smartd: warn user if -s regexp regular expression contains characters other than 0123456789.*()|+?[-]{}:=SLCO since such characters are 'suspicous' and may indicate a poorly formed regexp. Extended regular expression gurus: can this list be reduced somewhat? [CF] Fixed bug in Windows smartd: Missing close of config file when configuration is reloaded by smartd daemon. [CF] Windows smartd: Added mail warning feature using the "Blat" (http://blat.sourceforge.net/) mailer as a default. [PW] Added Maxtor DiamondMax Plus 5120 Ultra ATA 33 series and TOSHIBA MK3017GAP to knowndrives table. [CF] Added fixes to build smartmontools on old Linux systems (libc < 6, Kernel 2.0.x). [BA] Added ATA minor version identity strings for latest ATA specification updates: ATA/ATAPI-7 T13 1532D revision 4a and ATA/ATAPI-6 published, ANSI INCITS 361-2002 [PW] Added Hitachi Travelstar 5K80 family and Fujitsu MHTxxxxAH family to knowndrives table. [EM] Fix up compilation under FreeBSD < 5.x [PW] Added QUANTUM FIREBALL EX3.2A and missing Western Digital Caviar SE drives to knowndrives table. [BA] Modified Hitachi Travelstar 80GN family regexp in drive database. Thanks to [GK/CF] for problem & solution. [GK] Added os_darwin.[ch] [PW] Added the following drives to the knowndrives table: IBM Travelstar 48GH, 30GN, and 15GN family; IBM Deskstar 37GP and 34GXP family; Western Digital WDC WD272AA; Maxtor DiamondMax D540X-4D family; TOSHIBA MK2016GAP, MK2018GAP, MK2018GAS, MK2023GAS; and QUANTUM FIREBALL ST3.2A [BA] smartd/smarctl now print build HOST/OS information as part of startup slogan. This should make it slightly easier to read bug reports from users. [RZ] Fixed the DEVICESCAN to do what it was supposed to do - give error message unless scanning is in progress. [BA] Update documentation to describe 3ware character devices. Better error detection for missing/malfunctioning devices behind 3ware controllers. Now pack 3ware ioctl structures explicitly. [BA] For ATA devices that support LBA mode, print capacity as part of smartctl --info [RZ] Made DEVICESCAN quiet about non-existing devices unless debug is on. [DG] treat "unit attention" SCSI warning as try again in some contexts (test unit ready and mode sense) [BA] on drives that store max/min rather than min/max, get order correct in printing temp. [BA] fixed typo in 'smartctl -h' output. Thanks to Gabor Z. Papp. [BA] linux: clean-up to 3ware/AMCC support; dynamically create or fix /dev/tw[ae][0-15] device node entries if they don't exist or are incorrect. One can now use the character devices /dev/twe[0-15] OR /dev/sd? for 3ware 6000/7000/8000 series cards. One must use /dev/twa[0-15] for 3ware 9000 series cards. Note that selective self-tests now work via /dev/tw[ae] devices. Next step: documentation. [BA] linux: experimental "support" for 3ware/AMCC 9000 series controllers that use the 3w-9xxx driver. This will be in a state of flux for a few days. Note that this requires the character interface /dev/twa[0-15]. [DG] linux: extend general SCSI OS interface to use the SG_IO ioctl. If not available, use the older SCSI_IOCTL_SEND_COMMAND ioctl. [KS] Solaris/x86: fixed system identification problem in configure script. Thanks to Stuart Swales. smartmontools 5.32 [BA] Update link to revised/updated IBM Deskstar Firmware [CF] Cygwin & Windows: Added missing ASPI manager initialization with GetASPI32SupportInfo(). Thanks to Nikolai SAOUKH for pointing this out and providing a patch. [BA] modified smartd init script to work on whitebox (thanks to Michael Falzon) [BA] removed (reverted) additional Attribute definitions from http://smart.friko.pl/attributes.php. All (or most?) of these appear to be return code values for the WD Digital Life Guard Utility. [PW] Added Seagate Medalist 17242, 13032, 10232, 8422, and 4312 to knowndrives table. Added missing Seagate U Series 5 drives. [PW] Added the following QUANTUM models to knowndrives table: FIREBALL EX6.4A, FIREBALLP AS10.2, FIREBALLP AS40.0, FIREBALL CR4.3A, FIREBALLP LM15, FIREBALLP LM30, and FIREBALLlct20 30 [PW] Added missing Western Digital Protege drives to knowndrives table. [PW] Added Maxtor DiamondMax 40 ATA 66 series and DiamondMax 40 VL Ultra ATA 100 series to knowndrives table. [PW] Added the following Hitachi/IBM drives to knowndrives table: HITACHI_DK14FA-20B, Travelstar 40GNX series, Travelstar 4LP series, and Travelstar DK23XXB series. Added the missing Travelstar 80GN drives. [PW] Added Fujitsu MPB series and MPG series to knowndrives table. Added the missing Fujitsu MHSxxxxAT drives. [KS] Solaris: added workaround for dynamic change of time-zone. [KS] Solaris: fixed problem that autogen.sh cannot detect absence of auto* tools. [BA] smartd: added time-zone bug information to man page. Reverted CF code for _WIN32 case. [CF] Cygwin & Windows: Added better error messages on IDE/ATA device open error. [BA] added additional Attribute definitions from http://smart.friko.pl/attributes.php [BA] smartd: reworked TimeZone bug workaround so it is only invoked for glibc. Note: this might not be right -- a similar bug may exist in other platform's libcs. [DG] SCSI smartmontools documentation updated [2004/5/6]. See: http://smartmontools.sourceforge.net/smartmontools_scsi.html [CF] Windows: Fixed reset of TZ=GMT in glibc timezone bug workaround. smartmontools 5.31 [DG] move SCSI device temperature and start-stop log page output (smartctl) into --attributes section (was in --info section). [GG] change default installation location to /usr/local [CF] Cygwin smartd: Fixed crash on access of SCSI devices after fork(). [PW] Added TOSHIBA MK4018GAS and the following Maxtor drive families to knowndrives table: DiamondMax D540X-4G, Fireball 541DX, DiamondMax 3400 Ultra ATA, DiamondMax Plus 6800 Ultra ATA 66. [PW] Added missing Maxtor DiamondMax 16, DiamondMax D540X-4K, and DiamondMax Plus 45 Ulta ATA 100 drives to knowndrives table. [PW] Added ExcelStor J240, Hitachi Travelstar 80GN family, Fujitsu MHTxxxxAT family, and IBM Deskstar 25GP and 22GXP families to knowndrives table. [CF] Cygwin smartd: Added workaround for missing SIGQUIT via keyboard: To exit smartd in debug mode, type CONTROL-C twice. [BA] smartctl: printing of the selective self-test log is now controlled by a new option: -l selective [BA] Added entries for Samsung firmware versions -25 to -39 based on latest info about firmware bug fixes. [PW] Added Seagate U Series X family, Seagate U8 family, and Seagate Medalist 8641 family to knowndrives table. [CF] smartd: Added exit values 5/6 for missing/unreadable config file. [BA] smartd: now monitor the Current Pending Sector count (Attribute 197) and the Offline Pending Sector Count (Attribute 198). Log a warning (and send an email, if so configured) if the raw count is nonzero. These are controlled by new Directives: -C and -U. Currently they are enabled by default. [CF] Added option -c FILE, --configfile=FILE to smartd to specify an alternate configuration FILE or '-' for standard input. [KS] configure.in now searches for -lnsl and -lsocket for Solaris. [CF] Win32/native smartd: Added thread to combine several syslog output lines into one single event log entry. [CF] Win32 smartd: Added DEVICESCAN for SCSI/ASPI devices. [GG] Use gethostbyname() the get the DNS domain since getdomainname() returns the NIS domain when sending mails from smartd. [GG] smartd.init.in: pass smartd_opts to smartd on startup, read distribution specific configuration files if found [SS] smartctl: added NetBSD support for Selective Self-tests. [BA] smartd.conf example configuration file now has all examples commented out except for 'DEVICESCAN'. [CF] Win32/native smartd: Added ability to display warning "emails" as message box by "-m msgbox" directive. With "-m sysmsgbox", a system modal (always on top) message box is shown. [BA] smartctl: printing of self-test log for disks that support Selective self-testing now shows the status of the (optional) read-scan after the selective self test. Also, changed format in printing self-test log to print failing LBA in base 10 not base 16 (more compatible with kernel error messages). Also, in printing SMART error log, print timestamps in format days+hours+minutes+seconds. [CF] Win32 smartd: Added ability to log to stdout/stderr (-l local1/2). Toggling debug console still works if stdout is redirected. [BA] smartctl: selective self-test log, print current status in a more detailed way. Allow writing of selective self-test log provided that no other self-test is underway. [BA] Linux: eliminated dependency on kernel tree hdreg.h. [BA] smartctl: -l selftest option now prints Selective self-test log in addition to the normal self-test log. Added additional options (-t pending, -t afterselect) to control remaining Selective Self-test capabilities. Tested with several Maxtor disks. Modified error message printing so that munged option messages print at the end not the start of output. [CF] Added daemon support to Win32 native version of smartd. The daemon can be controlled by commands similar to initd scripts: "smartd status|stop|reload|restart|sigusr1|sigusr2". [CF] Added minor support for option "-l local[0-7]" to Win32 native (not Cygwin) version of smartd. If specified, the log output is written to file "./smartd[1-7]?.log" instead of event log. [BA] Added Selective Self-test to smartctl (-t selective,M-N). Currently only supported under Linux; Solaris, NetBSD, FreeBSD and Windows developers must add WRITE LOG functionality to os_*.c [BA] Added workaround for an annoying glibc bug: if you change timezones, (eg, flying with a laptop from USA to Europe) localtime() does not notice this in a running executable, so time that appears in the system log (syslog!) will be incorrect. See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=48184 for additional examples of this bug. [DG] Set explicit timeouts for SCSI commands (most default to 6 seconds). Previously a 0 second timeout was meant to be interpreted as a default timeout but the FreeBSD port had a problem in this area. [CF] Fixed un-thread-safe exit signal handler for Win32 [BA] Fixed un-thread-safe exit signal handler pointed out by CF. [BA] Changed configure script to eliminate warnings under Solaris from sys/int_type.h conflicts with int64.h Added header files for umask to smartd.c. [BA] Man page format change from Werner LEMBERG. " " changed to \& [CF] Added os_win32/syslogevt.* event message file tool for Win32 smartd (native+cygwin). May also be useful for other cygwin programs writing to syslog(). [CF] Added Win32 version of smartd [CF] Merged RELEASE_5_26_WIN32_BRANCH [BA] Made some changes to man page markup suggested by Richard Verhoeven to work around bugs in man2html. Tested not to break anything under Linux and Solaris. [CF] Moved PrintOut() from utility.c to smart{ctl,d}.c to avoid syslog() output of smartctl. [BA] Grew worried that some time-zone names could be very long (eg, Mitteleuropaische Zeit) and put date string lengths into a single macro in utility.c [EM] Updated os_freebsd.c to handle older versions of FreeBSD in a more appropriate/obvious fashion. [EM] Modified autogen.sh as FreeBSD installs automake 1.7 as 'automake17' and NOT 'automake-1.7' smartmontools 5.30 [PW] Added QUANTUM FIREBALLlct15 30, QUANTUM FIREBALLlct20 40, and Maxtor 6Y060P0 (DiamondMax Plus 9 60GB) to knowndrives table. [PW] Added Maxtor MaXLine II family to knowndrives table (thanks to Brett Russ for submitting the patch). [BA] Added remaining read/write commands to detailed list of error log commands that have text descriptions of problem printed. For commands that support it, print number of failed sectors at problem LBA. [BA] Made SuSE section of smartd init script more SuSE 9 compatible. Thanks to Hans-Peter Jansen. [CF] Windows smartd: Added IDE/ATA device scan Added windows device names to smartctl.8.in, smartd.8.in [BA] smartctl/smartd: user-provided '-F samsung' and '-F samsung2' command line options/Directives did NOT over-ride preset values unless user specified '-P ignore'. Now they will always over-ride preset values from the database. [BA] Added error decoding for a few more READ and WRITE commands. [PW] Added Maxtor MaXLine Plus II, Western Digital Caviar SE (Serial ATA) series, Hitachi Deskstar 7K250 series, and Ultra ATA 66 models of the Maxtor DiamondMax Plus 40 series to knowndrives table. [BA] Added Maxtor Diamondmax 250 GB drives to database. Note that these model numbers are not listed in Maxtor documentation, but they exist. [BA] Removed the 'contact developers' phrase from the Samsung disk warning messages. [PW] Added TOSHIBA MK2017GAP, IBM Deskstar 14GXP and 16GP series, Fujitsu MPC series, Seagate Barracuda ATA III family, and missing Seagate Barracuda U Series drives to knowndrives table [BA] smartd: wrong loglevel for message: Configuration file /etc/smartd.conf parsed. Changed to LOG_INFO from LOG_CRIT. Thanks to Emmanuel CHANTREAU for the report. [CF] Checked in development version of windows code base. smartmontools 5.29 (note: there was NO 5.28 release) [BA] smartd: configure script did not set correct directory to search for smartd.conf based on --prefix argument to ./configure. Thanks to GG for identifying the problem and fix. [BA] make clean now removes man pages (generated from *.in) files as well as object files. [EM] Correct copying of sense data in FreeBSD SCSI implementation. Thanks to Sergey Svishchev for noticing the bug. [BA] On solaris, wrong warning message if no ATA support. Warning message concerns 3ware controller, not ATA. [SS] Added SCSI support for NetBSD. [BA] on big-endian linux machines, fixed interpretation of HDIO_GET_IDENTITY to correctly identify ATAPI bit (was byte swapped). This should eliminate some SYSLOG noise if user queries a packet device (eg, CD ROM or DVD reader). [PW] Removed warning for IBM Deskstar 40GV & 75GXP series drives with A5AA/A6AA firmware. Thanks to Gerald Schnabel. [PW] Added Toshiba TOS MK3019GAXB SUN30G to knowndrives table [PW] Added Western Digital Caviar AC12500, AC24300, AC25100, AC36400, and AC38400 to knowndrives table [BA] When printing ATA error log, print the LBA at which READ or WRITE commands failed. [BA] Changed syntax of error message in smartctl [BA] Added versioning info (-V options to smartd/smartctl) for Solaris ATA module. smartmontools 5.27 [KS] Added ATA/IDE support for Solaris/SPARC (ATA/IDE not yet for Solaris/x86). [BA] 3ware controllers: documented that one can monitor any of the physical disks from any of the 3ware /dev/sd? logical devices. Better warnings if querying a disk that does not exist. [PW] Added Hitachi Travelstar DK23DA series, Maxtor DiamondMax Plus 40 series, Western Digital Caviar WDxxxAA, WDxxxBA, and WDxxxAB series to knowndrives table [BA] missing 'pragma pack' on ATA IDENTIFY DEVICE structure may have caused odd or incorrect results on 64-bit machines. [BA] smartctl/smartd allow inspection of self-test and error logs even if disk firmware claims that these don't exist. This is needed for some Maxtor disks whose firmware does not indicate log support even though the disk DOES support it. [BA] Improved porting instructions and documentation in os_generic.c [PW] Add Western Digital Caviar WD136AA and SAMSUNG SP40A2H (RR100-07 firmware) to knowndrives table. [EM] FreeBSD: remove extra definition of FreeNonZero [BA] smartctl: the -q silent option was printing output for some error conditions. Fixed. Will rename relevant variables to help avoid these errors in the future. [SS] NetBSD port added. [BA] more sensible error messages for devfs and devfs-like systems. Instead of saying that the DIRECTORY does not exist, say that the DEVICE does not exist. [BA] smartd: added -n Directive, to prevent disk spin-up depending upon the power mode (SLEEP, STANDBY, or IDLE). [PW] Added Maxtor DiamondMax 20 VL series, Fujitsu MPF series, Maxtor DiamondMax 36 series, Maxtor DiamondMax 4320 series, and Maxtor DiamondMax 536DX series to knowndrives table. [BA] many warning messages now give the file name AND VERSION [BA] smartd: when the user provides multiple address recipients to the '-m' Directive in a comma-delineated list, the commas are stripped out before passing the list of addresses to the mailer program. (Thanks to Calin A. Culianu for pointing this out and providing a patch.) [BA] smartd: when the '-M exec path' Directive is used, any stdout OR stderr output from the executable "path" is assumed to indicate a problem, and is echoed to SYSLOG. [BA] Added all missing IBM/Hitachi Deskstar 180GXP models to knowndrives table. [PW] Added some missing IBM/Hitachi Deskstar 120GXP models to knowndrives table. [PW] Added IBM Travelstar 14GS to knowndrives table. [PW] Modified knowndrives table to match entire Hitachi Travelstar DK23BA and DK23EA series of drives (thanks to Norikatsu Shigemura for submitting the patch). [PW] Added some missing Fujitsu MPE series drives to knowndrives table. [PW] Added TOSHIBA MK4019GAX, TOSHIBA MK6409MAV, and QUANTUM FIREBALLlct15 20 to knowndrives table. [EM] Fixup example command output for FreeBSD [PW] Added Maxtor DiamondMax 80 family to knowndrives table. [EM] Catch up FreeBSD code to switch PROJECTHOME to PACKAGE_HOMEPAGE macros. [BA] smartd: now watches stdout/stderr when trying to run mail, mailx or mail warning script, and reports any output to SYSLOG. This gives a clearer error message if something is wrong. [BA] smartd: Solaris init script modified to accomodate grep that lacks '-q' quiet option. Also check for running process to kill on stop. [PW] Added some missing Seagate Barracuda 7200.7 and 7200.7 Plus drives to knowndrives table. [PW] Added Maxtor DiamondMax Plus 60 family and Seagate U Series 5 20413 to knowndrives table. [BA] smartd: under Solaris, made default mailer be 'mailx' not 'mail', since Solaris 'mail' does not accept a '-s' argument. A workaround for Solaris users of earlier versions is to have '-M exec /bin/mailx' in their smartd.conf config file. [DG] some SCSI controllers don't like odd length transfers so make sure LOG SENSE transfers are rounded up to an even number when and odd length is reported (i.e. there is a double fetch, the first to find the length, the second gets the data) [BA] smartd man pages: under Solaris, correct section numbers in the 'See also' section. [KS/BA] smartd man page: describe how to set Solaris syslog.conf file to catch all messages. Give correct Solaris SYSLOG default path /var/adm/messages in man pages. [BA] smartd: incorporated Debian startup script submitted by user. [BA] smartctl: modified printing of self-test log entry number. Seagate firmware can leave 'holes' in the self-test log while a test is actually running. We now print entry numbers consistently in this case, not assuming that entries are contiguous. [PW] Added QUANTUM FIREBALL CX10.2A and Western Digital Caviar AC23200L to knowndrives table. [PW] Added QUANTUM FIREBALLlct20 20 to knowndrives table. [PW] Added Maxtor DiamondMax Plus D740X family to knowndrives table. [PW] Added IBM Travelstar 32GH, 30GT, and 20GN family to knowndrives table. [BA] Slackware init script modified to search for /etc/slackware-version rather than /etc/slackware-release. [PW] Added Seagate Barracuda ATA II family and TOSHIBA MK4019GAXB to knowndrives table. [GG] explain howto use autoreconf in autogen.sh [KS] Makefile.am/configure.in: changed manual page sections for Solaris. [BA] smartd: reduced number of scheduled self-test messages if test already run in current hour. [PW] Added Maxtor DiamondMax Plus 8 family to knowndrives table. [BA] linux: check for linux/hdreg.h. If it's there, use it. If not, provide the necessary definitions ourselves. [PW] Removed warning for IBM Deskstar 40GV & 75GXP series drives with TXAOA5AA firmware [PW] Added IBM Travelstar 25GS, 18GT, and 12GN family to knowndrives table. [PW] Added IBM/Hitachi Travelstar 60GH & 40GN family to knowndrives table. [BA] smartd: made '-s' Directive more efficient. Now store compiled regex, and re-use. If device lacks certain self-test capabilities, track it and don't try again. [BA] smartd: made memory allocation for device lists completely dynamic (eliminating compile-time maximum length constants). [PW] Removed warning for SAMSUNG SP0802N with TK100-23 firmware [PW] Added Seagate Barracuda ATA IV family to knowndrives table. [BA] smartd: reduce per-device memory footprint by making mail-warning info dynamically allocated. Also remove potential memory leak if use has -m Directive twice and keeps reloading the config file (highly unlikely this would ever be noticed!) [DG] smartd: added SCSI scheduled self-tests (Background short or extended). [BA] smartd: can now run scheduled offline immediate and self-tests. See man page and -s Directive for details. [GG] don't include manpages in make-dist-tarball. [BA] smartctl: on-line examples given with -h are now correct for solaris and linux, but wrong for freebsd. Ed? [BA] smartd: man page now explains device scanning for solaris as well as linux and freebsd. [BA] smartd/smartctl: man pages now report correct CVS tag release date, and executables '-V' options reports more build info. smartmontools 5.26 [BA] Improved user messages that appear from 'make install' [PW] Removed warning for SAMSUNG SP1213N with firmware TL100-23 [BA] incorporated SuSE init script from user. [DG] if SCSI device is read only, then open it read only. [BA] when compiled on non-supported system (NOT linux, freebsd or solaris) then the run-time error messages now clearly say 'your system is not supported' and give clear directions. [BA] ./configure script now works correctly on SuSE linux boxes [BA] minor improvements to man pages [BA] simplified detection of packet (ATAPI, CD) devices. [BA] init script (redhat, mandrake, yellowdog) now uses correct strings for translation and is slightly more standard. [DG] smartctl: output scsi Seagate vendor pages for disks (not tapes) smartmontools 5.25 Note: there was no '5.24' release. From this point on, even numbered releases will be 'stable' ones and odd numbered releases will be unstable/testing/development ones. [DG] smartd/smartctl: changed scsiClearControlGLTSD() to scsiSetControlGLTSD() with an 'enabled' argument so '-S on' and '-S off' work for SCSI devices (if changing GLTSD supported). [BA] smartd/smartctl: wired in scsiClearControlGLTSD(). Could still use a corresponding Set function. Left stubs for this purpose. [DG] scsicmds: added scsiClearControlGLTSD() [still to be wired in] [BA] smartctl: make SCSI -T options behave the same way as the ATA ones. [DG] smartctl: output scsi transport protocol if available [DG] scsi: stop device scan in smartd and smartctl if badly formed mode response [heuristic to filter out USB devices before we (potentially) lock them up]. [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 GLTSD bit is set (global disable of saving log counters) [DG] scsi: remember mode sense cmd length. Output trip temperature from IE lpage (IBM extension) when unavailable from temp lpage. [BA] smartd: for both SCSI and ATA now warns user if either the number of self-test errors OR timestamp of most recent self-test error have increased. [DG] smartctl: output Seagate scsi Cache and Factory log pages (if available) when vendor attributes chosen [DG] smartd: add scsiCountFailedSelfTests() function. [DG] Do more sanity checking of scsi log page responses. [BA] smartd: now warns user if number of self-test errors has increased for SCSI devices. [BA] smartd: warn user if number of ATA self-test errors increases (as before) OR if hour time stamp of most recent self-test error changes. [DG] More checks for well formed mode page responses. This has the side effect of stopping scans on bad SCSI implementations (e.g. some USB disks) prior to sending commands (typically log sense) that locks them up. [PW] Added Western Digital Caviar family and Caviar SE family to knowndrives table. [BA] smartd: added -l daemon (which is the default value if -l is not used). [PW] Added Seagate Barracuda ATA V family to knowndrives table. [BA] smartd: added additional command line argument -l FACILITY or --logfacility FACILITY. This can be used to redirect messages from smartd to a different file than the one used by other system daemons. [PW] Added Seagate Barracuda 7200.7, Western Digital Protege WD400EB, and Western Digital Caviar AC38400 to knowndrives table. [BA] smartd: scanning should now also work correctly for devfs WITHOUT traditional links /dev/hd[a-t] or /dev/sd[a-z]. [PW] Added Maxtor 4W040H3, Seagate Barracuda 7200.7 Plus, IBM Deskstar 120GXP (40GB), Seagate U Series 20410, Fujitsu MHM2100AT, MHL2300AT, MHM2150AT, and IBM-DARA-212000 to knowndrives table. [PW] Added remaining Maxtor DiamondMax Plus 9 models to knowndrives table. [EM] smartd: If no matches found, then return 0, rather than an error indication, as it just means no devices of the given type exist. Adjust FreeBSD scan code to mirror Linux version. [BA] smartd: made device scan code simpler and more robust. If too many devices detected, warn user but scan as many as possible. If error in scanning, warn user but don't die right away. [EM] smartd: To keep as consistent as possible, migrate FreeBSD 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. 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. [EM] FreeBSD: Fixup code to allow for proper compilation under -STABLE branch. smartmontools 5.23 [BA] smartd: didn't close file descriptors of ATA packet devices that are scanned. Fixed. [BA] Added reload/report targets to the smartmontools init script. reload: reloads config file report: send SIGUSR1 to check devices now smartmontools 5.22 [EM] Fix compile issues for FreeBSD < 5-CURRENT. [PW] Added Fujitsu MHM2200AT to knowndrives table. [BA] To help catch bugs, clear ATA error structures before all ioctl calls. Disable code that attempted to time-out on SCSI devices when they hung (doesn't work). [BA] Documented STATUS/ERROR flags added by [PW] below. [BA] Improved algorithm to recognize ATA packet devices. Should no longer generate SYSLOG kernel noise when user tries either smartd or smartctl on packet device (CD-ROM or DVD). Clearer warning messages from smartd when scanning ATA packet device. [PW] Added TOSHIBA MK4025GAS to knowndrives table. [PW] Added a textual interpretation of the status and error registers in the SMART error log (ATA). The interpretation is command-dependent and currently only eight commands are supported (those which produced errors in the error logs that I happen to have seen). [BA] added memory allocation tracking to solaris code. Fixed solaris signal handling (reset handler to default after first call to handler) by using sigset. Added HAVE_SIGSET to configure.in [CD] solaris port: added SCSI functionality to solaris stubs. [BA] smartd: attempt to address bug report about smartd hanging on USB devices when scanning: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=107615 Set a timeout of SCSITIMEOUT (nominally 7 seconds) before giving up. [EM] smartd: DEVICESCAN will follow links in a devfs filesystem and make sure the end point is a disc. Update documentation, added note about FreeBSD scanning [BA] smartd: DEVICESCAN also looks for block devices in /dev. Updated documentation. Now scans for up to 20 ATA devices /dev/hda-t rather than previous 12 /dev/hda-l. [EM] smartd: mirror the FreeBSD DEVICESCAN logic for Linux, so that smartd now scans only devices found in /dev/. Also, make utility memory functions take a line number and file so that we report errors with the correct location. [GG] add a note about Debian bug #208964 to WARNINGS. [BA] smartctl: -T verypermissive option broken. Use -T verpermissive until the next release, please. [BA] Syntax mods so that code also compiles on Solaris using Sun Workshop compiler. Need -xmemalign 1i -xCC flags for cc. smartmontools 5.21 [DK] Changed configure.in so -Wall is only included if gcc is used (this is a gcc specific flag) and -fsignedchar is not used at all (this is a gcc specific compiler flag). [BA] Modifications so that code now compiles under solaris. Now all that's needed (:-) is to fill in os_solaris.[hc]. Added os_generic.[hc] as guide to future ports. Fixed -D option of smartd (no file name). Modified -h opt of smartd/smartctl to work properly with solaris getopt(). [EM] Update MAN pages with notes that 3ware drives are NOT supported under FreeBSD. Cleanup FreeBSD warning message handling. [EM] FreeBSD only: Fix first user found bug....I guess I was making the wrong assumption on how to convert ATA devnames to channel/unit numbers. [EM] Allow for option --enable-sample to append '.sample' to installed smartd.conf and rc script files. Also, let rc script shell setting be determined by configure [EM] Minor autoconf update to include -lcam for FreeBSD [EM] Add conditional logic to allow FreeBSD to compile pre-ATAng. -- note, not tested Add some documentation to INSTALL for FreeBSD. [EM] Implement SCSI CAM support for FreeBSD. NOTE: I am not an expert in the use of CAM. It seems to work for me, but I may be doing something horribly wrong, so please exercise caution. [EM] Switch over to using 'atexit' rather than 'on_exit' routine. This also meant we needed to save the exit status elsewhere so our 'Goodbye' routine could examine it. [EM] Move the DEVICESCAN code to os specific files. Also moved some of the smartd Memory functions to utility.c to make available to smartctl. [EM] Code janitor work on os_freebsd.c. [EM] Added os_freebsd.[hc] code. Additional code janitor work. [BA] Code janitor working, moving OS dependent code into os_linux.[hc]. [GG] conditionally compile os_{freebsd,linux}.o depending on host architecture [PW] Print estimated completion time for tests [BA] Added -F samsung2 flag to correct firmware byte swap. All samsung drives with *-23 firmware revision string. smartmontools 5.20 [GG] Fixed broken Makefile.am (zero length smartd.conf.5 was being created), fix broken uninstall/distcheck targets [FM] Improved Slackware init script added to /etc/smartd.initd smartmontools 5.19 [NOTE CHANGE OF RELEASE NUMBERING] [BA] smartctl: added '-T verypermissive' option which is equivalent to giving '-T permissive' many times. [BA] Try harder to identify from IDENTIFY DEVICE structure if SMART supported/enabled. smartd now does a more thorough job of trying to assess this before sending a SMART status command to find out for sure. [BA] smartctl: it's now possible to override the program's guess of the device type (ATA or SCSI) with -d option. [BA] try hard to avoid sending IDENTIFY DEVICE to packet devices (CDROMS). They can't do SMART, and this generates annoying syslog messages. At the same time, identify type of Packet device. [BA] smartctl: Can now use permissive option more than once, to control how far to go before giving up. [BA] smartd: if user asked to monitor either error or self-test logs (-l error or -l selftest) WITHOUT monitoring any of the Attribute values, code will SEGV. For 5.1-18 and earlier, a good workaround is to enable Auto offline (-o on). [BA] smartctl: If enable auto offline command given, update auto offline status before printing capabilities. [GG] Make autotools build the default, remove autotools.diff [GG] Add auto{conf,make} support, not enabled by default. [BA] Eliminated #include <linux/hdreg.h> from code. This should simplify porting to solaris, FreeBSD, etc. The only linux-specific code is now isolated to three routines, one for SCSI, one for Escalade, one for ATA. smartmontools 5.1-18 [BA] smartd: fixed serious bug - Attributes not monitored unless user told smartd to ignore at least one of them! smartmontools 5.1-17 [BA] Default runlevels for smartd changed from 3 and 5 to 2, 3, 4, and 5. [BA] Removed as much dynamic memory allocation as possible from configuration file parsing. Reloading config file, even in presence of syntax errors etc. should not cause memory leaks. [PW] It is no longer permissible for the integer part (if any) of arguments to --report and --device to be followed by non-digits. For example, the "foo" in --report=ioctl,2foo was previously ignored, but now causes an error. [BA] smartd: added -q/--quit command line option to specify under what circumstances smartd should exit. The old -c/--checkonce option is now obsoleted by this more general-purpose option. [BA] smartd now responds to a HUP signal by re-reading its configuration file /etc/smartd.conf. If there are errors in this file, then the configuration file is ignored and smartd continues to monitor the devices that it was monitoring prior to receiving the HUP signal. [BA] Now correctly get SMART status from disks behind 3ware controllers, thanks to Adam Radford. Need 3w-xxxx driver version 1.02.00.037 or later. Previously the smartmontools SMART status always returned "OK" for 3ware controllers. [BA] Additional work on dynamic memory allocation/deallocation. This should have no effect on smartctl, but clears that way for smartd to dynamically add and remove entries. It should also now be easier to modify smartd to re-read its config file on HUP (which is easy) without leaking memory (which is harder). The philosophy is that memory for data structures in smartd is now allocated only on demand, the first time it is needed. [BA] smartd: finished cleanup. Now use create/rm functions for cfgentries and dynamic memory allocation almost everywhere. Philosophy: aggresively try and provoke SEGV to help find bad code. [BA] Added SAMSUNG SV0412H to knowndrives table. [BA] smartd: if DEVICESCAN used then knowndrives table might not set the -v attributes correctly -- may have been the same for all the drives. Cleaned up some data structures and memory allocation to try and ensure segvs if such problems are introduced again. [BA] Now allow -S on and -o on for the 3ware device type. For these commands to be passed through, the stock 3ware 3w-xxxx driver must be patched (8 lines). I'll post a patch on the smartmontools home page after it's been tested by a few other people and 3ware have had a chance to look it over. smartmontools-5.1-16 [BA] smartd - can now monitor ATA drives behind 3ware controllers. [BA] smartd - changed some FATAL out of memory error messages from syslog level LOG_INFO to LOG_CRIT. [BA] smartctl - added code to look at ATA drives behind 3ware RAID controllers using the 3w-xxxx driver. Note that for technical reasons related to the 3w-xxxx driver, the "Enable Autosave", "Enable Automatic Offline" commands are not implemented. I will add this to smartd shortly. [BA] smartd - modified sleep loop, so that smartd no longer comes on the run queue every second. Instead, unless interrupted, it sleeps until the next polling time, when it wakes up. Now smartd also tries to wake up at exactly the right intervals (nominally 30 min) even if the user has been sending signals to it. [GG] add Fujitsu MHN2300AT to vendoropts_9_seconds. [EB] Fujitsu change in knowndrives ... match the whole MPD and MPE series for vendoropts_9_seconds. [BA] smartd bug, might cause segv if a device can not be opened. Was due to missing comma in char* list. Consequence is that email failure messages might have had the wrong Subject: heading for errorcount, FAILEDhealthcheck, FAILEDreadsmartdata, FAILEDreadsmarterrorlog, FAILEDreadsmartsefltestlog, FAILEDopendevice were all displaced by one. And FAILEDopendevice might have caused a segv if -m was being used as a smartd Directive. smartmontools-5.1-15 [BA] Cleaned up smartmontools.spec so that upgrading, removing and other such operations correctly preserve running behavior and booting behavior of smartd. [BA] Improved formatting of ATA Error Log printout, and added listing of names of commands that caused the error. Added obsolete ATA-4 SMART feature commands to table, along with obsolete SFF-8035i SMART feature command. [PW] Added atacmdnames.[hc], which turn command register & feature register pairs into ATA command names. [BA] Added conveyance self-test. Some code added for selective self-tests, but #ifdefed out. [BA] Modified smartd exit status and log levels. If smartd is "cleanly" terminated, for example with SIGTERM, then its exit messages are now logged at LOG_INFO not LOG_CRIT [BA] Added Attribute IDs (Fujitsu) 0xCA - 0xCE. This is decimal 202-206. Added -v switches for interpretation of Attributes 192, 198 and 201. [BA] Made smartmontools work with any endian order machine for: - SMART selftest log - SMART ATA error log - SMART Attributes values - SMART Attributes thesholds - IDENTIFY DEVICE information - LOG DIRECTORY Smartmontools is now free of endian bias and works correctly on both little- and big-endian hardware. This has been tested by three independent PPC users on a variety of ATA and SCSI hardware. [DG] Check that certain SCSI command responses are well formed. If IEC mode page response is not well formed exit smartctl. This is to protect aacraid. smartd should ignore a aacraid device. smartmontools-5.1-14 [BA] smartctl: added column to -A output to show if Attributes are updated only during off-line testing or also during normal operation. smartmontools-5.1-13 [BA] smartd: attempt to enable/disable automatic offline testing even if the disk appears not to support it. Now the same logic as smartctl. [BA] Added definition of Attribute 201, soft read error rate. [BA] Added IBM/Hitachi IC35L120AVV207-1 (GXP-180) and corresponding 8MB Cache GXP-120 to drive database. [BA] smartd: if DEVICESCAN Directive used in smartd.conf, and -I, -R or -r Directives used in conjunction with this, got segv errors. Fixed by correcting memory allocation calls. [BA] smartd: enable automatic offline testing was broken due to cut-and-paste error that disabled it instead of enabling it. Thanks to Maciej W. Rozycki for pointing out the problem and solution. [BA] Fixed "spelling" of some Attribute names to replace spaces in names by underscores. (Fixed field width easier for awk style parsing.) [BA,GF] Added mods submitted by [GF] to support Attribute 193 being load/unload cycles. Add -v 193,loadunload option, useful for Hitachi drive DK23EA-30, and add this drive to knowndrive.c Add meaning of attribute 250 : Read error retry rate smartmontools-5.1-12 [BA] Added another entry for Samsung drives to knowndrive table. [DG] Refine SCSI log sense command to do a double fetch in most cases (but not for the TapeAlert log page). Fix TapeAlert and Self Test log page response truncation. [PW] Added 'removable' argument to -d Directive for smartd. This indicates that smartd should continue (rather than exit) if the device does not appear to be present. [BA] Modified smartmontools.spec [Man pages location] and smartd.initd [Extra space kills chkconfig!] for Redhat 6.x compatibility (thanks to Gerald Schnabel). smartmontools-5.1-11 [EB] Add another Fujitsu disk to knowndrives.c [GG] match for scsi/ and ide/ in case of devfs to exclude false postives [BA] If SCSI device listed in /etc/smartd.conf fails to open or do SMART stuff correctly, or not enough space to list all SCSI devices, fail with error unless -DSCSIDEVELOPMENT set during compile-time. [BA] Added automatic recognition of /dev/i* (example: /dev/ide/...) as an ATA device. [DG] Add "Device type: [disk | tape | medium changer | ...] line to smartctl -i output for SCSI devices. [PW] Fixed bug in smartd where test email would be sent regularly (for example, daily if the user had specified -M daily) instead of just once on startup. [KM] More TapeAlert work. Added translations for media changer alerts. TapeAlert support reported according to the log page presence. ModeSense not attempted for non-ready tapes (all drives do not support this after all). Get peripheral type from Inquiry even if drive info is not printed. Add QUIETON() QUIETOFF() to TapeAlert log check. [BA] Stupid bug in atacmds.c minor_str[] affected ataVersionInfo(). Two missing commas meant that minor_str[] had two few elements, leading to output like this: Device Model: Maxtor 6Y120L0 Serial Number: Y40BF74E Firmware Version: YAR41VW0 Device is: Not in smartctl database [for details use: -P showall] ATA Version is: 7 ATA Standard is: 9,minutes ^^^^^^^^^ Missing commas inserted. [BA] Fixed smartd bug. On device registration, if ATA device did not support SMART error or self-test logs but user had asked to monitor them, an attempt would be made to read them anyway, possibly generating "Drive Seek" errors. We now check that the self-test and error logs are supported before trying to access them the first time. [GG/BA] Fixed bug where if SMART ATA error log not supported, command was tried anyway. Changed some error printing to use print handlers. [GG] Makefile modifications to ease packaging [DG] Did work for TapeAlerts (SCSI). Now can detect /dev/nst0 as a SCSI device. Also open SCSI devices O_NONBLOCK so they don't hang on open awaiting media. The ATA side should worry about this also: during a DEVICESCAN a cd/dvd device without media will hang. Added some TapeAlert code suggested by Kai Makisara. smartmontools-5.1-10 [PW] Extended the -F option/Directive to potentially fix other firmware bugs in addition to the Samsung byte-order bug. Long option name is now --firmwarebug and the option/Directive accepts an argument indicating the type of firmware bug to fix. [BA] Fixed a bug that prevented the enable automatic off-line test feature from enabling. It also prevented the enable Attribute autosave from working. See CVS entry for additional details. [PW] Modified the -r/--report option (smartctl and smartd) to allow the user to specify the debug level as a positive integer. [BA] Added --log directory option to smartctl. If the disk supports the general-purpose logging feature set (ATA-6/7) then this option enables the Log Directory to be printed. This Log Directory shows which device logs are available, and their lengths in sectors. [PW] Added -P/--presets option to smartctl and -P Directive to smartd. [GG] Introduce different exit codes indicating the type of problem encountered for smartd. [DG] Add non-medium error count to '-l error' and extended self test duration to '-l selftest'. Get scsi IEs and temperature changes working in smartd. Step over various scsi disk problems rather than abort smartd startup. [DG] Support -l error for SCSI disks (and tapes). Output error counter log pages. [BA] Added -F/--fixbyteorder option to smartctl. This allows us to read SMART data from some disks that have byte-reversed two- and four- byte quantities in their SMART data structures. [BA] Fixed serious bug: the -v options in smartd.conf were all put together and used together, not drive-by-drive. [PW] Added knowndrives.h and knowndrives.c. The knowndrives array supersedes the drivewarnings array. [GG] add {-p,--pidfile} option to smartd to write a PID file on startup. Update the manpage accordingly. [DG] Fix scsi smartd problem detecting SMART support. More cleaning and fix (and rename) scsiTestUnitReady(). More scsi renaming. [BA] Fixed smartd so that if a disk that is explictily listed is not found, then smartd will exit with nonzero status BEFORE forking. If a disk can't be registered, this will also be detected before forking, so that init scripts can react correctly. [BA] Replaced all linux-specific ioctl() calls in atacmds.c with a generic handler smartcommandhandler(). Now the only routine that needs to be implemented for a given OS is os_specific_handler(). Also implemented the --report ataioctl. This provides two levels of reporting. Using the option once gives a summary report of device IOCTL transactions. Using the option twice give additional info (a printout of ALL device raw 512 byte SMART data structures). This is useful for debugging. [DG] more scsi cleanup. Output scsi device serial number (VPD page 0x80) if available as part of '-i'. Implement '-t offline' as default self test (only self test older disks support). [BA] Changed crit to info in loglevel of smartd complaint to syslog if DEVICESCAN enabled and device not found. [BA] Added -v 194,10xCelsius option/Directive. Raw Attribute number 194 is ten times the disk temperature in Celsius. [DG] scsicmds.[hc] + scsiprint.c: clean up indentation, remove tabs. Introduce new intermediate interface based on "struct scsi_cmnd_io" to isolate SCSI generic commands + responses from Linux details; should help port to FreeBSD of SCSI part of smartmontools. Make SCSI command builders more parametric. smartmontools-5.1-9 [BA] smartctl: if HDIO_DRIVE_TASK ioctl() is not implemented (no kernel support, then try to assess drive health by examining Attribute values/thresholds directly. [BA] smartd/smartctl: added -v 200,writeerrorcount option/Directive for Fujitsu disks. [BA] smartd: Now send email if any of the SMART commands fails, or if open()ing the device fails. This is often noted as a common disk failure mode. [BA] smartd/smartctl: Added -v N,raw8 -v N,raw16 and -v N,raw48 Directives/Options for printing Raw Attributes in different Formats. [BA] smartd: Added -r ID and -R ID for reporting/tracking Raw values of Attributes. [BA] smartd/smartctl: Changed printing of spin-up-time attribute raw value to reflect current/average as per IBM standard. [BA] smartd/smartctl: Added -v 9,seconds option for disks which use Attribute 9 for power-on lifetime in seconds. [BA] smartctl: Added a warning message so that users of some IBM disks are warned to update their firmware. Note: we may want to add a command-line flag to disable the warning messages. I have done this in a general way, using regexp, so that we can add warnings about any type of disk that we wish... smartmontools-5.1-7 [BA] smartd: Created a subdirectory examplescripts/ of source directory that contains executable scripts for the -M exec PATH Directive of smartd. smartmontools-5.1-5 [BA] smartd: DEVICESCAN in /etc/smartd.conf can now be followed by all the same Directives as a regular device name like /dev/hda takes. This allows one to use (for example): DEVICESCAN -m root@example.com in the /etc/smartd.conf file. [BA] smartd: Added -c (--checkonce) command-line option. This checks all devices once, then exits. The exit status can be used to learn if devices were detected, and if smartd is functioning correctly. This is primarily for Distribution scripters. [BA] smartd: Implemented -M exec Directive for smartd.conf. This makes it possible to run an arbitrary script or mailing program with the -m option. [PW] smartd: Modified -M Directive so that it can be given multiple times. Added -M exec Directive. smartmontools-5.1-4 [BA] Fixed bug in smartctl pointed out by Pierre Gentile. -d scsi didn't work because tryata and tryscsi were reversed -- now works on /devfs SCSI devices. [BA] Fixed bug in smartctl pointed out by Gregory Goddard <ggoddard@ufl.edu>. Manual says that bit 6 of return value turned on if errors found in smart error log. But this wasn't implemented. smartmontools-5.1-3 [BA] Modified printing format for 9,minutes to read Xh+Ym not X h + Y m, so that fields are fixed width. [BA] Added Attribute 240 "head flying hours" smartmontools-5.1.1 [BA] As requested, local time/date now printed by smartctl -i [PW] Added "help" argument to -v for smartctl [PW] Added -D, --showdirectives option to smartd [DG] add '-l selftest' capability for SCSI devices (update smartctl.8) [BA] smartd,smartctl: added additional Attribute modification option -v 220,temp and -v 9,temp. [PW] Renamed smartd option -X to -d START OF SMARTMONTOOLS 5.1 series smartmontools-5.0.50 [PW] Changed smartd.conf Directives -- see man page [BA/DG] Fixed uncommented comment in smartd.conf [DG] Correct 'Recommended start stop count' for SCSI devices [PW] Replaced smartd.conf directive -C with smartd option -i [PW] Changed options for smartctl -- see man page. [BA] Use strerror() to generate system call error messages. [BA] smartd: fflush() all open streams before fork(). [BA] smartctl, smartd simplified internal handling of checksums for simpler porting and less code. smartmontools-5.0.49 [PW] smartd --debugmode changed to --debug [BA] smartd/smartctl added attribute 230 Head Amplitude from IBM DPTA-353750. [PW] Added list of proposed new options for smartctl to README. [PW] smartd: ParseOpts() now uses getopt_long() if HAVE_GETOPT_LONG is defined and uses getopt() otherwise. This is controlled by CPPFLAGS in the Makefile. [BA] smartd: Fixed a couple of error messages done with perror() to redirect them as needed. smartmontools-5.0.48 [BA] smartctl: The -O option to enable an Immediate off-line test did not print out the correct time that the test would take to complete. This is because the test timer is volatile and not fixed. This has been fixed, and the smartctl.8 man page has been updated to explain how to track the Immediate offline test as it progresses, and to further emphasize the differences between the off-line immediate test and the self-tests. [BA] smartd/smartctl: Added new attribute (200) Multi_Zone_Error_Rate [BA] smartctl: modified so that arguments could have either a single - as in -ea or multiple ones as in -e -a. Improved warning message for device not opened, and fixed error in redirection of error output of HD identity command. [PW] smartd: added support for long options. All short options are still supported; see manpage for available long options. [BA] smartctl. When raw Attribute value was 2^31 or larger, did not print correctly. smartmontools-5.0.46 [BA] smartd: added smartd.conf Directives -T and -s. The -T Directive enables/disables Automatic Offline Testing. The -s Directive enables/disables Attribute Autosave. Documentation and example configuration file updated to agree. [BA] smartd: user can make smartd check the disks at any time (ie, interrupt sleep) by sending signal SIGUSR1 to smartd. This can be done for example with: kill -USR1 <pid> where <pid> is the process ID number of smartd. [EB] scsi: don't trust the data we receive from the drive too much. It very well might have errors (like zero response length). Seen on Megaraid logical drive, and verified in the driver source. [BA] smartd: added Directive -m for sending test email and for modifying email reminder behavior. Updated manual, and sample configuration file to illustrate & explain this. [BA] smartd: increased size of a continued smartd.conf line to 1023 characters. [BA] Simplified Directive parsers and improved warning/error messages. smartmontools-5.0.45 [EB] Fixed bug in smartd where testunitready logic inverted prevented functioning on scsi devices. The bug in question only affects smartd users with scsi devices. To see if your version of smartd has the testunitready() bug, do smartd -V If the version of the module smartd.c in a line like: Module: smartd.c revision: 1.66 date: 2002/11/17 has a revision greater than or equal to 1.30, and less than or equal to 1.64, then your version of the code has this problem. This problem affected releases starting with RELEASE_5_0_16 up to and including RELEASE_5_0_43. [BA] Added testunitnotready to smartctl for symmetry with smartd. [SB] added Czech descriptions to .spec file [SB] corrected comment in smartd.conf example [BA] Changed way that entries in the ATA error log are printed, to make it clearer which is the most recent error and which is the oldest one. NOTE: All changes made prior to this point were done by Bruce Allen [BA] although several of them had been suggested by earlier postings by Stanislav Brabec [SB]. smartmontools-5.0.43 Changed Temperature_Centigrade to Temperature_Celsius. The term "Centigrade" ceased to exist in 1948. (c.f http://www.bartleby.com/64/C004/016.html). smartmontools-5.0.42 Modified SCSI device check to also send warning emails if requested in directives file. Added a new smartd configuration file Directive: -M ADDRESS. This sends a single warning email to ADDRESS for failures or errors detected with the -c, -L, -l, or -f Directives. smartmontools-5.0.38 Modified perror() statements in atacmds.c so that printout for SMART commands errors is properly suppressed or queued depending upon users choices for error reporting modes. Added Italian descriptions to smartmontools.spec file. Started impementing send-mail-on-error for smartd; not yet enabled. Added -P (Permissive) Directive to smartd.conf file to allow SMART monitoring of pre-ATA-3 Rev 4 disks that have SMART but do not have a SMART capability bit. Removed charset encodings from smartmontools.spec file for non-English fields. smartmontools-5.0.32 Added manual page smartd.conf.5 for configuration file. smartctl: Missing ANSI prototype in failuretest(); fixed. smartctl: Checksum warnings now printed on stdout, or are silent, depending upon -q and -Q settings. smartmontools-5.0.31 Changed Makefile so that the -V option does not reflect file state before commit! smartctl: added new options -W, -U, and -P to control if and how the smartctl exits if an error is detected in either a SMART data structure checksum, or a SMART command returns an error. modified manual page to break options into slightly more logical categories. reformatted 'usage' message order to agree with man page ordering modified .spec file so that locale information now contains character set definition. Changed pt_BR to pt since we do not use any aspect other than language. See man setlocale. smartmontools-5.0.30 smartctl: added new options -n and -N to force device to be ATA or SCSI smartctl: no longer dies silently if device path does not start/dev/X smartctl: now handles arbitrary device paths smartmontools-5.0.29 Modified .spec file and Makefile to make them more compliant with the "right" way of doing things. smartmontools-5.0.26 Fixed typesetting error in man page smartd.8 Removed redundant variable (harmless) from smartd.c smartmontools-5.0.25 Added a new directive for the configuration file. If the word DEVICESCAN appears before any non-commented material in the configuration file, then the confi file will be ignored and the devices wil be scanned. smartmontools-5.0.24 Note: it has now been confirmed that the code modifications between 5.0.23 and 5.0.24 have eliminated the GCC 3.2 problems. Note that there is a GCC bug howerver, see #8404 at http://gcc.gnu.org/cgi-bin/gnatsweb.pl?database=gcc&cmd=query http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8404 Added new Directive for Configuration file: -C <N> This sets the time in between disk checks to be <N> seconds apart. Note that although you can give this Directive multiple times on different lines of the configuration file, only the final value that is given has an effect, and applies to all the disks. The default value of <N> is 1800 sec, and the minimum allowed value is ten seconds. Problem wasn't the print format. F.L.W. Meunier <0@pervalidus.net> sent me a gcc 3.2 build and I ran it under a debugger. The problem seems to be with passing the very large (2x512+4) byte data structures as arguments. I never liked this anyway; it was inherited from smartsuite. So I've changed all the heavyweight functions (ATA ones, anyone) to just passing pointers, not hideous kB size structures on the stack. Hopefully this will now build OK under gcc 3.2 with any sensible compilation options. smartmontools-5.0.23 Because of reported problems with GCC 3.2 compile, I have gone thorough the code and explicitly changed all print format parameters to correspond EXACTLY to int unless they have to be promoted to long longs. To quote from the glibc bible: [From GLIBC Manual: Since the prototype doesn't specify types for optional arguments, in a call to a variadic function the default argument promotions are performed on the optional argument values. This means the objects of type char or short int (whether signed or not) are promoted to either int or unsigned int, as appropriate.] smartmontools-5.0.22 smartd, smartctl now warn if they find an attribute whose ID number does not match between Data and Threshold structures. Fixed nasty bug which led to wrong number of arguments for a varargs statement, with attendent stack corruption. Sheesh! Have added script to CVS attic to help find such nasties in the future. smartmontools-5.0.21 Eliminated some global variables out of header files and other minor cleanup of smartd. smartmontools-5.0.20 Did some revision of the man page for smartd and made the usage messages for Directives 100% consistent. smartmontools-5.0-19 smartd: prints warning message when it gets SIGHUP, saying that it is NOT re-reading the config file. smartctl: updated man page to say self-test commands -O,x,X,s,S,A appear to be supported in the code. [I can't test these, can anyone report?] smartmontools-5.0-18 smartctl: smartctl would previously print the LBA of a self-test if it completed, and the LBA was not 0 or 0xff...f However according to the specs this is not correct. According to the specs, if the self-test completed without error then LBA is undefined. This version fixes that. LBA value only printed if self-test encountered an error. smartmontools-5.0-17 smartd has changed significantly. This is the first CVS checkin of code that extends the options available for smartd. The following options can be placed into the /etc/smartd.conf file, and control the behavior of smartd. Configuration file Directives (following device name): -A Device is an ATA device -S Device is a SCSI device -c Monitor SMART Health Status -l Monitor SMART Error Log for changes -L Monitor SMART Self-Test Log for new errors -f Monitor for failure of any 'Usage' Attributes -p Report changes in 'Prefailure' Attributes -u Report changes in 'Usage' Attributes -t Equivalent to -p and -u Directives -a Equivalent to -c -l -L -f -t Directives -i ID Ignore Attribute ID for -f Directive -I ID Ignore Attribute ID for -p, -u or -t Directive # Comment: text after a hash sign is ignored \ Line continuation character cleaned up functions used for printing CVS IDs. Now use string library, as it should be. modified length of device name string in smartd internal structure to accomodate max length device name strings removed un-implemented (-e = Email notification) option from command line arg list. We'll put it back on when implemeneted. smartd now logs serious (fatal) conditions in its operation at loglevel LOG_CRIT rather than LOG_INFO before exiting with error. smartd used to open a file descriptor for each SMART enabled device, and then keep it open the entire time smartd was running. This meant that some commands, like IOREADBLKPART did not work, since the fd to the device was open. smartd now opens the device when it needs to read values, then closes it. Also, if one time around it can't open the device, it simply prints a warning message but does not give up. Have eliminated the .fd field from data structures -- no longer gets used. smartd now opens SCSI devices as well using O_RDONLY rather than O_RDWR. If someone can no longer monitor a SCSI device that used to be readable, this may well be the reason why. smartd never checked if the number of ata or scsi devices detected was greater than the max number it could monitor. Now it does. smartmontools-5.0-16 smartd on startup now looks in the configuration file /etc/smartd.conf for a list of devices which to include in its monitoring list. See man page (man smartd) for syntax. smartd: close file descriptors of SCSI device if not SMART capable Closes ALL file descriptors after forking to daemon. added new temperature attribute (231, temperature) smartd: now open ATA disks using O_RDONLY smartmontools-5.0-11 smartd now prints the name of a failed or changed attribute into logfile, not just ID number Changed name of -p (print version) option to -V 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, 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. If the SMART status check shows GOOD, we then look to see if their are any usage attributes or prefail attributes have failed at any time. If so we print them. Modified function that prints vendor attributes to say if the attribute has currently failed or has ever failed. -p option now prints out license info and CVS strings for all 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 threshold and the prefailure bit is set. However the ATA Spec (ATA4 <=Rev 4) says that it is a SMART failure if the value of an attribute is LESS THAN OR EQUAL to the threshold and the prefailure bit is set. This is now fixed in both smartctl and smartd. Note that this is a troubled subject -- the original SFF 8035i specification defining SMART was inconsistent about this. One section says that Attribute==Threshold is pass, and another section says it is fail. However the ATA specs are consistent and say Attribute==Threshold is a fail. smartd did not print the correct value of any failing SMART attribute. It printed the index in the attribute table, not the attribute ID. This is fixed. when starting self-tests in captive mode ioctl returns EIO because the drive has been busied out. Detect this and don't return an eror in this case. Check this this is correct (or how to fix it?) fixed possible error in how to determine ATA standard support for devices with no ATA minor revision number. device opened only in read-only not read-write mode. Don't need R/W access to get smart data. Check this with Andre. smartctl now handles all possible choices of "multiple options" gracefully. It goes through the following phases of operation, in order: INFORMATION, ENABLE/DISABLE, DISPLAY DATA, RUN/ABORT TESTS. Documentation has bee updated to explain the different phases of operation. Control flow through ataPrintMain() simplified. If reading device identity information fails, try seeing if the info can be accessed using a "DEVICE PACKET" command. This way we can at least get device info. Modified Makefile to automatically tag CVS archive on issuance of a release Modified drive detection so minor device ID code showing ATA-3 rev 0 (no SMART) is known to not be SMART capable. Now verify the checksum of the device ID data structure, and of the attributes threshold structure. Before neither of these structures had their checksums verified. New behavior vis-a-vis checksums. If they are wrong, we log warning messages to stdout, stderr, and syslog, but carry on anyway. All functions now call a checksumwarning routine if the checksum doesn't vanish as it should. Changed Read Hard Disk Identity function to get fresh info from the disk on each call rather than to use the values that were read upon boot-up into the BIOS. This is the biggest change in this release. The ioctl(device, HDIO_GET_IDENTITY, buf ) call should be avoided in such code. Note that if people get garbled strings for the model, serial no and firmware versions of their drives, then blame goes here (the BIOS does the byte swapping for you, apparently!) Function ataSmartSupport now looks at correct bits in drive identity structure to verify first that these bits are valid, before using them. Function ataIsSmartEnabled() written which uses the Drive ID state information to tell if SMART is enabled or not. We'll carry this along for the moment without using it. Function ataDoesSmartWork() guaranteed to work if the device supports SMART. Replace some numbers by #define MACROS Wrote Function TestTime to return test time associated with each different type of test. Thinking of the future, have added a new function called ataSmartStatus2(). Eventually when I understand how to use the TASKFILE API and am sure that this works correctly, it will replace ataSmartStatus(). This queries the drive directly to see if the SMART status is OK, rather than comparing thresholds to attribute values ourselves. But I need to get some drives that fail their SMART status to check it. smartmontools-5.0-10 Removed extraneous space before printing in some error messages Fixed additional typos in documentation Fixed some character buffers that were too short for their contents. smartmontools-5.0-9 Put project home path into all source files near the top Corrected typos in the documentation Modified Makefile so that Mandrake Cooker won't increment version number (unless they happen to be working on my machine, which I doubt!) smartmontools-5.0-8: For IBM disks whose raw temp data includes three temps. print all three print timestamps for error log to msec precision added -m option for Hitachi disks that store power on life in minutes added -L option for printing self-test error logs in -l option, now print power on lifetime, so that one can see when the error took place updated SMART structure definitions to ATA-5 spec added -p option added -f and -F options to enable/disable autosave threshold parameters changed argv parsing to use getops -- elminate buffer overflow vulnerability expanded and corrected documentation fixed problem with smartd. It did not actually call ataSmartEnable()! Since the argument was left out, the test always suceeded because it evaluated to a pointer to the function. smartd: closed open file descriptors if device does not support smart. Note: this still needs to be fixed for SCSI devices smartmontools-5.0-0 STARTED with smartsuite-2.1-2 ������������������������������������������������smartmontools-6.2+svn3841.orig/do_release�����������������������������������������������������������0000755�0000000�0000000�00000007361�12104237231�017113� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # # do a smartmontools release # (C) 2003-11 Bruce Allen <ballen4705@users.sourceforge.net>, # Guido Guenther <agx@sigxcpu.org> # (C) 2006-13 Christian Franke <smartmontools-support@lists.sourceforge.net> # $Id: do_release 3765 2013-02-05 17:17:13Z chrfranke $ # Notes on generating releases: # (1) update NEWS # (2) update ChangeLog -- put in release number # (3) update release number in configure.ac # (4) to test, run without '--commit' # (5) when satisfied, add option '--commit' set -e # Smartmontools Signing Key (through 2014) KEYID=0x8F6ED8AA inc_release() { MINOR=`echo $VERSION | cut -d. -f2` MAJOR=`echo $VERSION | cut -d. -f1` PERL_OLD=$MAJOR\\.$MINOR ((++MINOR)) NEW_VERSION=$MAJOR.$MINOR PERL_NEW=$MAJOR\\.$MINOR NEW_RELEASE="RELEASE_${NEW_VERSION//\./_}" echo "New Version: $NEW_VERSION" echo "New Release: $NEW_RELEASE" } COMMIT= RC= case "$1" in --commit) COMMIT=yes; shift ;; esac case "$*" in RC[1-9]) RC="$1" ;; FINAL) ;; *) echo "Usage: $0 [--commit] RC[1-9]|FINAL"; exit 1 ;; esac # Check workdir case "`/bin/pwd`" in */trunk/smartmontools) WDROOT="../.."; DIRPAT="trunk" ;; */branches/*/smartmontools) WDROOT="../../.."; DIRPAT="branches/*" ;; *) echo "`/bin/pwd`: no trunk or branch working dir"; exit 1 ;; esac if [ ! -d "$WDROOT/tags" ]; then echo "tags directory missing"; exit 1 fi REVX="`(cd $WDROOT && svnversion)`" || exit 1 REV="${REVX/%[PM]/}"; REV="${REV/%[PM]/}" if [ -n "${REV//[0-9]/}" ]; then echo "Working directory not clean: $REVX"; exit 1 fi (cd $WDROOT && svn status) | while read s; do case "`echo $s | tr -s ' '`" in "M "$DIRPAT/smartmontools/ChangeLog) echo "$s: OK";; "M "$DIRPAT/smartmontools/NEWS) echo "$s: OK";; "M "$DIRPAT/smartmontools/configure.ac) echo "$s: OK";; *) echo "$s: not allowed"; exit 1;; esac done if [ $? -ne 0 ]; then exit 1 fi # Get release number VERSION=`sed -n 's|^AC_INIT[^,]*, *\([0-9.]*\) *,.*$|\1|p' configure.ac` if [ -z "$VERSION" ]; then echo "AC_INIT not found in configure.ac"; exit 1 fi VERSIONRC="$VERSION" RELEASE="RELEASE_${VERSION//\./_}" if [ "$RC" ]; then VERSIONRC="${VERSION}-${RC/#RC/rc}" RELEASE="${RELEASE}_${RC}" fi if [ -e "$WDROOT/tags/$RELEASE" ]; then echo "tags/$RELEASE exists"; exit 1 fi echo "r$REV: Release $VERSIONRC $RELEASE" # Update timestamp smartmontools_release_date=`date -u +"%Y-%m-%d"` smartmontools_release_time=`date -u +"%T %Z"` cat configure.ac | sed "s|smartmontools_release_date=.*|smartmontools_release_date=${smartmontools_release_date}|" > configure.tmp cat configure.tmp | sed "s|smartmontools_release_time=.*|smartmontools_release_time=\"${smartmontools_release_time}\"|" > configure.ac rm -f configure.tmp # Review changes svn diff echo "===================================================================" echo ">>> Continuing in 20 seconds ..." sleep 20 set -v # Create tag and commit if [ "$COMMIT" = "yes" ]; then svn mkdir $WDROOT/tags/$RELEASE svn copy ../smartmontools $WDROOT/tags/$RELEASE/smartmontools svn commit -m "Release $VERSIONRC $RELEASE" $WDROOT fi # Build ./autogen.sh mkdir build cd build ../configure make distcheck || exit 1 make maintainer-clean cd .. TARFILE=smartmontools-$VERSIONRC.tar.gz mv -f build/smartmontools-$VERSION.tar.gz $TARFILE rm -rvf build md5sum $TARFILE > $TARFILE.md5 # Increase release number if [ -z "$RC" -a "$DIRPAT" = "trunk" ]; then inc_release if [ "$COMMIT" = "yes" ]; then perl -p -i.bak -e "s/$PERL_OLD/$PERL_NEW/" configure.ac # svn commit -m "Bump release number to $NEW_VERSION" configure.ac fi fi # Sign tarball if [ -n "$KEYID" ] && gpg --list-secret-keys $KEYID >/dev/null 2>/dev/null; then gpg --default-key $KEYID --armor --detach-sign ./smartmontools-$VERSIONRC.tar.gz fi �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/TODO�����������������������������������������������������������������0000644�0000000�0000000�00000000251�11451641341�015547� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������$Id: TODO 3175 2010-10-02 14:34:09Z chrfranke $ This file is no longer maintained, please use the ticket reports: http://sourceforge.net/apps/trac/smartmontools/report �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/cciss.cpp������������������������������������������������������������0000644�0000000�0000000�00000016014�12002312310�016653� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <stdio.h> #include <string.h> #include <sys/types.h> #include <errno.h> #include "config.h" #if defined(linux) # include <sys/ioctl.h> # ifdef HAVE_LINUX_COMPILER_H # include <linux/compiler.h> # endif # if defined(HAVE_LINUX_CCISS_IOCTL_H) # include <linux/cciss_ioctl.h> # define _HAVE_CCISS # endif # include <asm/byteorder.h> # ifndef be32toh # define be32toh __be32_to_cpu # endif #elif defined(__FreeBSD__) # include <sys/endian.h> # include CISS_LOCATION # define _HAVE_CCISS #elif defined(__FreeBSD_kernel__) # include <endian.h> # ifdef __GLIBC__ # include <bsd/sys/cdefs.h> # include <stdint.h> # endif # include CISS_LOCATION # define _HAVE_CCISS #endif #ifdef _HAVE_CCISS #include "cciss.h" #include "int64.h" #include "scsicmds.h" #include "utility.h" const char * cciss_cpp_cvsid = "$Id: cciss.cpp 3578 2012-07-20 17:26:32Z chrfranke $" CCISS_H_CVSID; typedef struct _ReportLUNdata_struct { uint32_t LUNListLength; /* always big-endian */ uint32_t reserved; uint8_t LUN[CISS_MAX_LUN][8]; } ReportLunData_struct; /* Structure/defines of Report Physical LUNS of drive */ #ifndef CISS_MAX_LUN #define CISS_MAX_LUN 16 #endif #define CISS_MAX_PHYS_LUN 1024 #define CISS_REPORT_PHYS 0xc3 #define LSCSI_DRIVER_SENSE 0x8 /* alternate CHECK CONDITION indication */ #define SEND_IOCTL_RESP_SENSE_LEN 16 /* ioctl limitation */ static int cciss_getlun(int device, int target, unsigned char *physlun, int report); static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB, unsigned int CDBlen, char *buff, unsigned int size, unsigned int LunID, unsigned char *scsi3addr, int fd); /* This is an interface that uses the cciss passthrough to talk to the SMART controller on the HP system. The cciss driver provides a way to send SCSI cmds through the CCISS passthrough. */ int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int report) { unsigned char pBuf[512] = {0}; unsigned char phylun[8] = {0}; int iBufLen = 512; int status = -1; int len = 0; // used later in the code. status = cciss_getlun(device, target, phylun, report); if (report > 0) printf(" cciss_getlun(%d, %d) = 0x%x; scsi3addr: %02x %02x %02x %02x %02x %02x %02x %02x\n", device, target, status, phylun[0], phylun[1], phylun[2], phylun[3], phylun[4], phylun[5], phylun[6], phylun[7]); if (status) { return -ENXIO; /* give up, assume no device there */ } status = cciss_sendpassthru( 2, iop->cmnd, iop->cmnd_len, (char*) pBuf, iBufLen, 1, phylun, device); if (0 == status) { if (report > 0) printf(" status=0\n"); if (DXFER_FROM_DEVICE == iop->dxfer_dir) { memcpy(iop->dxferp, pBuf, iop->dxfer_len); if (report > 1) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; printf(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((const char*)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } } return 0; } iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */ if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf)) iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ? SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len; if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) && iop->sensep && (len > 0)) { memcpy(iop->sensep, pBuf, len); iop->resp_sense_len = iBufLen; if (report > 1) { printf(" >>> Sense buffer, len=%d:\n", (int)len); dStrHex((const char *)pBuf, len , 1); } } if (report) { if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) { printf(" status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff, pBuf[2] & 0xf, pBuf[12], pBuf[13]); } else printf(" status=0x%x\n", status); } if (iop->scsi_status > 0) return 0; else { if (report > 0) printf(" ioctl status=0x%x but scsi status=0, fail with ENXIO\n", status); return -ENXIO; /* give up, assume no device there */ } } static int cciss_sendpassthru(unsigned int cmdtype, unsigned char *CDB, unsigned int CDBlen, char *buff, unsigned int size, unsigned int LunID, unsigned char *scsi3addr, int fd) { int err ; IOCTL_Command_struct iocommand; memset(&iocommand, 0, sizeof(iocommand)); if (cmdtype == 0) { // To controller; nothing to do } else if (cmdtype == 1) { iocommand.LUN_info.LogDev.VolId = LunID; iocommand.LUN_info.LogDev.Mode = 1; } else if (cmdtype == 2) { memcpy(&iocommand.LUN_info.LunAddrBytes,scsi3addr,8); iocommand.LUN_info.LogDev.Mode = 0; } else { fprintf(stderr, "cciss_sendpassthru: bad cmdtype\n"); return 1; } memcpy(&iocommand.Request.CDB[0], CDB, CDBlen); iocommand.Request.CDBLen = CDBlen; iocommand.Request.Type.Type = TYPE_CMD; iocommand.Request.Type.Attribute = ATTR_SIMPLE; iocommand.Request.Type.Direction = XFER_READ; iocommand.Request.Timeout = 0; iocommand.buf_size = size; iocommand.buf = (unsigned char *)buff; if ((err = ioctl(fd, CCISS_PASSTHRU, &iocommand))) { fprintf(stderr, "CCISS ioctl error %d (fd %d CDBLen %d buf_size %d)\n", fd, err, CDBlen, size); } return err; } static int cciss_getlun(int device, int target, unsigned char *physlun, int report) { unsigned char CDB[16]= {0}; ReportLunData_struct *luns; int reportlunsize = sizeof(*luns) + CISS_MAX_PHYS_LUN * 8; int ret; luns = (ReportLunData_struct *)malloc(reportlunsize); memset(luns, 0, reportlunsize); /* Get Physical LUN Info (for physical device) */ CDB[0] = CISS_REPORT_PHYS; CDB[6] = (reportlunsize >> 24) & 0xFF; /* MSB */ CDB[7] = (reportlunsize >> 16) & 0xFF; CDB[8] = (reportlunsize >> 8) & 0xFF; CDB[9] = reportlunsize & 0xFF; if ((ret = cciss_sendpassthru(0, CDB, 12, (char *)luns, reportlunsize, 0, NULL, device))) { free(luns); return ret; } if (report > 1) { unsigned int i,j; unsigned char *stuff = (unsigned char *)luns; pout("\n===== [%s] DATA START (BASE-16) =====\n", "LUN DATA"); for (i=0; i<(sizeof(_ReportLUNdata_struct)+15)/16; i++){ pout("%03d-%03d: ", 16*i, 16*(i+1)-1); for (j=0; j<15; j++) pout("%02x ",*stuff++); pout("%02x\n",*stuff++); } pout("===== [%s] DATA END (%u Bytes) =====\n\n", "LUN DATA", (unsigned)sizeof(_ReportLUNdata_struct)); } if (target >= 0 && target < (int) be32toh(luns->LUNListLength) / 8) { memcpy(physlun, luns->LUN[target], 8); free(luns); return 0; } free(luns); return 1; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartd.service.in����������������������������������������������������0000644�0000000�0000000�00000000462�11763454010�020345� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������[Unit] Description=Self Monitoring and Reporting Technology (SMART) Daemon After=syslog.target [Service] EnvironmentFile=-/usr/local/etc/sysconfig/smartmontools ExecStart=/usr/local/sbin/smartd -n $smartd_opts ExecReload=/bin/kill -HUP $MAINPID StandardOutput=syslog [Install] WantedBy=multi-user.target ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/dev_legacy.cpp�������������������������������������������������������0000644�0000000�0000000�00000021544�11530257130�017672� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * dev_legacy.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2008-11 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "config.h" #include "int64.h" #include "utility.h" #include "atacmds.h" #include "scsicmds.h" #include "dev_interface.h" #include "dev_ata_cmd_set.h" #include <errno.h> const char * dev_legacy_cpp_cvsid = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $" DEV_INTERFACE_H_CVSID; ///////////////////////////////////////////////////////////////////////////// // Legacy interface declarations (now commented out globally): // from utility.h: int guess_device_type(const char * dev_name); int make_device_names (char ***devlist, const char* name); int deviceopen(const char *pathname, char *type); int deviceclose(int fd); // from atacmds.h: int ata_command_interface(int device, smart_command_set command, int select, char *data); // from scsicmds.h: int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); // from smartctl.h: void print_smartctl_examples(); ///////////////////////////////////////////////////////////////////////////// namespace os { // No need to publish anything, name provided for Doxygen ///////////////////////////////////////////////////////////////////////////// /// Implement shared open/close routines with old functions. class legacy_smart_device : virtual public /*implements*/ smart_device { public: explicit legacy_smart_device(const char * mode) : smart_device(never_called), m_fd(-1), m_mode(mode) { } virtual ~legacy_smart_device() throw(); virtual bool is_open() const; virtual bool open(); virtual bool close(); protected: /// Return filedesc for derived classes. int get_fd() const { return m_fd; } private: int m_fd; ///< filedesc, -1 if not open. const char * m_mode; ///< Mode string for deviceopen(). }; legacy_smart_device::~legacy_smart_device() throw() { if (m_fd >= 0) ::deviceclose(m_fd); } bool legacy_smart_device::is_open() const { return (m_fd >= 0); } bool legacy_smart_device::open() { m_fd = ::deviceopen(get_dev_name(), const_cast<char*>(m_mode)); if (m_fd < 0) { set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno); return false; } return true; } bool legacy_smart_device::close() { int fd = m_fd; m_fd = -1; if (::deviceclose(fd) < 0) { set_err(errno); return false; } return true; } ///////////////////////////////////////////////////////////////////////////// /// Implement standard ATA support with old functions class legacy_ata_device : public /*implements*/ ata_device_with_command_set, public /*extends*/ legacy_smart_device { public: legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); }; legacy_ata_device::legacy_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "ata", req_type), legacy_smart_device("ATA") { } int legacy_ata_device::ata_command_interface(smart_command_set command, int select, char * data) { return ::ata_command_interface(get_fd(), command, select, data); } ///////////////////////////////////////////////////////////////////////////// /// Implement standard SCSI support with old functions class legacy_scsi_device : public /*implements*/ scsi_device, public /*extends*/ legacy_smart_device { public: legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual smart_device * autodetect_open(); virtual bool scsi_pass_through(scsi_cmnd_io * iop); }; legacy_scsi_device::legacy_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "scsi", req_type), legacy_smart_device("SCSI") { } bool legacy_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) { int status = ::do_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); if (status < 0) { set_err(-status); return false; } return true; } ///////////////////////////////////////////////////////////////////////////// /// SCSI open with autodetection support smart_device * legacy_scsi_device::autodetect_open() { // Open device if (!open()) return this; // No Autodetection if device type was specified by user if (*get_req_type()) return this; // The code below is based on smartd.cpp:SCSIFilterKnown() // Get INQUIRY unsigned char req_buff[64] = {0, }; int req_len = 36; if (scsiStdInquiry(this, req_buff, req_len)) { // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices // watch this spot ... other devices could lock up here req_len = 64; if (scsiStdInquiry(this, req_buff, req_len)) { // device doesn't like INQUIRY commands close(); set_err(EIO, "INQUIRY failed"); return this; } } int avail_len = req_buff[4] + 5; int len = (avail_len < req_len ? avail_len : req_len); if (len < 36) return this; // Use INQUIRY to detect type // SAT or USB ? { smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); if (newdev) // NOTE: 'this' is now owned by '*newdev' return newdev; } // Nothing special found return this; } ///////////////////////////////////////////////////////////////////////////// /// Implement platform interface with old functions. class legacy_smart_interface : public /*implements*/ smart_interface { public: virtual std::string get_app_examples(const char * appname); virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern = 0); protected: virtual ata_device * get_ata_device(const char * name, const char * type); virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); }; ////////////////////////////////////////////////////////////////////// std::string legacy_smart_interface::get_app_examples(const char * appname) { if (!strcmp(appname, "smartctl")) ::print_smartctl_examples(); // this prints to stdout ... return ""; // ... so don't print again. } ata_device * legacy_smart_interface::get_ata_device(const char * name, const char * type) { return new legacy_ata_device(this, name, type); } scsi_device * legacy_smart_interface::get_scsi_device(const char * name, const char * type) { return new legacy_scsi_device(this, name, type); } smart_device * legacy_smart_interface::autodetect_smart_device(const char * name) { switch (::guess_device_type(name)) { case CONTROLLER_ATA : return new legacy_ata_device(this, name, ""); case CONTROLLER_SCSI: return new legacy_scsi_device(this, name, ""); } // TODO: Test autodetect device here return 0; } static void free_devnames(char * * devnames, int numdevs) { static const char version[] = "$Id: dev_legacy.cpp 3263 2011-02-20 18:32:56Z chrfranke $"; for (int i = 0; i < numdevs; i++) FreeNonZero(devnames[i], -1,__LINE__, version); FreeNonZero(devnames, (sizeof (char*) * numdevs),__LINE__, version); } bool legacy_smart_interface::scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern /*= 0*/) { if (pattern) { set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); return false; } // Make namelists char * * atanames = 0; int numata = 0; if (!type || !strcmp(type, "ata")) { numata = ::make_device_names(&atanames, "ATA"); if (numata < 0) { set_err(ENOMEM); return false; } } char * * scsinames = 0; int numscsi = 0; if (!type || !strcmp(type, "scsi")) { numscsi = ::make_device_names(&scsinames, "SCSI"); if (numscsi < 0) { free_devnames(atanames, numata); set_err(ENOMEM); return false; } } // Add to devlist int i; if (!type) type=""; for (i = 0; i < numata; i++) { ata_device * atadev = get_ata_device(atanames[i], type); if (atadev) devlist.push_back(atadev); } free_devnames(atanames, numata); for (i = 0; i < numscsi; i++) { scsi_device * scsidev = get_scsi_device(scsinames[i], type); if (scsidev) devlist.push_back(scsidev); } free_devnames(scsinames, numscsi); return true; } } // namespace ///////////////////////////////////////////////////////////////////////////// /// Initialize platform interface and register with smi() void smart_interface::init() { static os::legacy_smart_interface the_interface; smart_interface::set(&the_interface); } ������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/configure.ac���������������������������������������������������������0000644�0000000�0000000�00000052055�12174532061�017357� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# # $Id: configure.ac 3841 2013-07-26 17:38:57Z chrfranke $ # dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) AC_INIT(smartmontools, 6.2, smartmontools-support@lists.sourceforge.net) AC_CONFIG_SRCDIR(smartctl.cpp) smartmontools_configure_date=`date -u +'%Y-%m-%d %T %Z'` smartmontools_cvs_tag=`echo '$Id: configure.ac 3841 2013-07-26 17:38:57Z chrfranke $'` smartmontools_release_date=2013-07-26 smartmontools_release_time="17:38:20 UTC" AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_ARGS, "$ac_configure_args", [smartmontools Configure Arguments]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_CONFIGURE_DATE, "$smartmontools_configure_date", [smartmontools Configure Date]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_RELEASE_DATE, "$smartmontools_release_date", [smartmontools Release Date]) AC_DEFINE_UNQUOTED(SMARTMONTOOLS_RELEASE_TIME, "$smartmontools_release_time", [smartmontools Release Time]) AC_DEFINE_UNQUOTED(CONFIG_H_CVSID, "$smartmontools_cvs_tag", [smartmontools CVS Tag]) AC_DEFINE_UNQUOTED(PACKAGE_HOMEPAGE, "http://smartmontools.sourceforge.net/", [smartmontools Home Page]) AM_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE([foreign]) AM_MAINTAINER_MODE AC_LANG_CPLUSPLUS dnl Checks for programs. AC_PROG_CXX AM_PROG_AS AC_PROG_INSTALL m4_pattern_forbid([^PKG_PROG_]) if test "$cross_compiling" = "no"; then m4_ifdef([PKG_PROG_PKG_CONFIG], [PKG_PROG_PKG_CONFIG], [AC_MSG_WARN([m4/pkg.m4 missing, systemd detection disabled])]) fi AC_ARG_VAR(WINDMC, [Windows message compiler command]) AC_ARG_VAR(WINDRES, [Windows resource compiler command]) AC_ARG_VAR(MAKENSIS, [NSIS compiler command]) AC_CANONICAL_HOST case "${host}" in *-*-mingw*) # Cygwin gcc 4.x does no longer support '-mno-cygwin' to select MinGW gcc. if test "${build}" = "${host}" && test -x /usr/bin/uname && \ /usr/bin/uname | grep -i '^CYGWIN' >/dev/null; then AC_MSG_ERROR([Build with MinGW on Cygwin requires cross-compilation, see INSTALL file.]) fi AC_CHECK_TOOL(WINDMC, [windmc]) AC_CHECK_TOOL(WINDRES, [windres]) AC_MSG_CHECKING([checking for makensis]) if test -z "$MAKENSIS"; then if test -n "$PROGRAMFILES" && "$PROGRAMFILES/NSIS/makensis" -VERSION >/dev/null 2>&1; then MAKENSIS="$PROGRAMFILES/NSIS/makensis" elif makensis -VERSION >/dev/null 2>&1; then MAKENSIS=makensis fi fi AC_MSG_RESULT([${MAKENSIS:-no}]) ;; esac # Check for SVN. AC_MSG_CHECKING([whether this is a build from SVN]) is_svn_build=no svn_deps= if test -f "$srcdir/.svn/wc.db"; then # SVN 1.7, 1.8 working copy svn_deps='${srcdir}/.svn/wc.db' elif test -f "${srcdir}/.svn/entries"; then # SVN <= 1.6 working copy (SVN 1.7 has empty entries file) svn_deps='${srcdir}/.svn/entries' fi if test -n "$svn_deps"; then is_svn_build=unknown if (cd "$srcdir" && svn --version && svnversion && svn info) >/dev/null 2>&1; then is_svn_build=yes fi fi AC_SUBST([svn_deps]) AM_CONDITIONAL(IS_SVN_BUILD, [test "$is_svn_build" = "yes"]) AC_MSG_RESULT([$is_svn_build]) # Note: On Linux, clock_gettime() requires -lrt which implies -lpthreads # Check ommitted for now, gettimeofday() provides reasonable precision # AC_SEARCH_LIBS(clock_gettime, rt) dnl Checks for header files. AC_CHECK_HEADERS([locale.h]) AC_CHECK_HEADERS([dev/ata/atavar.h]) AC_CHECK_HEADERS([netdb.h]) dnl we need [u]int64_t and friends. AC_CHECK_HEADERS([inttypes.h]) dnl C99, UNIX98, solaris 2.6+ AC_CHECK_HEADERS([stdint.h]) dnl C99 AC_CHECK_HEADERS([sys/inttypes.h]) dnl pre-UNIX98 AC_CHECK_HEADERS([sys/int_types.h]) dnl pre-UNIX98, solaris 2.6+ dnl Check for FreeBSD twe include files...currently missing on 5.2, but should be there AC_CHECK_HEADERS([sys/tweio.h]) AC_CHECK_HEADERS([sys/twereg.h]) dnl Check for FreeBSD twa include files... AC_CHECK_HEADERS([sys/tw_osl_ioctl.h]) dnl This header file is needed for cciss_ioctl.h at least on SuSE LINUX AC_CHECK_HEADERS([linux/compiler.h]) dnl Check for the FreeBSD CCISS system header and use internal one if not found AC_CHECK_HEADERS([dev/ciss/cissio.h], [AC_DEFINE([CISS_LOCATION],[<dev/ciss/cissio.h>],[freebsd ciss header location])], [AC_DEFINE([CISS_LOCATION],["cissio_freebsd.h"],[freebsd ciss header location])] ) dnl Check for Linux CCISS include file AC_CHECK_HEADERS([linux/cciss_ioctl.h], [], [], [AC_INCLUDES_DEFAULT #ifdef HAVE_LINUX_COMPILER_H # include <linux/compiler.h> #endif ]) dnl Check for Windows DDK and WMI header files AC_CHECK_HEADERS([ntdddisk.h ddk/ntdddisk.h], [], [], [AC_INCLUDES_DEFAULT #include <windows.h> ]) AC_CHECK_HEADERS([wbemcli.h]) dnl Checks for typedefs, structures, and compiler characteristics. AC_CHECK_TYPES([int64_t, uint64_t]) dnl Checks for library functions. AC_CHECK_FUNCS([getopt_long], [need_getopt_long=no], [need_getopt_long=yes]) AM_CONDITIONAL(NEED_GETOPT_LONG, [test "$need_getopt_long" = "yes"]) AC_CHECK_FUNCS([regcomp], [need_regex=no], [need_regex=yes]) AM_CONDITIONAL(NEED_REGEX, [test "$need_regex" = "yes"]) AC_CHECK_FUNCS([sigset]) AC_CHECK_FUNCS([strtoull]) AC_CHECK_FUNCS([uname]) AC_CHECK_FUNCS([clock_gettime ftime gettimeofday]) # Check byte ordering (defines WORDS_BIGENDIAN) AC_C_BIGENDIAN # Check whether snprintf appends null char and returns expected length on overflow AC_MSG_CHECKING([for working snprintf]) AC_RUN_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>]], [[ char buf[]="ABCDEFGHI"; int i=snprintf(buf,8,"12345678"); return !(!buf[7] && i==8); ]])], [libc_have_working_snprintf=yes], [libc_have_working_snprintf=no], [libc_have_working_snprintf=unknown]) AC_SUBST(libc_have_working_snprintf) if test "$libc_have_working_snprintf" = "yes"; then AC_DEFINE(HAVE_WORKING_SNPRINTF, 1, [Define to 1 if the `snprintf' function is sane]) fi AC_MSG_RESULT([$libc_have_working_snprintf]) # check for __attribute__((packed)) # (sizeof() check is required to avoid false positives if other # __attribute__((x)) are supported) AC_MSG_CHECKING([whether $CXX supports __attribute__((packed))]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM(, [[ struct s { char a; short b; } __attribute__((packed)); typedef char t[sizeof(struct s) == 3 ? 1 : -1];]])], [gcc_have_attr_packed=yes], [gcc_have_attr_packed=no]) AC_SUBST(gcc_have_attr_packed) if test "$gcc_have_attr_packed" = "yes"; then AC_DEFINE(HAVE_ATTR_PACKED, 1, [Define to 1 if C++ compiler supports __attribute__((packed))]) fi AC_MSG_RESULT([$gcc_have_attr_packed]) AC_SUBST(CPPFLAGS) AC_SUBST(LDFLAGS) AC_SUBST(ASFLAGS) AC_ARG_WITH(systemdsystemunitdir, [AS_HELP_STRING([--with-systemdsystemunitdir@<:@=DIR|auto|yes|no@:>@], [Location of systemd service files [auto]])], [], [with_systemdsystemunitdir=auto]) systemdsystemunitdir= case "$with_systemdsystemunitdir" in auto|yes) if test -n "$PKG_CONFIG"; then AC_MSG_CHECKING([for systemdsystemunitdir]) systemdsystemunitdir=`$PKG_CONFIG --variable=systemdsystemunitdir systemd` AC_MSG_RESULT([${systemdsystemunitdir:-no}]) fi case "$with_systemdsystemunitdir:$sysconfdir:$systemdsystemunitdir" in yes:*:) AC_MSG_ERROR([Location of systemd service files not found]) ;; yes:*:*|auto:*:|auto:/etc:*) ;; *) systemdsystemunitdir='${prefix}'$systemdsystemunitdir ;; esac ;; no) ;; *) systemdsystemunitdir="$with_systemdsystemunitdir" ;; esac AC_SUBST(systemdsystemunitdir) AM_CONDITIONAL(INSTALL_SYSTEMDUNIT, [test -n "$systemdsystemunitdir"]) AC_ARG_WITH(initscriptdir, [AC_HELP_STRING([--with-initscriptdir@<:@=DIR|auto|yes|no@:>@], [Location of init scripts [auto]])], [], [with_initscriptdir=auto]) initddir= case "$with_initscriptdir:$cross_compiling:$systemdsystemunitdir" in auto:no:|yes:*) AC_MSG_CHECKING([for init (rc) directory]) for dir in rc.d/init.d init.d rc.d; do if test -d /etc/$dir; then initddir='${sysconfdir}'/$dir break fi done AC_MSG_RESULT([${initddir:-no}]) case "$with_initscriptdir:$initddir" in yes:) AC_MSG_ERROR([Location of init scripts not found]) ;; esac ;; auto:*|no:*) ;; *) initddir="$with_initscriptdir" ;; esac AC_SUBST(initddir) AM_CONDITIONAL(INSTALL_INITSCRIPT, [test -n "$initddir"]) # use different init script templates for different OS case "${host}" in *-*-freebsd*) initdfile="smartd.freebsd.initd" ;; *) initdfile="smartd.initd" ;; esac AC_SUBST(initdfile) AC_ARG_WITH(docdir, [AC_HELP_STRING([--with-docdir=DIR],[Location of documentation [DATADIR/doc/smartmontools]])], [docdir="$withval"], [ if test -z "$docdir"; then # autoconf 2.5x without '--docdir' support docdir='${datadir}/doc/${PACKAGE}' fi ]) AC_SUBST(docdir) AC_ARG_WITH(exampledir, [AC_HELP_STRING([--with-exampledir=DIR],[Location of example scripts [DOCDIR/examplescripts]])], [exampledir="$withval"], [exampledir='${docdir}/examplescripts']) AC_SUBST(exampledir) AC_ARG_ENABLE(drivedb, [AC_HELP_STRING([--disable-drivedb],[Disables drive database file])], [], [enable_drivedb=yes]) AC_ARG_WITH(drivedbdir, [AC_HELP_STRING([--with-drivedbdir=DIR],[Location of drive database file (implies --enable-drivedb) [DATADIR/smartmontools]])], [drivedbdir="$withval"; enable_drivedb=yes], [drivedbdir=; test "$enable_drivedb" = "yes" && drivedbdir='${datadir}/${PACKAGE}']) AC_SUBST(drivedbdir) AM_CONDITIONAL(ENABLE_DRIVEDB, [test "$enable_drivedb" = "yes"]) AC_ARG_ENABLE(savestates, [AC_HELP_STRING([--enable-savestates],[Enables default smartd state files])]) AC_ARG_WITH(savestates, [AC_HELP_STRING([--with-savestates=PREFIX],[Prefix for default smartd state files (implies --enable-savestates) [LOCALSTATEDIR/lib/smartmontools/smartd.]])], [savestates="$withval"; enable_savestates="yes"], [savestates=; test "$enable_savestates" = "yes" && savestates='${localstatedir}/lib/${PACKAGE}/smartd.']) savestatesdir="${savestates%/*}" AC_SUBST(savestates) AC_SUBST(savestatesdir) AM_CONDITIONAL(ENABLE_SAVESTATES, [test "$enable_savestates" = "yes"]) AC_ARG_ENABLE(attributelog, [AC_HELP_STRING([--enable-attributelog],[Enables default smartd attribute log files])]) AC_ARG_WITH(attributelog, [AC_HELP_STRING([--with-attributelog=PREFIX],[Prefix for default smartd attribute log files (implies --enable-attributelog) [LOCALSTATEDIR/lib/smartmontools/attrlog.]])], [attributelog="$withval"; enable_attributelog="yes"], [attributelog=; test "$enable_attributelog" = "yes" && attributelog='${localstatedir}/lib/${PACKAGE}/attrlog.']) attributelogdir="${attributelog%/*}" AC_SUBST(attributelog) AC_SUBST(attributelogdir) AM_CONDITIONAL(ENABLE_ATTRIBUTELOG, [test "$enable_attributelog" = "yes"]) AC_ARG_ENABLE(sample, [AC_HELP_STRING([--enable-sample],[Enables appending .sample to the installed smartd rc script and configuration file])], [smartd_suffix=; test "$enableval" = "yes" && smartd_suffix=".sample"], [smartd_suffix=;]) AC_SUBST(smartd_suffix) AC_ARG_WITH(os-deps, [AC_HELP_STRING([--with-os-deps='os_module.o ...'],[Specify OS dependent module(s) [guessed]])], [ for x in $with_os_deps; do case $x in *.o) ;; *) AC_MSG_ERROR([non-object file specified by --with-os-deps]) ;; esac done ],[]) AC_ARG_WITH(selinux, [AC_HELP_STRING([--with-selinux@<:@=yes|no@:>@],[Enables SELinux support [no]])], [ if test "$withval" = "yes"; then AC_CHECK_HEADERS([selinux/selinux.h], [], [AC_MSG_ERROR([Missing SELinux header files])]) AC_CHECK_LIB(selinux, matchpathcon, [], [AC_MSG_ERROR([Missing or incorrect SELinux library files])]) fi ],[]) AC_SUBST(with_selinux) if test "$with_selinux" = "yes"; then AC_DEFINE(WITH_SELINUX, 1, [Define to 1 if SELinux support is enabled]) fi AC_ARG_WITH(libcap-ng, [AC_HELP_STRING([--with-libcap-ng@<:@=auto|yes|no@:>@],[Add Libcap-ng support to smartd [auto]])], [], [with_libcap_ng=auto]) use_libcap_ng=no if test "$with_libcap_ng" != "no"; then AC_CHECK_LIB(cap-ng, capng_clear, [AC_DEFINE(HAVE_LIBCAP_NG, 1, [Define to 1 if you have the `cap-ng' library (-lcap-ng).]) CAPNG_LDADD="-lcap-ng"; use_libcap_ng=yes]) if test "$use_libcap_ng" = "yes"; then AC_CHECK_HEADER(cap-ng.h, [], [AC_MSG_ERROR([libcap-ng libraries found but headers are missing])]) elif test "$with_libcap_ng" = "yes"; then AC_MSG_ERROR([libcap-ng support was requested but the library was not found]) fi fi AC_MSG_CHECKING([whether to use libcap-ng]) AC_SUBST(CAPNG_LDADD) AM_CONDITIONAL(ENABLE_CAPABILITIES, [test "$use_libcap_ng" = "yes"]) AC_MSG_RESULT([$use_libcap_ng]) if test "$prefix" = "NONE"; then dnl no prefix and no mandir, so use ${prefix}/share/man as default if test "$mandir" = '${prefix}/man'; then AC_SUBST([mandir], ['${prefix}/share/man']) fi fi AC_SUBST(releaseversion,['${PACKAGE}-${VERSION}']) AC_SUBST(smartmontools_release_date) AC_SUBST(smartmontools_release_time) # Set platform-specific modules and symbols os_libs= os_dltools='curl wget lynx' os_mailer=mail os_hostname="'hostname'" os_dnsdomainname= os_nisdomainname="'domainname'" os_darwin=no os_solaris=no os_win32=no os_win32_mingw=no os_win64=no os_man_filter= case "${host}" in *-*-linux*) os_deps='os_linux.o cciss.o dev_areca.o' os_dnsdomainname="'dnsdomainname' 'hostname -d'" os_nisdomainname="'nisdomainname' 'hostname -y' 'domainname'" os_man_filter=Linux ;; *-*-freebsd*|*-*-dragonfly*|*-*-kfreebsd*-gnu*) os_deps='os_freebsd.o cciss.o dev_areca.o' os_libs='-lcam' os_dltools='curl wget lynx fetch' AC_CHECK_LIB(usb, libusb20_dev_get_device_desc) os_man_filter=FreeBSD ;; sparc-*-solaris*) os_deps='os_solaris.o os_solaris_ata.o' os_mailer='mailx' os_solaris=yes os_man_filter=Solaris ;; *-pc-solaris*) os_deps='os_solaris.o' os_mailer='mailx' os_solaris=yes os_man_filter=Solaris ;; *-*-netbsd*) os_deps='os_netbsd.o' os_libs='-lutil' os_man_filter=NetBSD ;; *-*-openbsd*) os_deps='os_openbsd.o' os_libs='-lutil' os_dltools='curl wget lynx ftp' os_man_filter=OpenBSD ;; *-*-cygwin*) os_deps='os_win32.o dev_areca.o' os_hostname="'hostname' 'echo "'"${HOSTNAME?unset}"'"'" os_dnsdomainname="'dnsdomainname' 'hostname -d' 'echo "'"${USERDNSDOMAIN?unset}"'"'" os_nisdomainname= os_win32=yes os_man_filter=Cygwin ;; x86_64-*-mingw*) os_deps='os_win32.o dev_areca.o' os_win32=yes os_win32_mingw=yes os_win64=yes os_man_filter=Windows ;; *-*-mingw*) os_deps='os_win32.o dev_areca.o' os_win32=yes os_win32_mingw=yes os_man_filter=Windows ;; *-*-darwin*) os_deps='os_darwin.o' os_libs='-framework CoreFoundation -framework IOKit' os_darwin=yes os_man_filter=Darwin ;; *-*-nto-qnx*) os_deps='os_qnxnto.o' ;; *) os_deps='os_generic.o' ;; esac # Replace if '--with-os-deps' was specified test -z "$with_os_deps" || os_deps="$with_os_deps" # Check if we need adapter to old interface (dev_legacy.cpp) os_src=`echo "${os_deps}"|sed -n 's,^\([[^ .]]*\)\.o.*$,\1.cpp,p'` AC_MSG_CHECKING([whether ${os_src} uses new interface]) if grep "smart_interface" "${srcdir}/${os_src}" >/dev/null 2>&1; then os_new_interface=yes else os_new_interface=no os_deps="${os_deps} dev_legacy.o" AC_DEFINE(OLD_INTERFACE, 1, [Define to 1 if os_*.cpp still uses the old interface]) fi AC_MSG_RESULT([$os_new_interface]) AC_SUBST([os_deps]) AC_SUBST([os_libs]) AC_SUBST([os_dltools]) AC_SUBST([os_mailer]) AC_SUBST([os_hostname]) AC_SUBST([os_dnsdomainname]) AC_SUBST([os_nisdomainname]) AC_SUBST([os_man_filter]) # Create drivedb.h update branch name from version: 5.41[.X] -> RELEASE_5_41_DRIVEDB DRIVEDB_BRANCH=`echo $VERSION | sed 's,^\([[0-9]]*\.[[0-9]]*\)\..*$,\1,' \ | sed -n 's,^\([[0-9]][[0-9]]*\)\.\([[0-9]][[0-9]]*\)$,RELEASE_\1_\2_DRIVEDB,p'` if test -z "$DRIVEDB_BRANCH"; then AC_MSG_ERROR([Unable to create DRIVEDB_BRANCH from VERSION=$VERSION]) fi AC_SUBST([DRIVEDB_BRANCH]) # Enable platform-specific makefile sections AM_CONDITIONAL(OS_DARWIN, [test "$os_darwin" = "yes"]) AM_CONDITIONAL(OS_SOLARIS, [test "$os_solaris" = "yes"]) AM_CONDITIONAL(OS_WIN32, [test "$os_win32" = "yes"]) AM_CONDITIONAL(OS_WIN32_MINGW, [test "$os_win32_mingw" = "yes"]) AM_CONDITIONAL(OS_WIN32_NSIS, [test -n "$MAKENSIS"]) AM_CONDITIONAL(OS_WIN64, [test "$os_win64" = "yes"]) dnl Add -Wall and -W if using g++ and its not already specified. if test "$GXX" = "yes"; then if test -z "`echo "$CXXFLAGS" | grep "\-Wall" 2> /dev/null`" ; then CXXFLAGS="$CXXFLAGS -Wall" fi # In the next line, do NOT delete the 2 spaces inside double quotes. if test -z "`echo "$CXXFLAGS " | grep "\-W " 2> /dev/null`" ; then CXXFLAGS="$CXXFLAGS -W" fi else dnl We are NOT using gcc, so enable host-specific compiler flags case "${host}" in sparc*-*-solaris*) dnl set CXXFLAGS for Solaris/SPARC C++ compiler if test -z "`echo "$CXXFLAGS" | grep "\-xmemalign" 2> /dev/null`" ; then dnl we have to tell the compilers about packed ATA structures CXXFLAGS="-xmemalign=1i $CXXFLAGS" fi esac case "${host}" in *-*-solaris*) if test -z "`echo "$CXXFLAGS" | grep "\-xO" 2> /dev/null`" ; then dnl turn on optimization if user has not explicitly set its value CXXFLAGS="-xO2 $CXXFLAGS" fi if test -z "`echo "$CXXFLAGS" | grep "\-erroff" 2> /dev/null`" ; then dnl suppress trivial warnings CXXFLAGS="-erroff=%none,wbadinitl,wbadasgl,badargtypel2w,badargtype2w $CXXFLAGS" fi esac fi AC_DEFINE_UNQUOTED(SMARTMONTOOLS_BUILD_HOST, "${host}", [smartmontools Build Host]) AC_SUBST(CXXFLAGS) AC_CONFIG_FILES(Makefile) AC_OUTPUT AC_PROG_MAKE_SET echo "-----------------------------------------------------------------------------" >&AS_MESSAGE_FD echo "${PACKAGE}-${VERSION} configuration:" >&AS_MESSAGE_FD echo "host operating system: $host" >&AS_MESSAGE_FD echo "C++ compiler: $CXX" >&AS_MESSAGE_FD echo "C compiler: $CC" >&AS_MESSAGE_FD echo "preprocessor flags: $CPPFLAGS" >&AS_MESSAGE_FD echo "C++ compiler flags: $CXXFLAGS" >&AS_MESSAGE_FD echo "C compiler flags: $CFLAGS" >&AS_MESSAGE_FD echo "linker flags: $LDFLAGS" >&AS_MESSAGE_FD echo "OS specific modules: $os_deps $os_libs $LIBS" >&AS_MESSAGE_FD case "$host_os" in mingw*) echo "resource compiler: $WINDRES" >&AS_MESSAGE_FD echo "message compiler: $WINDMC" >&AS_MESSAGE_FD echo "NSIS compiler: $MAKENSIS" >&AS_MESSAGE_FD if test -n "$drivedbdir"; then echo "drive database file: EXEDIR/drivedb.h" >&AS_MESSAGE_FD if test -n "$MAKENSIS"; then echo "database update tool: EXEDIR/update-smart-drivedb.exe" >&AS_MESSAGE_FD fi else echo "drive database file: [[disabled]]" >&AS_MESSAGE_FD fi if test -n "$savestates"; then echo "smartd save files: `eval eval eval echo $savestates`MODEL-SERIAL.TYPE.state" >&AS_MESSAGE_FD fi if test -n "$attributelog"; then echo "smartd attribute logs: `eval eval eval echo $attributelog`MODEL-SERIAL.TYPE.csv" >&AS_MESSAGE_FD fi ;; *) echo "binary install path: `eval eval eval echo $sbindir`" >&AS_MESSAGE_FD echo "man page install path: `eval eval eval echo $mandir`" >&AS_MESSAGE_FD echo "doc file install path: `eval eval eval echo $docdir`" >&AS_MESSAGE_FD echo "examples install path: `eval eval eval echo $exampledir`" >&AS_MESSAGE_FD if test -n "$drivedbdir"; then echo "drive database file: `eval eval eval echo $drivedbdir`/drivedb.h" >&AS_MESSAGE_FD echo "database update script: `eval eval eval echo $sbindir`/update-smart-drivedb" >&AS_MESSAGE_FD echo "download tools: `eval eval eval echo $os_dltools`" >&AS_MESSAGE_FD else echo "drive database file: [[disabled]]" >&AS_MESSAGE_FD fi echo "local drive database: `eval eval eval echo $sysconfdir`/smart_drivedb.h" >&AS_MESSAGE_FD echo "smartd config file: `eval eval eval echo $sysconfdir`/smartd.conf${smartd_suffix}" >&AS_MESSAGE_FD echo "smartd warning script: `eval eval eval echo $sysconfdir`/smartd_warning.sh" >&AS_MESSAGE_FD if test -n "$initddir"; then echo "smartd initd script: `eval eval eval echo $initddir`/smartd${smartd_suffix}" >&AS_MESSAGE_FD elif test -z "$systemdsystemunitdir"; then echo "smartd initd script: [[disabled]]" >&AS_MESSAGE_FD fi if test -n "$systemdsystemunitdir"; then echo "smartd systemd file: `eval eval eval echo $systemdsystemunitdir`/smartd.service" >&AS_MESSAGE_FD fi if test -n "$savestates"; then echo "smartd save files: `eval eval eval echo $savestates`MODEL-SERIAL.TYPE.state" >&AS_MESSAGE_FD else echo "smartd save files: [[disabled]]" >&AS_MESSAGE_FD fi if test -n "$attributelog"; then echo "smartd attribute logs: `eval eval eval echo $attributelog`MODEL-SERIAL.TYPE.csv" >&AS_MESSAGE_FD else echo "smartd attribute logs: [[disabled]]" >&AS_MESSAGE_FD fi echo "libcap-ng support: $use_libcap_ng" >&AS_MESSAGE_FD case "$host_os" in linux*) echo "SELinux support: ${with_selinux-no}" >&AS_MESSAGE_FD ;; esac ;; esac echo "-----------------------------------------------------------------------------" >&AS_MESSAGE_FD �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartctl.cpp���������������������������������������������������������0000644�0000000�0000000�00000134511�12166111311�017414� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * smartctl.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #include <errno.h> #include <stdio.h> #include <sys/types.h> #include <string.h> #include <stdarg.h> #include <stdexcept> #include <getopt.h> #include "config.h" #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #if defined(__FreeBSD__) #include <sys/param.h> #endif #include "int64.h" #include "atacmds.h" #include "dev_interface.h" #include "ataprint.h" #include "knowndrives.h" #include "scsicmds.h" #include "scsiprint.h" #include "smartctl.h" #include "utility.h" const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 3826 2013-07-06 21:57:29Z samm2 $" CONFIG_H_CVSID SMARTCTL_H_CVSID; // Globals to control printing bool printing_is_switchable = false; bool printing_is_off = false; static void printslogan() { pout("%s\n", format_version_info("smartctl").c_str()); } static void UsageSummary() { pout("\nUse smartctl -h to get a usage summary\n\n"); return; } static std::string getvalidarglist(int opt); /* void prints help information for command syntax */ static void Usage() { printf("Usage: smartctl [options] device\n\n"); printf( "============================================ SHOW INFORMATION OPTIONS =====\n\n" " -h, --help, --usage\n" " Display this help and exit\n\n" " -V, --version, --copyright, --license\n" " Print license, copyright, and version information and exit\n\n" " -i, --info\n" " Show identity information for device\n\n" " --identify[=[w][nvb]]\n" " Show words and bits from IDENTIFY DEVICE data (ATA)\n\n" " -g NAME, --get=NAME\n" " Get device setting: all, aam, apm, lookahead, security, wcache, rcache, wcreorder\n\n" " -a, --all\n" " Show all SMART information for device\n\n" " -x, --xall\n" " Show all information for device\n\n" " --scan\n" " Scan for devices\n\n" " --scan-open\n" " Scan for devices and try to open each device\n\n" ); printf( "================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n" " -q TYPE, --quietmode=TYPE (ATA)\n" " Set smartctl quiet mode to one of: errorsonly, silent, noserial\n\n" " -d TYPE, --device=TYPE\n" " Specify device type to one of: %s\n\n" " -T TYPE, --tolerance=TYPE (ATA)\n" " Tolerance: normal, conservative, permissive, verypermissive\n\n" " -b TYPE, --badsum=TYPE (ATA)\n" " Set action on bad checksum to one of: warn, exit, ignore\n\n" " -r TYPE, --report=TYPE\n" " Report transactions (see man page)\n\n" " -n MODE, --nocheck=MODE (ATA)\n" " No check if: never, sleep, standby, idle (see man page)\n\n", getvalidarglist('d').c_str()); // TODO: Use this function also for other options ? printf( "============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n" " -s VALUE, --smart=VALUE\n" " Enable/disable SMART on device (on/off)\n\n" " -o VALUE, --offlineauto=VALUE (ATA)\n" " Enable/disable automatic offline testing on device (on/off)\n\n" " -S VALUE, --saveauto=VALUE (ATA)\n" " Enable/disable Attribute autosave on device (on/off)\n\n" " -s NAME[,VALUE], --set=NAME[,VALUE]\n" " Enable/disable/change device setting: aam,[N|off], apm,[N|off],\n" " lookahead,[on|off], security-freeze, standby,[N|off|now],\n" " wcache,[on|off], rcache,[on|off], wcreorder,[on|off]\n\n" ); printf( "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n" " -H, --health\n" " Show device SMART health status\n\n" " -c, --capabilities (ATA)\n" " Show device SMART capabilities\n\n" " -A, --attributes\n" " Show device SMART vendor-specific Attributes and values\n\n" " -f FORMAT, --format=FORMAT (ATA)\n" " Set output format for attributes: old, brief, hex[,id|val]\n\n" " -l TYPE, --log=TYPE\n" " Show device log. TYPE: error, selftest, selective, directory[,g|s],\n" " xerror[,N][,error], xselftest[,N][,selftest],\n" " background, sasphy[,reset], sataphy[,reset],\n" " scttemp[sts,hist], scttempint,N[,p],\n" " scterc[,N,M], devstat[,N], ssd,\n" " gplog,N[,RANGE], smartlog,N[,RANGE]\n\n" " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n" " Set display OPTION for vendor Attribute N (see man page)\n\n" " -F TYPE, --firmwarebug=TYPE (ATA)\n" " Use firmware bug workaround:\n" " %s, swapid\n\n" " -P TYPE, --presets=TYPE (ATA)\n" " Drive-specific presets: use, ignore, show, showall\n\n" " -B [+]FILE, --drivedb=[+]FILE (ATA)\n" " Read and replace [add] drive database from FILE\n" " [default is +%s", get_valid_firmwarebug_args(), get_drivedb_path_add() ); #ifdef SMARTMONTOOLS_DRIVEDBDIR printf( "\n" " and then %s", get_drivedb_path_default() ); #endif printf( "]\n\n" "============================================ DEVICE SELF-TEST OPTIONS =====\n\n" " -t TEST, --test=TEST\n" " Run test. TEST: offline, short, long, conveyance, force, vendor,N,\n" " select,M-N, pending,N, afterselect,[on|off]\n\n" " -C, --captive\n" " Do test in captive mode (along with -t)\n\n" " -X, --abort\n" " Abort any non-captive test on device\n\n" ); std::string examples = smi()->get_app_examples("smartctl"); if (!examples.empty()) printf("%s\n", examples.c_str()); } // Values for --long only options, see parse_options() enum { opt_identify = 1000, opt_scan, opt_scan_open, opt_set, opt_smart }; /* Returns a string containing a formatted list of the valid arguments to the option opt or empty on failure. Note 'v' case different */ static std::string getvalidarglist(int opt) { switch (opt) { case 'q': return "errorsonly, silent, noserial"; case 'd': return smi()->get_valid_dev_types_str() + ", auto, test"; case 'T': return "normal, conservative, permissive, verypermissive"; case 'b': return "warn, exit, ignore"; case 'r': return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; case opt_smart: case 'o': case 'S': return "on, off"; case 'l': return "error, selftest, selective, directory[,g|s], " "xerror[,N][,error], xselftest[,N][,selftest], " "background, sasphy[,reset], sataphy[,reset], " "scttemp[sts,hist], scttempint,N[,p], " "scterc[,N,M], devstat[,N], ssd, " "gplog,N[,RANGE], smartlog,N[,RANGE]"; case 'P': return "use, ignore, show, showall"; case 't': return "offline, short, long, conveyance, force, vendor,N, select,M-N, " "pending,N, afterselect,[on|off]"; case 'F': return std::string(get_valid_firmwarebug_args()) + ", swapid"; case 'n': return "never, sleep, standby, idle"; case 'f': return "old, brief, hex[,id|val]"; case 'g': return "aam, apm, lookahead, security, wcache, rcache, wcreorder"; case opt_set: return "aam,[N|off], apm,[N|off], lookahead,[on|off], security-freeze, " "standby,[N|off|now], wcache,[on|off], rcache,[on|off], wcreorder,[on|off]"; case 's': return getvalidarglist(opt_smart)+", "+getvalidarglist(opt_set); case opt_identify: return "n, wn, w, v, wv, wb"; case 'v': default: return ""; } } /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where <LIST> is the list of valid arguments for option opt. */ static void printvalidarglistmessage(int opt) { if (opt=='v'){ pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", create_vendor_attribute_arg_list().c_str()); } else { // getvalidarglist() might produce a multiline or single line string. We // need to figure out which to get the formatting right. std::string s = getvalidarglist(opt); char separator = strchr(s.c_str(), '\n') ? '\n' : ' '; pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, s.c_str(), separator); } return; } // Checksum error mode enum checksum_err_mode_t { CHECKSUM_ERR_WARN, CHECKSUM_ERR_EXIT, CHECKSUM_ERR_IGNORE }; static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN; static void scan_devices(const char * type, bool with_open, char ** argv); /* Takes command options and sets features to be run */ static const char * parse_options(int argc, char** argv, ata_print_options & ataopts, scsi_print_options & scsiopts, bool & print_type_only) { // Please update getvalidarglist() if you edit shortopts const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:f:g:"; // Please update getvalidarglist() if you edit longopts struct option longopts[] = { { "help", no_argument, 0, 'h' }, { "usage", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "copyright", no_argument, 0, 'V' }, { "license", no_argument, 0, 'V' }, { "quietmode", required_argument, 0, 'q' }, { "device", required_argument, 0, 'd' }, { "tolerance", required_argument, 0, 'T' }, { "badsum", required_argument, 0, 'b' }, { "report", required_argument, 0, 'r' }, { "smart", required_argument, 0, opt_smart }, { "offlineauto", required_argument, 0, 'o' }, { "saveauto", required_argument, 0, 'S' }, { "health", no_argument, 0, 'H' }, { "capabilities", no_argument, 0, 'c' }, { "attributes", no_argument, 0, 'A' }, { "log", required_argument, 0, 'l' }, { "info", no_argument, 0, 'i' }, { "all", no_argument, 0, 'a' }, { "xall", no_argument, 0, 'x' }, { "vendorattribute", required_argument, 0, 'v' }, { "presets", required_argument, 0, 'P' }, { "test", required_argument, 0, 't' }, { "captive", no_argument, 0, 'C' }, { "abort", no_argument, 0, 'X' }, { "firmwarebug", required_argument, 0, 'F' }, { "nocheck", required_argument, 0, 'n' }, { "drivedb", required_argument, 0, 'B' }, { "format", required_argument, 0, 'f' }, { "get", required_argument, 0, 'g' }, { "identify", optional_argument, 0, opt_identify }, { "set", required_argument, 0, opt_set }, { "scan", no_argument, 0, opt_scan }, { "scan-open", no_argument, 0, opt_scan_open }, { 0, 0, 0, 0 } }; char extraerror[256]; memset(extraerror, 0, sizeof(extraerror)); opterr=optopt=0; const char * type = 0; // set to -d optarg bool no_defaultdb = false; // set true on '-B FILE' bool output_format_set = false; // set true on '-f FORMAT' int scan = 0; // set by --scan, --scan-open bool badarg = false, captive = false; int testcnt = 0; // number of self-tests requested int optchar; char *arg; while ((optchar = getopt_long(argc, argv, shortopts, longopts, 0)) != -1) { switch (optchar){ case 'V': printing_is_off = false; pout("%s", format_version_info("smartctl", true /*full*/).c_str()); EXIT(0); break; case 'q': if (!strcmp(optarg,"errorsonly")) { printing_is_switchable = true; printing_is_off = false; } else if (!strcmp(optarg,"silent")) { printing_is_switchable = false; printing_is_off = true; } else if (!strcmp(optarg,"noserial")) { dont_print_serial_number = true; } else { badarg = true; } break; case 'd': if (!strcmp(optarg, "test")) print_type_only = true; else type = (strcmp(optarg, "auto") ? optarg : (char *)0); break; case 'T': if (!strcmp(optarg,"normal")) { failuretest_conservative = false; failuretest_permissive = 0; } else if (!strcmp(optarg,"conservative")) { failuretest_conservative = true; } else if (!strcmp(optarg,"permissive")) { if (failuretest_permissive < 0xff) failuretest_permissive++; } else if (!strcmp(optarg,"verypermissive")) { failuretest_permissive = 0xff; } else { badarg = true; } break; case 'b': if (!strcmp(optarg,"warn")) { checksum_err_mode = CHECKSUM_ERR_WARN; } else if (!strcmp(optarg,"exit")) { checksum_err_mode = CHECKSUM_ERR_EXIT; } else if (!strcmp(optarg,"ignore")) { checksum_err_mode = CHECKSUM_ERR_IGNORE; } else { badarg = true; } break; case 'r': { int i; char *s; // split_report_arg() may modify its first argument string, so use a // copy of optarg in case we want optarg for an error message. if (!(s = strdup(optarg))) { throw std::bad_alloc(); } if (split_report_arg(s, &i)) { badarg = true; } else if (!strcmp(s,"ioctl")) { ata_debugmode = scsi_debugmode = i; } else if (!strcmp(s,"ataioctl")) { ata_debugmode = i; } else if (!strcmp(s,"scsiioctl")) { scsi_debugmode = i; } else { badarg = true; } free(s); } break; case 's': case opt_smart: // --smart if (!strcmp(optarg,"on")) { ataopts.smart_enable = scsiopts.smart_enable = true; ataopts.smart_disable = scsiopts.smart_disable = false; } else if (!strcmp(optarg,"off")) { ataopts.smart_disable = scsiopts.smart_disable = true; ataopts.smart_enable = scsiopts.smart_enable = false; } else if (optchar == 's') { goto case_s_continued; // --set, see below } else { badarg = true; } break; case 'o': if (!strcmp(optarg,"on")) { ataopts.smart_auto_offl_enable = true; ataopts.smart_auto_offl_disable = false; } else if (!strcmp(optarg,"off")) { ataopts.smart_auto_offl_disable = true; ataopts.smart_auto_offl_enable = false; } else { badarg = true; } break; case 'S': if (!strcmp(optarg,"on")) { ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = true; ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = false; } else if (!strcmp(optarg,"off")) { ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = true; ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = false; } else { badarg = true; } break; case 'H': ataopts.smart_check_status = scsiopts.smart_check_status = true; scsiopts.smart_ss_media_log = true; break; case 'F': if (!strcmp(optarg, "swapid")) ataopts.fix_swapped_id = true; else if (!parse_firmwarebug_def(optarg, ataopts.firmwarebugs)) badarg = true; break; case 'c': ataopts.smart_general_values = true; break; case 'A': ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; break; case 'l': if (!strcmp(optarg,"error")) { ataopts.smart_error_log = scsiopts.smart_error_log = true; } else if (!strcmp(optarg,"selftest")) { ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true; } else if (!strcmp(optarg, "selective")) { ataopts.smart_selective_selftest_log = true; } else if (!strcmp(optarg,"directory")) { ataopts.smart_logdir = ataopts.gp_logdir = true; // SMART+GPL } else if (!strcmp(optarg,"directory,s")) { ataopts.smart_logdir = true; // SMART } else if (!strcmp(optarg,"directory,g")) { ataopts.gp_logdir = true; // GPL } else if (!strcmp(optarg,"sasphy")) { scsiopts.sasphy = true; } else if (!strcmp(optarg,"sasphy,reset")) { scsiopts.sasphy = scsiopts.sasphy_reset = true; } else if (!strcmp(optarg,"sataphy")) { ataopts.sataphy = true; } else if (!strcmp(optarg,"sataphy,reset")) { ataopts.sataphy = ataopts.sataphy_reset = true; } else if (!strcmp(optarg,"background")) { scsiopts.smart_background_log = true; } else if (!strcmp(optarg,"ssd")) { ataopts.devstat_ssd_page = true; scsiopts.smart_ss_media_log = true; } else if (!strcmp(optarg,"scterc")) { ataopts.sct_erc_get = true; } else if (!strcmp(optarg,"scttemp")) { ataopts.sct_temp_sts = ataopts.sct_temp_hist = true; } else if (!strcmp(optarg,"scttempsts")) { ataopts.sct_temp_sts = true; } else if (!strcmp(optarg,"scttemphist")) { ataopts.sct_temp_hist = true; } else if (!strncmp(optarg, "scttempint,", sizeof("scstempint,")-1)) { unsigned interval = 0; int n1 = -1, n2 = -1, len = strlen(optarg); if (!( sscanf(optarg,"scttempint,%u%n,p%n", &interval, &n1, &n2) == 1 && 0 < interval && interval <= 0xffff && (n1 == len || n2 == len))) { snprintf(extraerror, sizeof(extraerror), "Option -l scttempint,N[,p] must have positive integer N\n"); badarg = true; } ataopts.sct_temp_int = interval; ataopts.sct_temp_int_pers = (n2 == len); } else if (!strncmp(optarg, "devstat", sizeof("devstat")-1)) { int n1 = -1, n2 = -1, len = strlen(optarg); unsigned val = ~0; sscanf(optarg, "devstat%n,%u%n", &n1, &val, &n2); if (n1 == len) ataopts.devstat_all_pages = true; else if (n2 == len && val <= 255) ataopts.devstat_pages.push_back(val); else badarg = true; } else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) { int n1 = -1, n2 = -1, len = strlen(optarg); unsigned val = 8; sscanf(optarg, "xerror%n,error%n", &n1, &n2); if (!(n1 == len || n2 == len)) { n1 = n2 = -1; sscanf(optarg, "xerror,%u%n,error%n", &val, &n1, &n2); } if ((n1 == len || n2 == len) && val > 0) { ataopts.smart_ext_error_log = val; ataopts.retry_error_log = (n2 == len); } else badarg = true; } else if (!strncmp(optarg, "xselftest", sizeof("xselftest")-1)) { int n1 = -1, n2 = -1, len = strlen(optarg); unsigned val = 25; sscanf(optarg, "xselftest%n,selftest%n", &n1, &n2); if (!(n1 == len || n2 == len)) { n1 = n2 = -1; sscanf(optarg, "xselftest,%u%n,selftest%n", &val, &n1, &n2); } if ((n1 == len || n2 == len) && val > 0) { ataopts.smart_ext_selftest_log = val; ataopts.retry_selftest_log = (n2 == len); } else badarg = true; } else if (!strncmp(optarg, "scterc,", sizeof("scterc,")-1)) { unsigned rt = ~0, wt = ~0; int n = -1; sscanf(optarg,"scterc,%u,%u%n", &rt, &wt, &n); if (n == (int)strlen(optarg) && rt <= 999 && wt <= 999) { ataopts.sct_erc_set = true; ataopts.sct_erc_readtime = rt; ataopts.sct_erc_writetime = wt; } else { snprintf(extraerror, sizeof(extraerror), "Option -l scterc,[READTIME,WRITETIME] syntax error\n"); badarg = true; } } else if ( !strncmp(optarg, "gplog," , sizeof("gplog," )-1) || !strncmp(optarg, "smartlog,", sizeof("smartlog,")-1)) { unsigned logaddr = ~0U; unsigned page = 0, nsectors = 1; char sign = 0; int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg); sscanf(optarg, "%*[a-z],0x%x%n,%u%n%c%u%n", &logaddr, &n1, &page, &n2, &sign, &nsectors, &n3); if (len > n2 && n3 == -1 && !strcmp(optarg+n2, "-max")) { nsectors = ~0U; sign = '+'; n3 = len; } bool gpl = (optarg[0] == 'g'); const char * erropt = (gpl ? "gplog" : "smartlog"); if (!( n1 == len || n2 == len || (n3 == len && (sign == '+' || sign == '-')))) { snprintf(extraerror, sizeof(extraerror), "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] syntax error\n", erropt); badarg = true; } else if (!( logaddr <= 0xff && page <= (gpl ? 0xffffU : 0x00ffU) && 0 < nsectors && (nsectors <= (gpl ? 0xffffU : 0xffU) || nsectors == ~0U) && (sign != '-' || page <= nsectors) )) { snprintf(extraerror, sizeof(extraerror), "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] parameter out of range\n", erropt); badarg = true; } else { ata_log_request req; req.gpl = gpl; req.logaddr = logaddr; req.page = page; req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors); ataopts.log_requests.push_back(req); } } else { badarg = true; } break; case 'i': ataopts.drive_info = scsiopts.drive_info = true; break; case opt_identify: ataopts.identify_word_level = ataopts.identify_bit_level = 0; if (optarg) { for (int i = 0; optarg[i]; i++) { switch (optarg[i]) { case 'w': ataopts.identify_word_level = 1; break; case 'n': ataopts.identify_bit_level = -1; break; case 'v': ataopts.identify_bit_level = 1; break; case 'b': ataopts.identify_bit_level = 2; break; default: badarg = true; } } } break; case 'a': ataopts.drive_info = scsiopts.drive_info = true; ataopts.smart_check_status = scsiopts.smart_check_status = true; ataopts.smart_general_values = true; ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; ataopts.smart_error_log = scsiopts.smart_error_log = true; ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true; ataopts.smart_selective_selftest_log = true; /* scsiopts.smart_background_log = true; */ scsiopts.smart_ss_media_log = true; break; case 'x': ataopts.drive_info = scsiopts.drive_info = true; ataopts.smart_check_status = scsiopts.smart_check_status = true; ataopts.smart_general_values = true; ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true; ataopts.smart_ext_error_log = 8; ataopts.retry_error_log = true; ataopts.smart_ext_selftest_log = 25; ataopts.retry_selftest_log = true; scsiopts.smart_error_log = scsiopts.smart_selftest_log = true; ataopts.smart_selective_selftest_log = true; ataopts.smart_logdir = ataopts.gp_logdir = true; ataopts.sct_temp_sts = ataopts.sct_temp_hist = true; ataopts.sct_erc_get = true; ataopts.sct_wcache_reorder_get = true; ataopts.devstat_all_pages = true; ataopts.sataphy = true; ataopts.get_set_used = true; ataopts.get_aam = ataopts.get_apm = true; ataopts.get_security = true; ataopts.get_lookahead = ataopts.get_wcache = true; scsiopts.get_rcd = scsiopts.get_wce = true; scsiopts.smart_background_log = true; scsiopts.smart_ss_media_log = true; scsiopts.sasphy = true; if (!output_format_set) ataopts.output_format |= ata_print_options::FMT_BRIEF; break; case 'v': // parse vendor-specific definitions of attributes if (!strcmp(optarg,"help")) { printing_is_off = false; printslogan(); pout("The valid arguments to -v are:\n\thelp\n%s\n", create_vendor_attribute_arg_list().c_str()); EXIT(0); } if (!parse_attribute_def(optarg, ataopts.attribute_defs, PRIOR_USER)) badarg = true; break; case 'P': if (!strcmp(optarg, "use")) { ataopts.ignore_presets = false; } else if (!strcmp(optarg, "ignore")) { ataopts.ignore_presets = true; } else if (!strcmp(optarg, "show")) { ataopts.show_presets = true; } else if (!strcmp(optarg, "showall")) { if (!no_defaultdb && !read_default_drive_databases()) EXIT(FAILCMD); if (optind < argc) { // -P showall MODEL [FIRMWARE] int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL)); EXIT(cnt); // report #matches } if (showallpresets()) EXIT(FAILCMD); // report regexp syntax error EXIT(0); } else { badarg = true; } break; case 't': if (!strcmp(optarg,"offline")) { testcnt++; ataopts.smart_selftest_type = OFFLINE_FULL_SCAN; scsiopts.smart_default_selftest = true; } else if (!strcmp(optarg,"short")) { testcnt++; ataopts.smart_selftest_type = SHORT_SELF_TEST; scsiopts.smart_short_selftest = true; } else if (!strcmp(optarg,"long")) { testcnt++; ataopts.smart_selftest_type = EXTEND_SELF_TEST; scsiopts.smart_extend_selftest = true; } else if (!strcmp(optarg,"conveyance")) { testcnt++; ataopts.smart_selftest_type = CONVEYANCE_SELF_TEST; } else if (!strcmp(optarg,"force")) { ataopts.smart_selftest_force = true; scsiopts.smart_selftest_force = true; } else if (!strcmp(optarg,"afterselect,on")) { // scan remainder of disk after doing selected segment ataopts.smart_selective_args.scan_after_select = 2; } else if (!strcmp(optarg,"afterselect,off")) { // don't scan remainder of disk after doing selected segments ataopts.smart_selective_args.scan_after_select = 1; } else if (!strncmp(optarg,"pending,",strlen("pending,"))) { // parse number of minutes that test should be pending int i; char *tailptr=NULL; errno=0; i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10); if (errno || *tailptr != '\0') { snprintf(extraerror, sizeof(extraerror), "Option -t pending,N requires N to be a non-negative integer\n"); badarg = true; } else if (i<0 || i>65535) { snprintf(extraerror, sizeof(extraerror), "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i); badarg = true; } else { ataopts.smart_selective_args.pending_time = i+1; } } else if (!strncmp(optarg,"select",strlen("select"))) { if (ataopts.smart_selective_args.num_spans == 0) testcnt++; // parse range of LBAs to test uint64_t start, stop; int mode; if (split_selective_arg(optarg, &start, &stop, &mode)) { snprintf(extraerror, sizeof(extraerror), "Option -t select,M-N must have non-negative integer M and N\n"); badarg = true; } else { if (ataopts.smart_selective_args.num_spans >= 5 || start > stop) { if (start > stop) { snprintf(extraerror, sizeof(extraerror), "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n", start, stop, optarg); } else { snprintf(extraerror, sizeof(extraerror),"ERROR: No more than five selective self-test spans may be" " defined\n"); } badarg = true; } ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].start = start; ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].end = stop; ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].mode = mode; ataopts.smart_selective_args.num_spans++; ataopts.smart_selftest_type = SELECTIVE_SELF_TEST; } } else if (!strncmp(optarg, "scttempint", sizeof("scstempint")-1)) { snprintf(extraerror, sizeof(extraerror), "-t scttempint is no longer supported, use -l scttempint instead\n"); badarg = true; } else if (!strncmp(optarg, "vendor,", sizeof("vendor,")-1)) { unsigned subcmd = ~0U; int n = -1; if (!( sscanf(optarg, "%*[a-z],0x%x%n", &subcmd, &n) == 1 && subcmd <= 0xff && n == (int)strlen(optarg))) { snprintf(extraerror, sizeof(extraerror), "Option -t vendor,0xNN syntax error\n"); badarg = true; } else ataopts.smart_selftest_type = subcmd; } else { badarg = true; } break; case 'C': captive = true; break; case 'X': testcnt++; scsiopts.smart_selftest_abort = true; ataopts.smart_selftest_type = ABORT_SELF_TEST; break; case 'n': // skip disk check if in low-power mode if (!strcmp(optarg, "never")) ataopts.powermode = 1; // do not skip, but print mode else if (!strcmp(optarg, "sleep")) ataopts.powermode = 2; else if (!strcmp(optarg, "standby")) ataopts.powermode = 3; else if (!strcmp(optarg, "idle")) ataopts.powermode = 4; else badarg = true; break; case 'f': if (!strcmp(optarg, "old")) { ataopts.output_format &= ~ata_print_options::FMT_BRIEF; output_format_set = true; } else if (!strcmp(optarg, "brief")) { ataopts.output_format |= ata_print_options::FMT_BRIEF; output_format_set = true; } else if (!strcmp(optarg, "hex")) ataopts.output_format |= ata_print_options::FMT_HEX_ID | ata_print_options::FMT_HEX_VAL; else if (!strcmp(optarg, "hex,id")) ataopts.output_format |= ata_print_options::FMT_HEX_ID; else if (!strcmp(optarg, "hex,val")) ataopts.output_format |= ata_print_options::FMT_HEX_VAL; else badarg = true; break; case 'B': { const char * path = optarg; if (*path == '+' && path[1]) path++; else no_defaultdb = true; if (!read_drive_database(path)) EXIT(FAILCMD); } break; case 'h': printing_is_off = false; printslogan(); Usage(); EXIT(0); break; case 'g': case_s_continued: // -s, see above case opt_set: // --set { ataopts.get_set_used = true; bool get = (optchar == 'g'); char name[16+1]; unsigned val; int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg); if (sscanf(optarg, "%16[^,=]%n%*[,=]%n%u%n", name, &n1, &n2, &val, &n3) >= 1 && (n1 == len || (!get && n2 > 0))) { bool on = (n2 > 0 && !strcmp(optarg+n2, "on")); bool off = (n2 > 0 && !strcmp(optarg+n2, "off")); if (n3 != len) val = ~0U; if (get && !strcmp(name, "all")) { ataopts.get_aam = ataopts.get_apm = true; ataopts.get_security = true; ataopts.get_lookahead = ataopts.get_wcache = true; scsiopts.get_rcd = scsiopts.get_wce = true; } else if (!strcmp(name, "aam")) { if (get) ataopts.get_aam = true; else if (off) ataopts.set_aam = -1; else if (val <= 254) ataopts.set_aam = val + 1; else { snprintf(extraerror, sizeof(extraerror), "Option -s aam,N must have 0 <= N <= 254\n"); badarg = true; } } else if (!strcmp(name, "apm")) { if (get) ataopts.get_apm = true; else if (off) ataopts.set_apm = -1; else if (1 <= val && val <= 254) ataopts.set_apm = val + 1; else { snprintf(extraerror, sizeof(extraerror), "Option -s apm,N must have 1 <= N <= 254\n"); badarg = true; } } else if (!strcmp(name, "lookahead")) { if (get) { ataopts.get_lookahead = true; } else if (off) ataopts.set_lookahead = -1; else if (on) ataopts.set_lookahead = 1; else badarg = true; } else if (!strcmp(name, "wcreorder")) { if (get) { ataopts.sct_wcache_reorder_get = true; } else if (off) ataopts.sct_wcache_reorder_set = -1; else if (on) ataopts.sct_wcache_reorder_set = 1; else badarg = true; } else if (!strcmp(name, "rcache")) { if (get) scsiopts.get_rcd = true; else if (off) scsiopts.set_rcd = -1; else if (on) scsiopts.set_rcd = 1; else badarg = true; } else if (get && !strcmp(name, "security")) { ataopts.get_security = true; } else if (!get && !strcmp(optarg, "security-freeze")) { ataopts.set_security_freeze = true; } else if (!get && !strcmp(optarg, "standby,now")) { ataopts.set_standby_now = true; } else if (!get && !strcmp(name, "standby")) { if (off) ataopts.set_standby = 0 + 1; else if (val <= 255) ataopts.set_standby = val + 1; else { snprintf(extraerror, sizeof(extraerror), "Option -s standby,N must have 0 <= N <= 255\n"); badarg = true; } } else if (!strcmp(name, "wcache")) { if (get) { ataopts.get_wcache = true; scsiopts.get_wce = true; } else if (off) { ataopts.set_wcache = -1; scsiopts.set_wce = -1; } else if (on) { ataopts.set_wcache = 1; scsiopts.set_wce = 1; } else badarg = true; } else badarg = true; } else badarg = true; } break; case opt_scan: case opt_scan_open: scan = optchar; break; case '?': default: printing_is_off = false; printslogan(); // Point arg to the argument in which this option was found. arg = argv[optind-1]; // Check whether the option is a long option that doesn't map to -h. if (arg[1] == '-' && optchar != 'h') { // Iff optopt holds a valid option then argument must be missing. if (optopt && (optopt >= opt_scan || strchr(shortopts, optopt))) { pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2); printvalidarglistmessage(optopt); } else pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2); if (extraerror[0]) pout("=======> %s", extraerror); UsageSummary(); EXIT(FAILCMD); } if (0 < optopt && optopt < '~') { // Iff optopt holds a valid option then argument must be // missing. Note (BA) this logic seems to fail using Solaris // getopt! if (strchr(shortopts, optopt) != NULL) { pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt); printvalidarglistmessage(optopt); } else pout("=======> UNRECOGNIZED OPTION: %c\n",optopt); if (extraerror[0]) pout("=======> %s", extraerror); UsageSummary(); EXIT(FAILCMD); } Usage(); EXIT(0); } // closes switch statement to process command-line options // Check to see if option had an unrecognized or incorrect argument. if (badarg) { printslogan(); // It would be nice to print the actual option name given by the user // here, but we just print the short form. Please fix this if you know // a clean way to do it. char optstr[] = { (char)optchar, 0 }; pout("=======> INVALID ARGUMENT TO -%s: %s\n", (optchar == opt_identify ? "-identify" : optchar == opt_set ? "-set" : optchar == opt_smart ? "-smart" : optstr), optarg); printvalidarglistmessage(optchar); if (extraerror[0]) pout("=======> %s", extraerror); UsageSummary(); EXIT(FAILCMD); } } // Special handling of --scan, --scanopen if (scan) { // Read or init drive database to allow USB ID check. if (!no_defaultdb && !read_default_drive_databases()) EXIT(FAILCMD); scan_devices(type, (scan == opt_scan_open), argv + optind); EXIT(0); } // At this point we have processed all command-line options. If the // print output is switchable, then start with the print output // turned off if (printing_is_switchable) printing_is_off = true; // error message if user has asked for more than one test if (testcnt > 1) { printing_is_off = false; printslogan(); pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n"); UsageSummary(); EXIT(FAILCMD); } // error message if user has set selective self-test options without // asking for a selective self-test if ( (ataopts.smart_selective_args.pending_time || ataopts.smart_selective_args.scan_after_select) && !ataopts.smart_selective_args.num_spans) { printing_is_off = false; printslogan(); if (ataopts.smart_selective_args.pending_time) pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n"); else pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n"); UsageSummary(); EXIT(FAILCMD); } // If captive option was used, change test type if appropriate. if (captive) switch (ataopts.smart_selftest_type) { case SHORT_SELF_TEST: ataopts.smart_selftest_type = SHORT_CAPTIVE_SELF_TEST; scsiopts.smart_short_selftest = false; scsiopts.smart_short_cap_selftest = true; break; case EXTEND_SELF_TEST: ataopts.smart_selftest_type = EXTEND_CAPTIVE_SELF_TEST; scsiopts.smart_extend_selftest = false; scsiopts.smart_extend_cap_selftest = true; break; case CONVEYANCE_SELF_TEST: ataopts.smart_selftest_type = CONVEYANCE_CAPTIVE_SELF_TEST; break; case SELECTIVE_SELF_TEST: ataopts.smart_selftest_type = SELECTIVE_CAPTIVE_SELF_TEST; break; } // From here on, normal operations... printslogan(); // Warn if the user has provided no device name if (argc-optind<1){ pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n"); UsageSummary(); EXIT(FAILCMD); } // Warn if the user has provided more than one device name if (argc-optind>1){ int i; pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n"); pout("You have provided %d device names:\n",argc-optind); for (i=0; i<argc-optind; i++) pout("%s\n",argv[optind+i]); UsageSummary(); EXIT(FAILCMD); } // Read or init drive database if (!no_defaultdb && !read_default_drive_databases()) EXIT(FAILCMD); return type; } // Printing function (controlled by global printing_is_off) // [From GLIBC Manual: Since the prototype doesn't specify types for // optional arguments, in a call to a variadic function the default // argument promotions are performed on the optional argument // values. This means the objects of type char or short int (whether // signed or not) are promoted to either int or unsigned int, as // appropriate.] void pout(const char *fmt, ...){ va_list ap; // initialize variable argument list va_start(ap,fmt); if (printing_is_off) { va_end(ap); return; } // print out vprintf(fmt,ap); va_end(ap); fflush(stdout); return; } // Globals to set failuretest() policy bool failuretest_conservative = false; unsigned char failuretest_permissive = 0; // Compares failure type to policy in effect, and either exits or // simply returns to the calling routine. // Used in ataprint.cpp and scsiprint.cpp. void failuretest(failure_type type, int returnvalue) { // If this is an error in an "optional" SMART command if (type == OPTIONAL_CMD) { if (!failuretest_conservative) return; pout("An optional SMART command failed: exiting. Remove '-T conservative' option to continue.\n"); EXIT(returnvalue); } // If this is an error in a "mandatory" SMART command if (type == MANDATORY_CMD) { if (failuretest_permissive--) return; pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n"); EXIT(returnvalue); } throw std::logic_error("failuretest: Unknown type"); } // Used to warn users about invalid checksums. Called from atacmds.cpp. // Action to be taken may be altered by the user. void checksumwarning(const char * string) { // user has asked us to ignore checksum errors if (checksum_err_mode == CHECKSUM_ERR_IGNORE) return; pout("Warning! %s error: invalid SMART checksum.\n", string); // user has asked us to fail on checksum errors if (checksum_err_mode == CHECKSUM_ERR_EXIT) EXIT(FAILSMART); } // Return info string about device protocol static const char * get_protocol_info(const smart_device * dev) { switch ((int)dev->is_ata() | ((int)dev->is_scsi() << 1)) { case 0x1: return "ATA"; case 0x2: return "SCSI"; case 0x3: return "ATA+SCSI"; default: return "Unknown"; } } // Device scan // smartctl [-d type] --scan[-open] -- [PATTERN] [smartd directive ...] void scan_devices(const char * type, bool with_open, char ** argv) { bool dont_print = !(ata_debugmode || scsi_debugmode); const char * pattern = 0; int ai = 0; if (argv[ai] && argv[ai][0] != '-') pattern = argv[ai++]; smart_device_list devlist; printing_is_off = dont_print; bool ok = smi()->scan_smart_devices(devlist, type , pattern); printing_is_off = false; if (!ok) { pout("# scan_smart_devices: %s\n", smi()->get_errmsg()); return; } for (unsigned i = 0; i < devlist.size(); i++) { smart_device_auto_ptr dev( devlist.release(i) ); if (with_open) { printing_is_off = dont_print; dev.replace ( dev->autodetect_open() ); printing_is_off = false; if (!dev->is_open()) { pout("# %s -d %s # %s, %s device open failed: %s\n", dev->get_dev_name(), dev->get_dev_type(), dev->get_info_name(), get_protocol_info(dev.get()), dev->get_errmsg()); continue; } } pout("%s -d %s", dev->get_dev_name(), dev->get_dev_type()); if (!argv[ai]) pout(" # %s, %s device\n", dev->get_info_name(), get_protocol_info(dev.get())); else { for (int j = ai; argv[j]; j++) pout(" %s", argv[j]); pout("\n"); } if (dev->is_open()) dev->close(); } } // Main program without exception handling static int main_worker(int argc, char **argv) { // Throw if CPU endianess does not match compile time test. check_endianness(); // Initialize interface smart_interface::init(); if (!smi()) return 1; // Parse input arguments ata_print_options ataopts; scsi_print_options scsiopts; bool print_type_only = false; const char * type = parse_options(argc, argv, ataopts, scsiopts, print_type_only); const char * name = argv[argc-1]; smart_device_auto_ptr dev; if (!strcmp(name,"-")) { // Parse "smartctl -r ataioctl,2 ..." output from stdin if (type || print_type_only) { pout("-d option is not allowed in conjunction with device name \"-\".\n"); UsageSummary(); return FAILCMD; } dev = get_parsed_ata_device(smi(), name); } else // get device of appropriate type dev = smi()->get_smart_device(name, type); if (!dev) { pout("%s: %s\n", name, smi()->get_errmsg()); if (type) printvalidarglistmessage('d'); else pout("Please specify device type with the -d option.\n"); UsageSummary(); return FAILCMD; } if (print_type_only) // Report result of first autodetection pout("%s: Device of type '%s' [%s] detected\n", dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get())); // Open device { // Save old info smart_device::device_info oldinfo = dev->get_info(); // Open with autodetect support, may return 'better' device dev.replace( dev->autodetect_open() ); // Report if type has changed if ((type || print_type_only) && oldinfo.dev_type != dev->get_dev_type()) pout("%s: Device open changed type from '%s' to '%s'\n", dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type()); } if (!dev->is_open()) { pout("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg()); return FAILDEV; } // now call appropriate ATA or SCSI routine int retval = 0; if (print_type_only) pout("%s: Device of type '%s' [%s] opened\n", dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get())); else if (dev->is_ata()) retval = ataPrintMain(dev->to_ata(), ataopts); else if (dev->is_scsi()) retval = scsiPrintMain(dev->to_scsi(), scsiopts); else // we should never fall into this branch! pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name()); dev->close(); return retval; } // Main program int main(int argc, char **argv) { int status; try { // Do the real work ... status = main_worker(argc, argv); } catch (int ex) { // EXIT(status) arrives here status = ex; } catch (const std::bad_alloc & /*ex*/) { // Memory allocation failed (also thrown by std::operator new) printf("Smartctl: Out of memory\n"); status = FAILCMD; } catch (const std::exception & ex) { // Other fatal errors printf("Smartctl: Exception: %s\n", ex.what()); status = FAILCMD; } return status; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/scsicmds.h�����������������������������������������������������������0000644�0000000�0000000�00000043435�12114255420�017047� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * scsicmds.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * Additional SCSI work: * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * * N.B. What was formerly known as "SMART" are now called "informational * exceptions" in recent t10.org drafts (i.e. recent SCSI). * */ #ifndef SCSICMDS_H_ #define SCSICMDS_H_ #define SCSICMDS_H_CVSID "$Id: scsicmds.h 3783 2013-03-02 01:51:12Z dpgilbert $\n" #include <stdio.h> #include <stdlib.h> #include <string.h> /* #define SCSI_DEBUG 1 */ /* Comment out to disable command debugging */ /* Following conditional defines just in case OS already has them defined. * If they are defined we hope they are defined correctly (for SCSI). */ #ifndef TEST_UNIT_READY #define TEST_UNIT_READY 0x0 #endif #ifndef LOG_SELECT #define LOG_SELECT 0x4c #endif #ifndef LOG_SENSE #define LOG_SENSE 0x4d #endif #ifndef MODE_SENSE #define MODE_SENSE 0x1a #endif #ifndef MODE_SENSE_10 #define MODE_SENSE_10 0x5a #endif #ifndef MODE_SELECT #define MODE_SELECT 0x15 #endif #ifndef MODE_SELECT_10 #define MODE_SELECT_10 0x55 #endif #ifndef INQUIRY #define INQUIRY 0x12 #endif #ifndef REQUEST_SENSE #define REQUEST_SENSE 0x03 #endif #ifndef RECEIVE_DIAGNOSTIC #define RECEIVE_DIAGNOSTIC 0x1c #endif #ifndef SEND_DIAGNOSTIC #define SEND_DIAGNOSTIC 0x1d #endif #ifndef READ_DEFECT_10 #define READ_DEFECT_10 0x37 #endif #ifndef READ_DEFECT_12 #define READ_DEFECT_12 0xb7 #endif #ifndef START_STOP_UNIT #define START_STOP_UNIT 0x1b #endif #ifndef REPORT_LUNS #define REPORT_LUNS 0xa0 #endif #ifndef READ_CAPACITY_10 #define READ_CAPACITY_10 0x25 #endif #ifndef READ_CAPACITY_16 #define READ_CAPACITY_16 0x9e #endif #ifndef SAI_READ_CAPACITY_16 /* service action for READ_CAPACITY_16 */ #define SAI_READ_CAPACITY_16 0x10 #endif #ifndef SAT_ATA_PASSTHROUGH_12 #define SAT_ATA_PASSTHROUGH_12 0xa1 #endif #ifndef SAT_ATA_PASSTHROUGH_16 #define SAT_ATA_PASSTHROUGH_16 0x85 #endif typedef unsigned char UINT8; typedef signed char INT8; typedef unsigned int UINT32; typedef int INT32; #define DXFER_NONE 0 #define DXFER_FROM_DEVICE 1 #define DXFER_TO_DEVICE 2 struct scsi_cmnd_io { UINT8 * cmnd; /* [in]: ptr to SCSI command block (cdb) */ size_t cmnd_len; /* [in]: number of bytes in SCSI command */ int dxfer_dir; /* [in]: DXFER_NONE, DXFER_FROM_DEVICE, or DXFER_TO_DEVICE */ UINT8 * dxferp; /* [in]: ptr to outgoing or incoming data buffer */ size_t dxfer_len; /* [in]: bytes to be transferred to/from dxferp */ UINT8 * sensep; /* [in]: ptr to sense buffer, filled when CHECK CONDITION status occurs */ size_t max_sense_len; /* [in]: max number of bytes to write to sensep */ unsigned timeout; /* [in]: seconds, 0-> default timeout (60 seconds?) */ size_t resp_sense_len; /* [out]: sense buffer length written */ UINT8 scsi_status; /* [out]: 0->ok, 2->CHECK CONDITION, etc ... */ int resid; /* [out]: Number of bytes requested to be transferred less actual number transferred (0 if not supported) */ }; struct scsi_sense_disect { UINT8 resp_code; UINT8 sense_key; UINT8 asc; UINT8 ascq; int progress; /* -1 -> N/A, 0-65535 -> available */ }; /* Useful data from Informational Exception Control mode page (0x1c) */ #define SCSI_IECMP_RAW_LEN 64 struct scsi_iec_mode_page { UINT8 requestedCurrent; UINT8 gotCurrent; UINT8 requestedChangeable; UINT8 gotChangeable; UINT8 modese_len; /* 0 (don't know), 6 or 10 */ UINT8 raw_curr[SCSI_IECMP_RAW_LEN]; UINT8 raw_chg[SCSI_IECMP_RAW_LEN]; }; /* Carrier for Error counter log pages (e.g. read, write, verify ...) */ struct scsiErrorCounter { UINT8 gotPC[7]; UINT8 gotExtraPC; uint64_t counter[8]; }; /* Carrier for Non-medium error log page */ struct scsiNonMediumError { UINT8 gotPC0; UINT8 gotExtraPC; uint64_t counterPC0; UINT8 gotTFE_H; uint64_t counterTFE_H; /* Track following errors [Hitachi] */ UINT8 gotPE_H; uint64_t counterPE_H; /* Positioning errors [Hitachi] */ }; /* SCSI Peripheral types (of interest) */ #define SCSI_PT_DIRECT_ACCESS 0x0 #define SCSI_PT_SEQUENTIAL_ACCESS 0x1 #define SCSI_PT_CDROM 0x5 #define SCSI_PT_MEDIUM_CHANGER 0x8 #define SCSI_PT_ENCLOSURE 0xd /* ANSI SCSI-3 Log Pages retrieved by LOG SENSE. */ #define SUPPORTED_LPAGES 0x00 #define BUFFER_OVERRUN_LPAGE 0x01 #define WRITE_ERROR_COUNTER_LPAGE 0x02 #define READ_ERROR_COUNTER_LPAGE 0x03 #define READ_REVERSE_ERROR_COUNTER_LPAGE 0x04 #define VERIFY_ERROR_COUNTER_LPAGE 0x05 #define NON_MEDIUM_ERROR_LPAGE 0x06 #define LAST_N_ERROR_LPAGE 0x07 #define FORMAT_STATUS_LPAGE 0x08 #define LB_PROV_LPAGE 0x0c /* SBC-3 */ #define TEMPERATURE_LPAGE 0x0d #define STARTSTOP_CYCLE_COUNTER_LPAGE 0x0e #define APPLICATION_CLIENT_LPAGE 0x0f #define SELFTEST_RESULTS_LPAGE 0x10 #define SS_MEDIA_LPAGE 0x11 /* SBC-3 */ #define BACKGROUND_RESULTS_LPAGE 0x15 /* SBC-3 */ #define NONVOL_CACHE_LPAGE 0x17 /* SBC-3 */ #define PROTOCOL_SPECIFIC_LPAGE 0x18 #define IE_LPAGE 0x2f /* Seagate vendor specific log pages. */ #define SEAGATE_CACHE_LPAGE 0x37 #define SEAGATE_FACTORY_LPAGE 0x3e /* Log page response lengths */ #define LOG_RESP_SELF_TEST_LEN 0x194 /* See the SSC-2 document at www.t10.org . Earler note: From IBM Documentation, see http://www.storage.ibm.com/techsup/hddtech/prodspecs.htm */ #define TAPE_ALERTS_LPAGE 0x2e /* ANSI SCSI-3 Mode Pages */ #define VENDOR_UNIQUE_PAGE 0x00 #define READ_WRITE_ERROR_RECOVERY_PAGE 0x01 #define DISCONNECT_RECONNECT_PAGE 0x02 #define FORMAT_DEVICE_PAGE 0x03 #define RIGID_DISK_DRIVE_GEOMETRY_PAGE 0x04 #define FLEXIBLE_DISK_PAGE 0x05 #define VERIFY_ERROR_RECOVERY_PAGE 0x07 #define CACHING_PAGE 0x08 #define PERIPHERAL_DEVICE_PAGE 0x09 #define XOR_CONTROL_MODE_PAGE 0x10 #define CONTROL_MODE_PAGE 0x0a #define MEDIUM_TYPES_SUPPORTED_PAGE 0x0b #define NOTCH_PAGE 0x0c #define CD_DEVICE_PAGE 0x0d #define CD_AUDIO_CONTROL_PAGE 0x0e #define DATA_COMPRESSION_PAGE 0x0f #define ENCLOSURE_SERVICES_MANAGEMENT_PAGE 0x14 #define PROTOCOL_SPECIFIC_LUN_PAGE 0x18 #define PROTOCOL_SPECIFIC_PORT_PAGE 0x19 #define POWER_CONDITION_PAGE 0x1a #define INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE 0x1c #define FAULT_FAILURE_REPORTING_PAGE 0x1c /* Background control mode subpage is [0x1c,0x1] */ #define BACKGROUND_CONTROL_M_SUBPAGE 0x1 /* SBC-2 */ #define ALL_MODE_PAGES 0x3f /* Mode page control field */ #define MPAGE_CONTROL_CURRENT 0 #define MPAGE_CONTROL_CHANGEABLE 1 #define MPAGE_CONTROL_DEFAULT 2 #define MPAGE_CONTROL_SAVED 3 /* SCSI Vital Product Data (VPD) pages */ #define SCSI_VPD_SUPPORTED_VPD_PAGES 0x0 #define SCSI_VPD_UNIT_SERIAL_NUMBER 0x80 #define SCSI_VPD_DEVICE_IDENTIFICATION 0x83 #define SCSI_VPD_EXTENDED_INQUIRY_DATA 0x86 #define SCSI_VPD_ATA_INFORMATION 0x89 #define SCSI_VPD_POWER_CONDITION 0x8a #define SCSI_VPD_POWER_CONSUMPTION 0x8d #define SCSI_VPD_BLOCK_LIMITS 0xb0 #define SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS 0xb1 #define SCSI_VPD_LOGICAL_BLOCK_PROVISIONING 0xb2 /* defines for useful SCSI Status codes */ #define SCSI_STATUS_CHECK_CONDITION 0x2 /* defines for useful Sense Key codes */ #define SCSI_SK_NO_SENSE 0x0 #define SCSI_SK_RECOVERED_ERR 0x1 #define SCSI_SK_NOT_READY 0x2 #define SCSI_SK_MEDIUM_ERROR 0x3 #define SCSI_SK_HARDWARE_ERROR 0x4 #define SCSI_SK_ILLEGAL_REQUEST 0x5 #define SCSI_SK_UNIT_ATTENTION 0x6 #define SCSI_SK_ABORTED_COMMAND 0xb /* defines for useful Additional Sense Codes (ASCs) */ #define SCSI_ASC_NOT_READY 0x4 /* more info in ASCQ code */ #define SCSI_ASC_NO_MEDIUM 0x3a /* more info in ASCQ code */ #define SCSI_ASC_UNKNOWN_OPCODE 0x20 #define SCSI_ASC_INVALID_FIELD 0x24 #define SCSI_ASC_UNKNOWN_PARAM 0x26 #define SCSI_ASC_WARNING 0xb #define SCSI_ASC_IMPENDING_FAILURE 0x5d #define SCSI_ASCQ_ATA_PASS_THROUGH 0x1d /* Simplified error code (negative values as per errno) */ #define SIMPLE_NO_ERROR 0 #define SIMPLE_ERR_NOT_READY 1 #define SIMPLE_ERR_BAD_OPCODE 2 #define SIMPLE_ERR_BAD_FIELD 3 /* in cbd */ #define SIMPLE_ERR_BAD_PARAM 4 /* in data */ #define SIMPLE_ERR_BAD_RESP 5 /* response fails sanity */ #define SIMPLE_ERR_NO_MEDIUM 6 /* no medium present */ #define SIMPLE_ERR_BECOMING_READY 7 /* device will be ready soon */ #define SIMPLE_ERR_TRY_AGAIN 8 /* some warning, try again */ #define SIMPLE_ERR_MEDIUM_HARDWARE 9 /* medium or hardware error */ #define SIMPLE_ERR_UNKNOWN 10 /* unknown sense value */ #define SIMPLE_ERR_ABORTED_COMMAND 11 /* most likely transport error */ /* defines for functioncode parameter in SENDDIAGNOSTIC function */ #define SCSI_DIAG_NO_SELF_TEST 0x00 #define SCSI_DIAG_DEF_SELF_TEST 0xff #define SCSI_DIAG_BG_SHORT_SELF_TEST 0x01 #define SCSI_DIAG_BG_EXTENDED_SELF_TEST 0x02 #define SCSI_DIAG_FG_SHORT_SELF_TEST 0x05 #define SCSI_DIAG_FG_EXTENDED_SELF_TEST 0x06 #define SCSI_DIAG_ABORT_SELF_TEST 0x04 /* SCSI command timeout values (units are seconds) */ #define SCSI_TIMEOUT_DEFAULT 20 // should be longer than the spin up time // of a disk in standby mode. #define SCSI_TIMEOUT_SELF_TEST (5 * 60 * 60) /* allow max 5 hours for */ /* extended foreground self test */ #define LOGPAGEHDRSIZE 4 class scsi_device; // Set of supported SCSI VPD pages. Constructor fetches Supported VPD pages // VPD page and remembers the response for later queries. class supported_vpd_pages { public: supported_vpd_pages(scsi_device * device); ~supported_vpd_pages() { num_valid = 0; } bool is_supported(int vpd_page_num) const; /* Returns 0 or less for VPD pages not supported or error */ int num_pages() const { return num_valid; } private: int num_valid; /* 0 or less for invalid */ unsigned char pages[256]; }; extern supported_vpd_pages * supported_vpd_pages_p; // Print SCSI debug messages? extern unsigned char scsi_debugmode; void scsi_do_sense_disect(const struct scsi_cmnd_io * in, struct scsi_sense_disect * out); int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo); const char * scsiErrString(int scsiErr); int scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len, int * off, int m_assoc, int m_desig_type, int m_code_set); int scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen, int * transport); /* STANDARD SCSI Commands */ int scsiTestUnitReady(scsi_device * device); int scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen); int scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen); int scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf, int bufLen, int known_resp_len); int scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum, int subpagenum, UINT8 *pBuf, int bufLen); int scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc, UINT8 *pBuf, int bufLen); int scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen); int scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc, UINT8 *pBuf, int bufLen); int scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen); int scsiModePageOffset(const UINT8 * resp, int len, int modese_len); int scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info); int scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, int bufLen); int scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf, int bufLen); int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format, UINT8 *pBuf, int bufLen); int scsiReadDefect12(scsi_device * device, int req_plist, int req_glist, int dl_format, int addrDescIndex, UINT8 *pBuf, int bufLen); int scsiReadCapacity10(scsi_device * device, unsigned int * last_lbp, unsigned int * lb_sizep); int scsiReadCapacity16(scsi_device * device, UINT8 *pBuf, int bufLen); /* SMART specific commands */ int scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage, UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp, UINT8 *triptemp); int scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp, int modese_len); int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp); int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp); int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled, const struct scsi_iec_mode_page *iecp); void scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp); void scsiDecodeNonMediumErrPage(unsigned char * resp, struct scsiNonMediumError *nmep); int scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec, int modese_len); int scsiCountFailedSelfTests(scsi_device * device, int noisy); int scsiSelfTestInProgress(scsi_device * device, int * inProgress); int scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current); int scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len); int scsiFetchTransportProtocol(scsi_device * device, int modese_len); int scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp); int scsiGetSetCache(scsi_device * device, int modese_len, short int * wce, short int * rcd); uint64_t scsiGetSize(scsi_device * device, unsigned int * lb_sizep, int * lb_per_pb_expp); int scsiGetProtPBInfo(scsi_device * device, unsigned char * rc16_12_31p); /* T10 Standard IE Additional Sense Code strings taken from t10.org */ const char* scsiGetIEString(UINT8 asc, UINT8 ascq); int scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp); int scsiSmartIBMOfflineTest(scsi_device * device); int scsiSmartDefaultSelfTest(scsi_device * device); int scsiSmartShortSelfTest(scsi_device * device); int scsiSmartExtendSelfTest(scsi_device * device); int scsiSmartShortCapSelfTest(scsi_device * device); int scsiSmartExtendCapSelfTest(scsi_device * device); int scsiSmartSelfTestAbort(scsi_device * device); const char * scsiTapeAlertsTapeDevice(unsigned short code); const char * scsiTapeAlertsChangerDevice(unsigned short code); const char * scsi_get_opcode_name(UINT8 opcode); void scsi_format_id_string(char * out, const unsigned char * in, int n); void dStrHex(const char* str, int len, int no_ascii); inline void dStrHex(const unsigned char* str, int len, int no_ascii) { dStrHex((const char *)str, len, no_ascii); } /* Attempt to find the first SCSI sense data descriptor that matches the given 'desc_type'. If found return pointer to start of sense data descriptor; otherwise (including fixed format sense data) returns NULL. */ const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len, int desc_type); /* SCSI command transmission interface function declaration. Its * definition is target OS specific (see os_<OS>.c file). * Returns 0 if SCSI command successfully launched and response * received. Even when 0 is returned the caller should check * scsi_cmnd_io::scsi_status for SCSI defined errors and warnings * (e.g. CHECK CONDITION). If the SCSI command could not be issued * (e.g. device not present or not a SCSI device) or some other problem * arises (e.g. timeout) then returns a negative errno value. */ // Moved to C++ interface //int do_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_darwin/�����������������������������������������������������������0000755�0000000�0000000�00000000000�12212065523�017044� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_darwin/English_Localizable.strings��������������������������������0000644�0000000�0000000�00000000721�11227432427�024357� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> <plist version="0.9"> <dict> <key>SMART disk monitoring</key> <string>SMART disk monitoring</string> <key>Starting SMART disk monitoring</key> <string>Starting SMART disk monitoring</string> <key>Stopping SMART disk monitoring</key> <string>Stopping SMART disk monitoring</string> </dict> </plist> �����������������������������������������������smartmontools-6.2+svn3841.orig/os_darwin/SMART.in���������������������������������������������������0000644�0000000�0000000�00000002352�12062413436�020267� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # Darwin init file for smartd # # Home page of code is: http://smartmontools.sourceforge.net # # Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org> # # 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 # Software Foundation; either version 2, or (at your option) any later # version. # # You should have received a copy of the GNU General Public License (for # example COPYING); if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # $Id: SMART.in 3728 2012-12-13 17:57:50Z chrfranke $ ## # SMART monitoring ## . /etc/rc.common StartService () { if [ "${SMARTd:=-YES-}" = "-YES-" ] && ! GetPID smartd > /dev/null; then ConsoleMessage "Starting SMART disk monitoring" /usr/sbin/smartd -p /var/run/smartd.pid fi } StopService () { if pid=$(GetPID smartd); then ConsoleMessage "Stopping SMART disk monitoring" kill -TERM "${pid}" else echo "smartd is not running." fi } RestartService () { if pid=$(GetPID smartd); then kill -HUP "${pid}" else StartService fi } RunService "$1" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_darwin/StartupParameters.plist������������������������������������0000644�0000000�0000000�00000000164�11227432427�023616� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������{ Description = "SMART disk monitoring"; Provides = ("SMART"); Requires = ("System Log"); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_darwin.h����������������������������������������������������������0000644�0000000�0000000�00000002201�12062413436�017213� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_generic.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Geoff Keating <geoffk@geoffk.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef OS_DARWIN_H_ #define OS_DARWIN_H_ #define OS_DARWIN_H_CVSID "$Id: os_darwin.h 3728 2012-12-13 17:57:50Z chrfranke $\n" // Isn't in 10.3.9? #ifndef kIOPropertySMARTCapableKey #define kIOPropertySMARTCapableKey "SMART Capable" #endif #endif /* OS_DARWIN_H_ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_os2/��������������������������������������������������������������0000755�0000000�0000000�00000000000�12212065524�016264� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_os2/hdreg.h�������������������������������������������������������0000644�0000000�0000000�00000033327�11227432427�017543� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef _LINUX_HDREG_H #define _LINUX_HDREG_H /* * This file contains some defines for the AT-hd-controller. * Various sources. */ #define HD_IRQ 14 /* the standard disk interrupt */ /* ide.c has its own port definitions in "ide.h" */ /* Hd controller regs. Ref: IBM AT Bios-listing */ #define HD_DATA 0x1f0 /* _CTL when writing */ #define HD_ERROR 0x1f1 /* see err-bits */ #define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ #define HD_SECTOR 0x1f3 /* starting sector */ #define HD_LCYL 0x1f4 /* starting cylinder */ #define HD_HCYL 0x1f5 /* high byte of starting cyl */ #define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ #define HD_STATUS 0x1f7 /* see status-bits */ #define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */ #define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */ #define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ #define HD_CMD 0x3f6 /* used for resets */ #define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */ /* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */ /* Bits of HD_STATUS */ #define ERR_STAT 0x01 #define INDEX_STAT 0x02 #define ECC_STAT 0x04 /* Corrected error */ #define DRQ_STAT 0x08 #define SEEK_STAT 0x10 #define WRERR_STAT 0x20 #define READY_STAT 0x40 #define BUSY_STAT 0x80 /* Values for HD_COMMAND */ #define WIN_RESTORE 0x10 #define WIN_READ 0x20 #define WIN_WRITE 0x30 #define WIN_WRITE_VERIFY 0x3C #define WIN_VERIFY 0x40 #define WIN_FORMAT 0x50 #define WIN_INIT 0x60 #define WIN_SEEK 0x70 #define WIN_DIAGNOSE 0x90 #define WIN_SPECIFY 0x91 /* set drive geometry translation */ #define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ #define WIN_SETIDLE1 0xE3 #define WIN_SETIDLE2 0x97 #define WIN_STANDBYNOW1 0xE0 #define WIN_STANDBYNOW2 0x94 #define WIN_SLEEPNOW1 0xE6 #define WIN_SLEEPNOW2 0x99 #define WIN_CHECKPOWERMODE1 0xE5 #define WIN_CHECKPOWERMODE2 0x98 #define WIN_DOORLOCK 0xDE /* lock door on removable drives */ #define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ #define WIN_MULTREAD 0xC4 /* read sectors using multiple mode */ #define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ #define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ #define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ #define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ #define WIN_SETFEATURES 0xEF /* set special drive features */ #define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ #define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ #define WIN_QUEUED_SERVICE 0xA2 /* */ #define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ #define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ #define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ #define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ #define WIN_SMART 0xB0 /* self-monitoring and reporting */ /* Additional drive command codes used by ATAPI devices. */ #define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ #define WIN_SRST 0x08 /* ATAPI soft reset command */ #define WIN_PACKETCMD 0xA0 /* Send a packet command. */ #define DISABLE_SEAGATE 0xFB #define EXABYTE_ENABLE_NEST 0xF0 /* WIN_SMART sub-commands */ #define SMART_READ_VALUES 0xd0 #define SMART_READ_THRESHOLDS 0xd1 #define SMART_AUTOSAVE 0xd2 #define SMART_SAVE 0xd3 #define SMART_IMMEDIATE_OFFLINE 0xd4 #define SMART_READ_LOG_SECTOR 0xd5 #define SMART_WRITE_LOG_SECTOR 0xd6 #define SMART_ENABLE 0xd8 #define SMART_DISABLE 0xd9 #define SMART_STATUS 0xda #define SMART_AUTO_OFFLINE 0xdb /* WIN_SETFEATURES sub-commands */ #define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ #define SETFEATURES_XFER 0x03 /* Set transfer mode */ # define XFER_UDMA_7 0x47 /* 0100|0111 */ # define XFER_UDMA_6 0x46 /* 0100|0110 */ # define XFER_UDMA_5 0x45 /* 0100|0101 */ # define XFER_UDMA_4 0x44 /* 0100|0100 */ # define XFER_UDMA_3 0x43 /* 0100|0011 */ # define XFER_UDMA_2 0x42 /* 0100|0010 */ # define XFER_UDMA_1 0x41 /* 0100|0001 */ # define XFER_UDMA_0 0x40 /* 0100|0000 */ # define XFER_MW_DMA_2 0x22 /* 0010|0010 */ # define XFER_MW_DMA_1 0x21 /* 0010|0001 */ # define XFER_MW_DMA_0 0x20 /* 0010|0000 */ # define XFER_SW_DMA_2 0x12 /* 0001|0010 */ # define XFER_SW_DMA_1 0x11 /* 0001|0001 */ # define XFER_SW_DMA_0 0x10 /* 0001|0000 */ # define XFER_PIO_4 0x0C /* 0000|1100 */ # define XFER_PIO_3 0x0B /* 0000|1011 */ # define XFER_PIO_2 0x0A /* 0000|1010 */ # define XFER_PIO_1 0x09 /* 0000|1001 */ # define XFER_PIO_0 0x08 /* 0000|1000 */ # define XFER_PIO_SLOW 0x00 /* 0000|0000 */ #define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */ #define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ #define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ #define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ #define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ #define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ #define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ #define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ #define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */ #define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ #define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ #define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ #define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */ #define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ #define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */ #define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt */ /* WIN_SECURITY sub-commands */ #define SECURITY_SET_PASSWORD 0xBA /* 0xF1 */ #define SECURITY_UNLOCK 0xBB /* 0xF2 */ #define SECURITY_ERASE_PREPARE 0xBC /* 0xF3 */ #define SECURITY_ERASE_UNIT 0xBD /* 0xF4 */ #define SECURITY_FREEZE_LOCK 0xBE /* 0xF5 */ #define SECURITY_DISABLE_PASSWORD 0xBF /* 0xF6 */ /* Bits for HD_ERROR */ #define MARK_ERR 0x01 /* Bad address mark */ #define TRK0_ERR 0x02 /* couldn't find track 0 */ #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* media change request */ #define ID_ERR 0x10 /* ID field not found */ #define ECC_ERR 0x40 /* Uncorrectable ECC error */ #define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ #define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ struct hd_geometry { unsigned char heads; unsigned char sectors; unsigned short cylinders; unsigned long start; }; /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */ #define HDIO_GETGEO 0x0301 /* get device geometry */ #define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ #define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ #define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */ #define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ #define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ #define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ #define HDIO_GET_DMA 0x030b /* get use-dma flag */ #define HDIO_GET_NICE 0x030c /* get nice flags */ #define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ #define HDIO_DRIVE_RESET 0x031c /* execute a device reset */ #define HDIO_TRISTATE_HWIF 0x031d /* execute a channel tristate */ #ifndef __EMX__ #define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */ #endif #define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ #define HDIO_DRIVE_CMD_AEB HDIO_DRIVE_TASK /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ #define HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */ #define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */ #define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */ #define HDIO_SET_32BIT 0x0324 /* change io_32bit flags */ #define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ #define HDIO_SET_DMA 0x0326 /* change use-dma flag */ #define HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ #define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */ #define HDIO_SET_NICE 0x0329 /* set nice flags */ #define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */ /* BIG GEOMETRY */ struct hd_big_geometry { unsigned char heads; unsigned char sectors; unsigned int cylinders; unsigned long start; }; /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */ #define HDIO_GETGEO_BIG 0x0330 /* */ #define HDIO_GETGEO_BIG_RAW 0x0331 /* */ #define __NEW_HD_DRIVE_ID /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */ struct hd_driveid { unsigned short config; /* lots of obsolete bit flags */ unsigned short cyls; /* "physical" cyls */ unsigned short reserved2; /* reserved (word 2) */ unsigned short heads; /* "physical" heads */ unsigned short track_bytes; /* unformatted bytes per track */ unsigned short sector_bytes; /* unformatted bytes per sector */ unsigned short sectors; /* "physical" sectors per track */ unsigned short vendor0; /* vendor unique */ unsigned short vendor1; /* vendor unique */ unsigned short vendor2; /* vendor unique */ unsigned char serial_no[20]; /* 0 = not_specified */ unsigned short buf_type; unsigned short buf_size; /* 512 byte increments; 0 = not_specified */ unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */ unsigned char fw_rev[8]; /* 0 = not_specified */ unsigned char model[40]; /* 0 = not_specified */ unsigned char max_multsect; /* 0=not_implemented */ unsigned char vendor3; /* vendor unique */ unsigned short dword_io; /* 0=not_implemented; 1=implemented */ unsigned char vendor4; /* vendor unique */ unsigned char capability; /* bits 0:DMA 1:LBA 2:IORDYsw 3:IORDYsup*/ unsigned short reserved50; /* reserved (word 50) */ unsigned char vendor5; /* vendor unique */ unsigned char tPIO; /* 0=slow, 1=medium, 2=fast */ unsigned char vendor6; /* vendor unique */ unsigned char tDMA; /* 0=slow, 1=medium, 2=fast */ unsigned short field_valid; /* bits 0:cur_ok 1:eide_ok */ unsigned short cur_cyls; /* logical cylinders */ unsigned short cur_heads; /* logical heads */ unsigned short cur_sectors; /* logical sectors per track */ unsigned short cur_capacity0; /* logical total sectors on drive */ unsigned short cur_capacity1; /* (2 words, misaligned int) */ unsigned char multsect; /* current multiple sector count */ unsigned char multsect_valid; /* when (bit0==1) multsect is ok */ unsigned int lba_capacity; /* total number of sectors */ unsigned short dma_1word; /* single-word dma info */ unsigned short dma_mword; /* multiple-word dma info */ unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ unsigned short eide_pio; /* min cycle time (ns), no IORDY */ unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ unsigned short words69_70[2]; /* reserved words 69-70 */ /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ unsigned short words71_74[4]; /* reserved words 71-74 */ unsigned short queue_depth; /* */ unsigned short words76_79[4]; /* reserved words 76-79 */ unsigned short major_rev_num; /* */ unsigned short minor_rev_num; /* */ unsigned short command_set_1; /* bits 0:Smart 1:Security 2:Removable 3:PM */ unsigned short command_set_2; /* bits 14:Smart Enabled 13:0 zero */ unsigned short cfsse; /* command set-feature supported extensions */ unsigned short cfs_enable_1; /* command set-feature enabled */ unsigned short cfs_enable_2; /* command set-feature enabled */ unsigned short csf_default; /* command set-feature default */ unsigned short dma_ultra; /* */ unsigned short word89; /* reserved (word 89) */ unsigned short word90; /* reserved (word 90) */ unsigned short CurAPMvalues; /* current APM values */ unsigned short word92; /* reserved (word 92) */ unsigned short hw_config; /* hardware config */ unsigned short words94_125[32];/* reserved words 94-125 */ unsigned short last_lun; /* reserved (word 126) */ unsigned short word127; /* reserved (word 127) */ unsigned short dlf; /* device lock function * 15:9 reserved * 8 security level 1:max 0:high * 7:6 reserved * 5 enhanced erase * 4 expire * 3 frozen * 2 locked * 1 en/disabled * 0 capability */ unsigned short csfo; /* current set features options * 15:4 reserved * 3 auto reassign * 2 reverting * 1 read-look-ahead * 0 write cache */ unsigned short words130_155[26];/* reserved vendor words 130-155 */ unsigned short word156; unsigned short words157_159[3];/* reserved vendor words 157-159 */ unsigned short words160_255[95];/* reserved words 160-255 */ }; /* * IDE "nice" flags. These are used on a per drive basis to determine * when to be nice and give more bandwidth to the other devices which * share the same IDE bus. */ #define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */ #define IDE_NICE_ATAPI_OVERLAP (1) /* not supported yet */ #define IDE_NICE_0 (2) /* when sure that it won't affect us */ #define IDE_NICE_1 (3) /* when probably won't affect us much */ #define IDE_NICE_2 (4) /* when we know it's on our expense */ #ifdef __KERNEL__ /* * These routines are used for kernel command line parameters from main.c: */ #include <linux/config.h> #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) int ide_register(int io_port, int ctl_port, int irq); void ide_unregister(unsigned int); #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */ #endif /* __KERNEL__ */ #endif /* _LINUX_HDREG_H */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_os2/configure.os2�������������������������������������������������0000644�0000000�0000000�00000000460�11227432427�020677� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh CFLAGS="-s -Zomf -O3 -march=pentium -mcpu=pentium3" \ CXXFLAGS="-s -Zomf -O3 -march=pentium -mcpu=pentium3" \ LDFLAGS="-s -Zmap -Zhigh-mem -Zomf -Zexe -Zstack 0x100" \ LIBS=" -lsyslog -lsocket" \ LN_CP_F="cp.exe" \ RANLIB="echo" \ AR="emxomfar" \ ./configure --prefix=/usr/local/smartmontools ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_darwin.cpp��������������������������������������������������������0000644�0000000�0000000�00000032520�12125370552�017556� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_darwin.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Geoffrey Keating <geoffk@geoffk.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdbool.h> #include <errno.h> #include <unistd.h> #include <mach/mach.h> #include <mach/mach_error.h> #include <mach/mach_init.h> #include <IOKit/IOCFPlugIn.h> #include <IOKit/IOKitLib.h> #include <IOKit/IOReturn.h> #include <IOKit/IOBSD.h> #include <IOKit/storage/IOBlockStorageDevice.h> #include <IOKit/storage/IOStorageDeviceCharacteristics.h> #include <IOKit/storage/IOMedia.h> #include <IOKit/storage/ata/IOATAStorageDefines.h> #include <IOKit/storage/ata/ATASMARTLib.h> #include <CoreFoundation/CoreFoundation.h> // No, I don't know why there isn't a header for this. #define kIOATABlockStorageDeviceClass "IOATABlockStorageDevice" #include "config.h" #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "utility.h" #include "os_darwin.h" // Needed by '-V' option (CVS versioning) of smartd/smartctl const char *os_XXXX_c_cvsid="$Id: os_darwin.cpp 3805 2013-03-29 19:54:18Z chrfranke $" \ ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_DARWIN_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; // Print examples for smartctl. void print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); printf( " smartctl -a disk0 (Prints all SMART information)\n\n" " smartctl -t long /dev/disk0 (Executes extended disk self-test)\n\n" #ifdef HAVE_GETOPT_LONG " smartctl --smart=on --saveauto=on /dev/rdisk0 (Enables SMART on first disk)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/disk0\n" " (Prints Self-Test & Attribute errors)\n\n" #else " smartctl -s on -S on /dev/rdisk0 (Enables SMART on first disk)\n\n" " smartctl -A -l selftest -q errorsonly /dev/disk0\n" " (Prints Self-Test & Attribute errors)\n\n" #endif " smartctl -a IOService:/MacRISC2PE/pci@f4000000/AppleMacRiscPCI/ata-6@D/AppleKauaiATA/ATADeviceNub@0/IOATABlockStorageDriver/IOATABlockStorageDevice\n" " (You can use IOService: ...)\n\n" " smartctl -c IODeviceTree:/pci@f4000000/ata-6@D/@0:0\n" " (... Or IODeviceTree:)\n" ); return; } // tries to guess device type given the name (a path). See utility.h // for return values. int guess_device_type (const char * /* dev_name */) { // Only ATA is supported right now, so that's what it'd better be. return CONTROLLER_ATA; } // Determine whether 'dev' is a SMART-capable device. static bool is_smart_capable (io_object_t dev) { CFTypeRef smartCapableKey; CFDictionaryRef diskChars; // If the device has kIOPropertySMARTCapableKey, then it's capable, // no matter what it looks like. smartCapableKey = IORegistryEntryCreateCFProperty (dev, CFSTR (kIOPropertySMARTCapableKey), kCFAllocatorDefault, 0); if (smartCapableKey) { CFRelease (smartCapableKey); return true; } // If it's an kIOATABlockStorageDeviceClass then we're successful // only if its ATA features indicate it supports SMART. if (IOObjectConformsTo (dev, kIOATABlockStorageDeviceClass) && (diskChars = (CFDictionaryRef)IORegistryEntryCreateCFProperty (dev, CFSTR (kIOPropertyDeviceCharacteristicsKey), kCFAllocatorDefault, kNilOptions)) != NULL) { CFNumberRef diskFeatures = NULL; UInt32 ataFeatures = 0; if (CFDictionaryGetValueIfPresent (diskChars, CFSTR ("ATA Features"), (const void **)&diskFeatures)) CFNumberGetValue (diskFeatures, kCFNumberLongType, &ataFeatures); CFRelease (diskChars); if (diskFeatures) CFRelease (diskFeatures); return (ataFeatures & kIOATAFeatureSMART) != 0; } return false; } // makes a list of ATA or SCSI devices for the DEVICESCAN directive of // smartd. Returns number N of devices, or -1 if out of // memory. Allocates N+1 arrays: one of N pointers (devlist); the // other N arrays each contain null-terminated character strings. In // the case N==0, no arrays are allocated because the array of 0 // pointers has zero length, equivalent to calling malloc(0). int make_device_names (char*** devlist, const char* name) { IOReturn err; io_iterator_t i; io_object_t device = MACH_PORT_NULL; int result; int index; // We treat all devices as ATA so long as they support SMARTLib. if (strcmp (name, "ATA") != 0) return 0; err = IOServiceGetMatchingServices (kIOMasterPortDefault, IOServiceMatching (kIOBlockStorageDeviceClass), &i); if (err != kIOReturnSuccess) return -1; // Count the devices. result = 0; while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) { if (is_smart_capable (device)) result++; IOObjectRelease (device); } // Create an array of service names. IOIteratorReset (i); *devlist = (char**)Calloc (result, sizeof (char *)); if (! *devlist) goto error; index = 0; while ((device = IOIteratorNext (i)) != MACH_PORT_NULL) { if (is_smart_capable (device)) { io_string_t devName; IORegistryEntryGetPath(device, kIOServicePlane, devName); (*devlist)[index] = CustomStrDup (devName, true, __LINE__, __FILE__); if (! (*devlist)[index]) goto error; index++; } IOObjectRelease (device); } IOObjectRelease (i); return result; error: if (device != MACH_PORT_NULL) IOObjectRelease (device); IOObjectRelease (i); if (*devlist) { for (index = 0; index < result; index++) if ((*devlist)[index]) FreeNonZero ((*devlist)[index], 0, __LINE__, __FILE__); FreeNonZero (*devlist, result * sizeof (char *), __LINE__, __FILE__); } return -1; } // Information that we keep about each device. static struct { io_object_t ioob; IOCFPlugInInterface **plugin; IOATASMARTInterface **smartIf; } devices[20]; // Like open(). Return non-negative integer handle, only used by the // functions below. type=="ATA" or "SCSI". The return value is // an index into the devices[] array. If the device can't be opened, // sets errno and returns -1. // Acceptable device names are: // /dev/disk* // /dev/rdisk* // disk* // IOService:* // IODeviceTree:* int deviceopen(const char *pathname, char *type){ size_t devnum; const char *devname; io_object_t disk; if (strcmp (type, "ATA") != 0) { errno = EINVAL; return -1; } // Find a free device number. for (devnum = 0; devnum < sizeof (devices) / sizeof (devices[0]); devnum++) if (! devices[devnum].ioob) break; if (devnum == sizeof (devices) / sizeof (devices[0])) { errno = EMFILE; return -1; } devname = NULL; if (strncmp (pathname, "/dev/rdisk", 10) == 0) devname = pathname + 6; else if (strncmp (pathname, "/dev/disk", 9) == 0) devname = pathname + 5; else if (strncmp (pathname, "disk", 4) == 0) // allow user to just say 'disk0' devname = pathname; // Find the device. if (devname) { CFMutableDictionaryRef matcher; matcher = IOBSDNameMatching (kIOMasterPortDefault, 0, devname); disk = IOServiceGetMatchingService (kIOMasterPortDefault, matcher); } else { disk = IORegistryEntryFromPath (kIOMasterPortDefault, pathname); } if (! disk) { errno = ENOENT; return -1; } // Find a SMART-capable driver which is a parent of this device. while (! is_smart_capable (disk)) { IOReturn err; io_object_t prevdisk = disk; // Find this device's parent and try again. err = IORegistryEntryGetParentEntry (disk, kIOServicePlane, &disk); if (err != kIOReturnSuccess || ! disk) { errno = ENODEV; IOObjectRelease (prevdisk); return -1; } } devices[devnum].ioob = disk; { SInt32 dummy; devices[devnum].plugin = NULL; devices[devnum].smartIf = NULL; // Create an interface to the ATA SMART library. if (IOCreatePlugInInterfaceForService (disk, kIOATASMARTUserClientTypeID, kIOCFPlugInInterfaceID, &devices[devnum].plugin, &dummy) == kIOReturnSuccess) (*devices[devnum].plugin)->QueryInterface (devices[devnum].plugin, CFUUIDGetUUIDBytes ( kIOATASMARTInterfaceID), (void **)&devices[devnum].smartIf); } return devnum; } // Like close(). Acts only on integer handles returned by // deviceopen() above. int deviceclose(int fd){ if (devices[fd].smartIf) (*devices[fd].smartIf)->Release (devices[fd].smartIf); if (devices[fd].plugin) IODestroyPlugInInterface (devices[fd].plugin); IOObjectRelease (devices[fd].ioob); devices[fd].ioob = MACH_PORT_NULL; return 0; } // Interface to ATA devices. See os_linux.cpp for the cannonical example. // DETAILED DESCRIPTION OF ARGUMENTS // device: is the integer handle provided by deviceopen() // command: defines the different operations, see atacmds.h // select: additional input data IF NEEDED (which log, which type of // self-test). // data: location to write output data, IF NEEDED (1 or 512 bytes). // Note: not all commands use all arguments. // RETURN VALUES (for all commands BUT command==STATUS_CHECK) // -1 if the command failed // 0 if the command succeeded, // RETURN VALUES if command==STATUS_CHECK // -1 if the command failed OR the disk SMART status can't be determined // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" // Things that aren't available in the Darwin interfaces: // - Tests other than short and extended (in particular, can't run // an immediate offline test) // - Captive-mode tests, aborting tests // - ability to switch automatic offline testing on or off // Note that some versions of Darwin, at least 7H63 and earlier, // have a buggy library that treats the boolean value in // SMARTEnableDisableOperations, SMARTEnableDisableAutosave, and // SMARTExecuteOffLineImmediate as always being true. int ata_command_interface(int fd, smart_command_set command, int select, char *data) { IOATASMARTInterface **ifp = devices[fd].smartIf; IOATASMARTInterface *smartIf; IOReturn err; int timeoutCount = 5; if (! ifp) return -1; smartIf = *ifp; do { switch (command) { case STATUS: return 0; case STATUS_CHECK: { Boolean is_failing; err = smartIf->SMARTReturnStatus (ifp, &is_failing); if (err == kIOReturnSuccess && is_failing) return 1; break; } case ENABLE: case DISABLE: err = smartIf->SMARTEnableDisableOperations (ifp, command == ENABLE); break; case AUTOSAVE: err = smartIf->SMARTEnableDisableAutosave (ifp, select != 0); break; case IMMEDIATE_OFFLINE: if (select != SHORT_SELF_TEST && select != EXTEND_SELF_TEST) { errno = EINVAL; return -1; } err = smartIf->SMARTExecuteOffLineImmediate (ifp, select == EXTEND_SELF_TEST); break; case READ_VALUES: err = smartIf->SMARTReadData (ifp, (ATASMARTData *)data); break; case READ_THRESHOLDS: err = smartIf->SMARTReadDataThresholds (ifp, (ATASMARTDataThresholds *)data); break; case READ_LOG: err = smartIf->SMARTReadLogAtAddress (ifp, select, data, 512); break; case WRITE_LOG: err = smartIf->SMARTWriteLogAtAddress (ifp, select, data, 512); break; case IDENTIFY: { UInt32 dummy; err = smartIf->GetATAIdentifyData (ifp, data, 512, &dummy); if (err != kIOReturnSuccess && err != kIOReturnTimeout && err != kIOReturnNotResponding) printf ("identify failed: %#x\n", (unsigned) err); if (err == kIOReturnSuccess && isbigendian()) { int i; /* The system has already byte-swapped, undo it. */ for (i = 0; i < 256; i+=2) swap2 (data + i); } } break; case CHECK_POWER_MODE: // The information is right there in the device registry, but how // to get to it portably? default: errno = ENOTSUP; return -1; } /* This bit is a bit strange. Apparently, when the drive is spun down, the intended behaviour of these calls is that they fail, return kIOReturnTimeout and then power the drive up. So if you get a timeout, you have to try again to get the actual command run, but the drive is already powering up so you can't use this for CHECK_POWER_MODE. */ if (err == kIOReturnTimeout || err == kIOReturnNotResponding) sleep (1); } while ((err == kIOReturnTimeout || err == kIOReturnNotResponding) && timeoutCount-- > 0); if (err == kIOReturnExclusiveAccess) errno = EBUSY; return err == kIOReturnSuccess ? 0 : -1; } // Interface to SCSI devices. See os_linux.c int do_scsi_cmnd_io(int /* fd */, struct scsi_cmnd_io * /* iop */, int /* report */) { return -ENOSYS; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/utility.cpp����������������������������������������������������������0000644�0000000�0000000�00000055026�12173006433�017277� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * utility.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-12 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ // THIS FILE IS INTENDED FOR UTILITY ROUTINES THAT ARE APPLICABLE TO // BOTH SCSI AND ATA DEVICES, AND THAT MAY BE USED IN SMARTD, // SMARTCTL, OR BOTH. #include "config.h" #include <stdio.h> #include <string.h> #include <time.h> #include <errno.h> #include <stdlib.h> #include <ctype.h> #include <stdarg.h> #include <sys/stat.h> #ifdef HAVE_LOCALE_H #include <locale.h> #endif #ifdef _WIN32 #include <mbstring.h> // _mbsinc() #endif #include <stdexcept> #include "svnversion.h" #include "int64.h" #include "utility.h" #include "atacmds.h" #include "dev_interface.h" const char * utility_cpp_cvsid = "$Id: utility.cpp 3838 2013-07-21 16:32:27Z chrfranke $" UTILITY_H_CVSID INT64_H_CVSID; const char * packet_types[] = { "Direct-access (disk)", "Sequential-access (tape)", "Printer", "Processor", "Write-once (optical disk)", "CD/DVD", "Scanner", "Optical memory (optical disk)", "Medium changer", "Communications", "Graphic arts pre-press (10)", "Graphic arts pre-press (11)", "Array controller", "Enclosure services", "Reduced block command (simplified disk)", "Optical card reader/writer" }; // BUILD_INFO can be provided by package maintainers #ifndef BUILD_INFO #define BUILD_INFO "(local build)" #endif // Make version information string std::string format_version_info(const char * prog_name, bool full /*= false*/) { std::string info = strprintf( "%s "PACKAGE_VERSION" " #ifdef SMARTMONTOOLS_SVN_REV SMARTMONTOOLS_SVN_DATE" r"SMARTMONTOOLS_SVN_REV #else "(build date "__DATE__")" // checkout without expansion of Id keywords #endif " [%s] "BUILD_INFO"\n" "Copyright (C) 2002-13, Bruce Allen, Christian Franke, www.smartmontools.org\n", prog_name, smi()->get_os_version_str().c_str() ); if (!full) return info; info += strprintf( "\n" "%s comes with ABSOLUTELY NO WARRANTY. This is free\n" "software, and you are welcome to redistribute it under\n" "the terms of the GNU General Public License; either\n" "version 2, or (at your option) any later version.\n" "See http://www.gnu.org for further details.\n" "\n", prog_name ); info += strprintf( "smartmontools release "PACKAGE_VERSION " dated "SMARTMONTOOLS_RELEASE_DATE" at "SMARTMONTOOLS_RELEASE_TIME"\n" #ifdef SMARTMONTOOLS_SVN_REV "smartmontools SVN rev "SMARTMONTOOLS_SVN_REV " dated "SMARTMONTOOLS_SVN_DATE" at "SMARTMONTOOLS_SVN_TIME"\n" #else "smartmontools SVN rev is unknown\n" #endif "smartmontools build host: "SMARTMONTOOLS_BUILD_HOST"\n" "smartmontools build configured: "SMARTMONTOOLS_CONFIGURE_DATE "\n" "%s compile dated "__DATE__" at "__TIME__"\n" "smartmontools configure arguments: ", prog_name ); info += (sizeof(SMARTMONTOOLS_CONFIGURE_ARGS) > 1 ? SMARTMONTOOLS_CONFIGURE_ARGS : "[no arguments given]"); info += '\n'; return info; } // Solaris only: Get site-default timezone. This is called from // UpdateTimezone() when TZ environment variable is unset at startup. #if defined (__SVR4) && defined (__sun) static const char *TIMEZONE_FILE = "/etc/TIMEZONE"; static char *ReadSiteDefaultTimezone(){ FILE *fp; char buf[512], *tz; int n; tz = NULL; fp = fopen(TIMEZONE_FILE, "r"); if(fp == NULL) return NULL; while(fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, "TZ=", 3)) // searches last "TZ=" line continue; n = strlen(buf) - 1; if (buf[n] == '\n') buf[n] = 0; if (tz) free(tz); tz = strdup(buf); } fclose(fp); return tz; } #endif // Make sure that this executable is aware if the user has changed the // time-zone since the last time we polled devices. The cannonical // example is a user who starts smartd on a laptop, then flies across // time-zones with a laptop, and then changes the timezone, WITHOUT // restarting smartd. This is a work-around for a bug in // GLIBC. Yuk. See bug number 48184 at http://bugs.debian.org and // thanks to Ian Redfern for posting a workaround. // Please refer to the smartd manual page, in the section labeled LOG // TIMESTAMP TIMEZONE. void FixGlibcTimeZoneBug(){ #if __GLIBC__ if (!getenv("TZ")) { putenv((char *)"TZ=GMT"); // POSIX prototype is 'int putenv(char *)' tzset(); putenv((char *)"TZ"); tzset(); } #elif _WIN32 if (!getenv("TZ")) { putenv("TZ=GMT"); tzset(); putenv("TZ="); // empty value removes TZ, putenv("TZ") does nothing tzset(); } #elif defined (__SVR4) && defined (__sun) // In Solaris, putenv("TZ=") sets null string and invalid timezone. // putenv("TZ") does nothing. With invalid TZ, tzset() do as if // TZ=GMT. With TZ unset, /etc/TIMEZONE will be read only _once_ at // first tzset() call. Conclusion: Unlike glibc, dynamic // configuration of timezone can be done only by changing actual // value of TZ environment value. enum tzstate { NOT_CALLED_YET, USER_TIMEZONE, TRACK_TIMEZONE }; static enum tzstate state = NOT_CALLED_YET; static struct stat prev_stat; static char *prev_tz; struct stat curr_stat; char *curr_tz; if(state == NOT_CALLED_YET) { if(getenv("TZ")) { state = USER_TIMEZONE; // use supplied timezone } else { state = TRACK_TIMEZONE; if(stat(TIMEZONE_FILE, &prev_stat)) { state = USER_TIMEZONE; // no TZ, no timezone file; use GMT forever } else { prev_tz = ReadSiteDefaultTimezone(); // track timezone file change if(prev_tz) putenv(prev_tz); } } tzset(); } else if(state == TRACK_TIMEZONE) { if(stat(TIMEZONE_FILE, &curr_stat) == 0 && (curr_stat.st_ctime != prev_stat.st_ctime || curr_stat.st_mtime != prev_stat.st_mtime)) { // timezone file changed curr_tz = ReadSiteDefaultTimezone(); if(curr_tz) { putenv(curr_tz); if(prev_tz) free(prev_tz); prev_tz = curr_tz; prev_stat = curr_stat; } } tzset(); } #endif // OTHER OS/LIBRARY FIXES SHOULD GO HERE, IF DESIRED. PLEASE TRY TO // KEEP THEM INDEPENDENT. return; } #ifdef _WIN32 // Fix strings in tzname[] to avoid long names with non-ascii characters. // If TZ is not set, tzset() in the MSVC runtime sets tzname[] to the // national language timezone names returned by GetTimezoneInformation(). static char * fixtzname(char * dest, int destsize, const char * src) { int i = 0, j = 0; while (src[i] && j < destsize-1) { int i2 = (const char *)_mbsinc((const unsigned char *)src+i) - src; if (i2 > i+1) i = i2; // Ignore multibyte chars else { if ('A' <= src[i] && src[i] <= 'Z') dest[j++] = src[i]; // "Pacific Standard Time" => "PST" i++; } } if (j < 2) j = 0; dest[j] = 0; return dest; } #endif // _WIN32 // This value follows the peripheral device type value as defined in // SCSI Primary Commands, ANSI INCITS 301:1997. It is also used in // the ATA standard for packet devices to define the device type. const char *packetdevicetype(int type){ if (type<0x10) return packet_types[type]; if (type<0x20) return "Reserved"; return "Unknown"; } // Runtime check of byte ordering, throws if different from isbigendian(). void check_endianness() { union { // Force compile error if int type is not 32bit. unsigned char c[sizeof(unsigned) == 4 ? 4 : -1]; unsigned i; } x = {{1,2,3,4}}; int big = -1; switch (x.i) { case 0x01020304: big = 1; break; case 0x04030201: big = 0; break; } if (big != (isbigendian() ? 1 : 0)) throw std::logic_error("CPU endianness does not match compile time test"); } // Utility function prints date and time and timezone into a character // buffer of length>=64. All the fuss is needed to get the right // timezone info (sigh). void dateandtimezoneepoch(char *buffer, time_t tval){ struct tm *tmval; const char *timezonename; char datebuffer[DATEANDEPOCHLEN]; int lenm1; #ifdef _WIN32 char tzfixbuf[6+1]; #endif FixGlibcTimeZoneBug(); // Get the time structure. We need this to determine if we are in // daylight savings time or not. tmval=localtime(&tval); // Convert to an ASCII string, put in datebuffer // same as: asctime_r(tmval, datebuffer); strncpy(datebuffer, asctime(tmval), DATEANDEPOCHLEN); datebuffer[DATEANDEPOCHLEN-1]='\0'; // Remove newline lenm1=strlen(datebuffer)-1; datebuffer[lenm1>=0?lenm1:0]='\0'; // correct timezone name if (tmval->tm_isdst==0) // standard time zone timezonename=tzname[0]; else if (tmval->tm_isdst>0) // daylight savings in effect timezonename=tzname[1]; else // unable to determine if daylight savings in effect timezonename=""; #ifdef _WIN32 // Fix long non-ascii timezone names if (!getenv("TZ")) timezonename=fixtzname(tzfixbuf, sizeof(tzfixbuf), timezonename); #endif // Finally put the information into the buffer as needed. snprintf(buffer, DATEANDEPOCHLEN, "%s %s", datebuffer, timezonename); return; } // Date and timezone gets printed into string pointed to by buffer void dateandtimezone(char *buffer){ // Get the epoch (time in seconds since Jan 1 1970) time_t tval=time(NULL); dateandtimezoneepoch(buffer, tval); return; } // A replacement for perror() that sends output to our choice of // printing. If errno not set then just print message. void syserror(const char *message){ if (errno) { // Get the correct system error message: const char *errormessage=strerror(errno); // Check that caller has handed a sensible string, and provide // appropriate output. See perrror(3) man page to understand better. if (message && *message) pout("%s: %s\n",message, errormessage); else pout("%s\n",errormessage); } else if (message && *message) pout("%s\n",message); return; } // Check regular expression for non-portable features. // // POSIX extended regular expressions interpret unmatched ')' ordinary: // "The close-parenthesis shall be considered special in this context // only if matched with a preceding open-parenthesis." // // GNU libc and BSD libc support unmatched ')', Cygwin reports an error. // // POSIX extended regular expressions do not define empty subexpressions: // "A vertical-line appearing first or last in an ERE, or immediately following // a vertical-line or a left-parenthesis, or immediately preceding a // right-parenthesis, produces undefined results." // // GNU libc and Cygwin support empty subexpressions, BSD libc reports an error. // static const char * check_regex(const char * pattern) { int level = 0; char c; for (int i = 0; (c = pattern[i]); i++) { // Skip "\x" if (c == '\\') { if (!pattern[++i]) break; continue; } // Skip "[...]" if (c == '[') { if (pattern[++i] == '^') i++; if (!pattern[i++]) break; while ((c = pattern[i]) && c != ']') i++; if (!c) break; continue; } // Check "(...)" nesting if (c == '(') level++; else if (c == ')' && --level < 0) return "Unmatched ')'"; // Check for leading/trailing '|' or "||", "|)", "|$", "(|", "^|" char c1; if ( (c == '|' && ( i == 0 || !(c1 = pattern[i+1]) || c1 == '|' || c1 == ')' || c1 == '$')) || ((c == '(' || c == '^') && pattern[i+1] == '|') ) return "Empty '|' subexpression"; } return (const char *)0; } // Wrapper class for regex(3) regular_expression::regular_expression() : m_flags(0) { memset(&m_regex_buf, 0, sizeof(m_regex_buf)); } regular_expression::regular_expression(const char * pattern, int flags, bool throw_on_error /*= true*/) { memset(&m_regex_buf, 0, sizeof(m_regex_buf)); if (!compile(pattern, flags) && throw_on_error) throw std::runtime_error(strprintf( "error in regular expression \"%s\": %s", m_pattern.c_str(), m_errmsg.c_str())); } regular_expression::~regular_expression() { free_buf(); } regular_expression::regular_expression(const regular_expression & x) { memset(&m_regex_buf, 0, sizeof(m_regex_buf)); copy(x); } regular_expression & regular_expression::operator=(const regular_expression & x) { free_buf(); copy(x); return *this; } void regular_expression::free_buf() { if (nonempty(&m_regex_buf, sizeof(m_regex_buf))) { regfree(&m_regex_buf); memset(&m_regex_buf, 0, sizeof(m_regex_buf)); } } void regular_expression::copy(const regular_expression & x) { m_pattern = x.m_pattern; m_flags = x.m_flags; m_errmsg = x.m_errmsg; if (!m_pattern.empty() && m_errmsg.empty()) { // There is no POSIX compiled-regex-copy command. if (!compile()) throw std::runtime_error(strprintf( "Unable to recompile regular expression \"%s\": %s", m_pattern.c_str(), m_errmsg.c_str())); } } bool regular_expression::compile(const char * pattern, int flags) { free_buf(); m_pattern = pattern; m_flags = flags; return compile(); } bool regular_expression::compile() { int errcode = regcomp(&m_regex_buf, m_pattern.c_str(), m_flags); if (errcode) { char errmsg[512]; regerror(errcode, &m_regex_buf, errmsg, sizeof(errmsg)); m_errmsg = errmsg; free_buf(); return false; } const char * errmsg = check_regex(m_pattern.c_str()); if (errmsg) { m_errmsg = errmsg; free_buf(); return false; } m_errmsg.clear(); return true; } // Splits an argument to the -r option into a name part and an (optional) // positive integer part. s is a pointer to a string containing the // argument. After the call, s will point to the name part and *i the // integer part if there is one or 1 otherwise. Note that the string s may // be changed by this function. Returns zero if successful and non-zero // otherwise. int split_report_arg(char *s, int *i) { if ((s = strchr(s, ','))) { // Looks like there's a name part and an integer part. char *tailptr; *s++ = '\0'; if (*s == '0' || !isdigit((int)*s)) // The integer part must be positive return 1; errno = 0; *i = (int) strtol(s, &tailptr, 10); if (errno || *tailptr != '\0') return 1; } else { // There's no integer part. *i = 1; } return 0; } #ifndef HAVE_STRTOULL // Replacement for missing strtoull() (Linux with libc < 6, MSVC) // Functionality reduced to requirements of smartd and split_selective_arg(). uint64_t strtoull(const char * p, char * * endp, int base) { uint64_t result, maxres; int i = 0; char c = p[i++]; if (!base) { if (c == '0') { if (p[i] == 'x' || p[i] == 'X') { base = 16; i++; } else base = 8; c = p[i++]; } else base = 10; } result = 0; maxres = ~(uint64_t)0 / (unsigned)base; for (;;) { unsigned digit; if ('0' <= c && c <= '9') digit = c - '0'; else if ('A' <= c && c <= 'Z') digit = c - 'A' + 10; else if ('a' <= c && c <= 'z') digit = c - 'a' + 10; else break; if (digit >= (unsigned)base) break; if (!( result < maxres || (result == maxres && digit <= ~(uint64_t)0 % (unsigned)base))) { result = ~(uint64_t)0; errno = ERANGE; // return on overflow break; } result = result * (unsigned)base + digit; c = p[i++]; } if (endp) *endp = (char *)p + i - 1; return result; } #endif // HAVE_STRTOLL // Splits an argument to the -t option that is assumed to be of the form // "selective,%lld-%lld" (prefixes of "0" (for octal) and "0x"/"0X" (for hex) // are allowed). The first long long int is assigned to *start and the second // to *stop. Returns zero if successful and non-zero otherwise. int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode) { char *tailptr; if (!(s = strchr(s, ','))) return 1; bool add = false; if (!isdigit((int)(*++s))) { *start = *stop = 0; if (!strncmp(s, "redo", 4)) *mode = SEL_REDO; else if (!strncmp(s, "next", 4)) *mode = SEL_NEXT; else if (!strncmp(s, "cont", 4)) *mode = SEL_CONT; else return 1; s += 4; if (!*s) return 0; if (*s != '+') return 1; } else { *mode = SEL_RANGE; errno = 0; // Last argument to strtoull (the base) is 0 meaning that decimal is assumed // unless prefixes of "0" (for octal) or "0x"/"0X" (for hex) are used. *start = strtoull(s, &tailptr, 0); s = tailptr; add = (*s == '+'); if (!(!errno && (add || *s == '-'))) return 1; if (!strcmp(s, "-max")) { *stop = ~(uint64_t)0; // replaced by max LBA later return 0; } } errno = 0; *stop = strtoull(s+1, &tailptr, 0); if (errno || *tailptr != '\0') return 1; if (add) { if (*stop > 0) (*stop)--; *stop += *start; // -t select,N+M => -t select,N,(N+M-1) } return 0; } #ifdef OLD_INTERFACE int64_t bytes = 0; // Helps debugging. If the second argument is non-negative, then // decrement bytes by that amount. Else decrement bytes by (one plus) // length of null terminated string. void *FreeNonZero1(void *address, int size, int line, const char* file){ if (address) { if (size<0) bytes-=1+strlen((char*)address); else bytes-=size; return CheckFree1(address, line, file); } return NULL; } // To help with memory checking. Use when it is known that address is // NOT null. void *CheckFree1(void *address, int /*whatline*/, const char* /*file*/){ if (address){ free(address); return NULL; } throw std::runtime_error("Internal error in CheckFree()"); } // A custom version of calloc() that tracks memory use void *Calloc(size_t nmemb, size_t size) { void *ptr=calloc(nmemb, size); if (ptr) bytes+=nmemb*size; return ptr; } // A custom version of strdup() that keeps track of how much memory is // being allocated. If mustexist is set, it also throws an error if we // try to duplicate a NULL string. char *CustomStrDup(const char *ptr, int mustexist, int /*whatline*/, const char* /*file*/){ char *tmp; // report error if ptr is NULL and mustexist is set if (ptr==NULL){ if (mustexist) throw std::runtime_error("Internal error in CustomStrDup()"); else return NULL; } // make a copy of the string... tmp=strdup(ptr); if (!tmp) throw std::bad_alloc(); // and track memory usage bytes+=1+strlen(ptr); return tmp; } #endif // OLD_INTERFACE // Returns true if region of memory contains non-zero entries bool nonempty(const void * data, int size) { for (int i = 0; i < size; i++) if (((const unsigned char *)data)[i]) return true; return false; } // Format integer with thousands separator const char * format_with_thousands_sep(char * str, int strsize, uint64_t val, const char * thousands_sep /* = 0 */) { if (!thousands_sep) { thousands_sep = ","; #ifdef HAVE_LOCALE_H setlocale(LC_ALL, ""); const struct lconv * currentlocale = localeconv(); if (*(currentlocale->thousands_sep)) thousands_sep = currentlocale->thousands_sep; #endif } char num[64]; snprintf(num, sizeof(num), "%"PRIu64, val); int numlen = strlen(num); int i = 0, j = 0; do str[j++] = num[i++]; while (i < numlen && (numlen - i) % 3 != 0 && j < strsize-1); str[j] = 0; while (i < numlen && j < strsize-1) { j += snprintf(str+j, strsize-j, "%s%.3s", thousands_sep, num+i); i += 3; } return str; } // Format capacity with SI prefixes const char * format_capacity(char * str, int strsize, uint64_t val, const char * decimal_point /* = 0 */) { if (!decimal_point) { decimal_point = "."; #ifdef HAVE_LOCALE_H setlocale(LC_ALL, ""); const struct lconv * currentlocale = localeconv(); if (*(currentlocale->decimal_point)) decimal_point = currentlocale->decimal_point; #endif } const unsigned factor = 1000; // 1024 for KiB,MiB,... static const char prefixes[] = " KMGTP"; // Find d with val in [d, d*factor) unsigned i = 0; uint64_t d = 1; for (uint64_t d2 = d * factor; val >= d2; d2 *= factor) { d = d2; if (++i >= sizeof(prefixes)-2) break; } // Print 3 digits uint64_t n = val / d; if (i == 0) snprintf(str, strsize, "%u B", (unsigned)n); else if (n >= 100) // "123 xB" snprintf(str, strsize, "%"PRIu64" %cB", n, prefixes[i]); else if (n >= 10) // "12.3 xB" snprintf(str, strsize, "%"PRIu64"%s%u %cB", n, decimal_point, (unsigned)(((val % d) * 10) / d), prefixes[i]); else // "1.23 xB" snprintf(str, strsize, "%"PRIu64"%s%02u %cB", n, decimal_point, (unsigned)(((val % d) * 100) / d), prefixes[i]); return str; } // return (v)sprintf() formatted std::string std::string vstrprintf(const char * fmt, va_list ap) { char buf[512]; vsnprintf(buf, sizeof(buf), fmt, ap); buf[sizeof(buf)-1] = 0; return buf; } std::string strprintf(const char * fmt, ...) { va_list ap; va_start(ap, fmt); std::string str = vstrprintf(fmt, ap); va_end(ap); return str; } #ifndef HAVE_WORKING_SNPRINTF // Some versions of (v)snprintf() don't append null char on overflow (MSVCRT.DLL), // and/or return -1 on overflow (old Linux). // Below are sane replacements substituted by #define in utility.h. #undef vsnprintf #if defined(_WIN32) && defined(_MSC_VER) #define vsnprintf _vsnprintf #endif int safe_vsnprintf(char *buf, int size, const char *fmt, va_list ap) { int i; if (size <= 0) return 0; i = vsnprintf(buf, size, fmt, ap); if (0 <= i && i < size) return i; buf[size-1] = 0; return strlen(buf); // Note: cannot detect for overflow, not necessary here. } int safe_snprintf(char *buf, int size, const char *fmt, ...) { int i; va_list ap; va_start(ap, fmt); i = safe_vsnprintf(buf, size, fmt, ap); va_end(ap); return i; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/dev_ata_cmd_set.cpp��������������������������������������������������0000644�0000000�0000000�00000006741�11227432427�020702� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * dev_ata_cmd_set.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "config.h" #include "int64.h" #include "atacmds.h" #include "dev_ata_cmd_set.h" #include <errno.h> const char * dev_ata_cmd_set_cpp_cvsid = "$Id: dev_ata_cmd_set.cpp,v 1.4 2008/10/24 21:49:23 manfred99 Exp $" DEV_ATA_CMD_SET_H_CVSID; ///////////////////////////////////////////////////////////////////////////// // ata_device_with_command_set // Adapter routine to implement new ATA pass through with old interface bool ata_device_with_command_set::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_ok(in, true)) // data_out_support return false; smart_command_set command = (smart_command_set)-1; int select = 0; char * data = (char *)in.buffer; char buffer[512]; switch (in.in_regs.command) { case ATA_IDENTIFY_DEVICE: command = IDENTIFY; break; case ATA_IDENTIFY_PACKET_DEVICE: command = PIDENTIFY; break; case ATA_CHECK_POWER_MODE: command = CHECK_POWER_MODE; data = buffer; data[0] = 0; break; case ATA_SMART_CMD: switch (in.in_regs.features) { case ATA_SMART_ENABLE: command = ENABLE; break; case ATA_SMART_READ_VALUES: command = READ_VALUES; break; case ATA_SMART_READ_THRESHOLDS: command = READ_THRESHOLDS; break; case ATA_SMART_READ_LOG_SECTOR: command = READ_LOG; select = in.in_regs.lba_low; break; case ATA_SMART_WRITE_LOG_SECTOR: command = WRITE_LOG; select = in.in_regs.lba_low; break; case ATA_SMART_DISABLE: command = DISABLE; break; case ATA_SMART_STATUS: command = (in.out_needed.lba_high ? STATUS_CHECK : STATUS); break; case ATA_SMART_AUTO_OFFLINE: command = AUTO_OFFLINE; select = in.in_regs.sector_count; break; case ATA_SMART_AUTOSAVE: command = AUTOSAVE; select = in.in_regs.sector_count; break; case ATA_SMART_IMMEDIATE_OFFLINE: command = IMMEDIATE_OFFLINE; select = in.in_regs.lba_low; break; default: return set_err(ENOSYS, "Unknown SMART command"); } break; default: return set_err(ENOSYS, "Non-SMART commands not implemented"); } clear_err(); errno = 0; int rc = ata_command_interface(command, select, data); if (rc < 0) { if (!get_errno()) set_err(errno); return false; } switch (command) { case CHECK_POWER_MODE: out.out_regs.sector_count = data[0]; break; case STATUS_CHECK: switch (rc) { case 0: // Good SMART status out.out_regs.lba_high = 0xc2; out.out_regs.lba_mid = 0x4f; break; case 1: // Bad SMART status out.out_regs.lba_high = 0x2c; out.out_regs.lba_mid = 0xf4; break; } break; default: break; } return true; } �������������������������������smartmontools-6.2+svn3841.orig/os_os2.cpp�����������������������������������������������������������0000644�0000000�0000000�00000041625�12125373277�017012� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_os2.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * * Thanks to Daniela Engert for providing sample code for SMART ioctl access. * */ // These are needed to define prototypes for the functions defined below #include <errno.h> #include "atacmds.h" #include "scsicmds.h" #include "utility.h" // This is to include whatever prototypes you define in os_generic.h #include "os_os2.h" // Needed by '-V' option (CVS versioning) of smartd/smartctl const char *os_XXXX_c_cvsid="$Id: os_os2.cpp 3806 2013-03-29 20:17:03Z chrfranke $" \ ATACMDS_H_CVSID OS_XXXX_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; // global handle to device driver static HFILE hDevice; // Please eliminate the following block: both the two #includes and // the 'unsupported()' function. They are only here to warn // unsuspecting users that their Operating System is not supported! If // you wish, you can use a similar warning mechanism for any of the // functions in this file that you can not (or choose not to) // implement. #include "config.h" typedef struct _IDEREGS { UCHAR bFeaturesReg; UCHAR bSectorCountReg; UCHAR bSectorNumberReg; UCHAR bCylLowReg; UCHAR bCylHighReg; UCHAR bDriveHeadReg; UCHAR bCommandReg; UCHAR bReserved; } IDEREGS, *PIDEREGS, *LPIDEREGS; static void unsupported(int which){ static int warninggiven[4]; if (which<0 || which>3) return; if (!warninggiven[which]) { char msg; warninggiven[which]=1; switch (which) { case 0: msg="generate a list of devices"; break; case 1: msg="interface to Marvell-based SATA controllers"; break; case 2: msg="interface to 3ware-based RAID controllers"; break; case 3: msg="interface to SCSI devices"; break; } pout("Under OS/2, smartmontools can not %s\n"); } return; } // print examples for smartctl. You should modify this function so // that the device paths are sensible for your OS, and to eliminate // unsupported commands (eg, 3ware controllers). void print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); #ifdef HAVE_GETOPT_LONG printf( " smartctl -a /dev/hda (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a --device=3ware,2 /dev/sda\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" ); #else printf( " smartctl -a /dev/hda (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a -d 3ware,2 /dev/sda\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" ); #endif return; } static const char * skipdev(const char * s) { return (!strncmp(s, "/dev/", 5) ? s + 5 : s); } // tries to guess device type given the name (a path). See utility.h // for return values. int guess_device_type (const char* dev_name) { //printf( "dev_name %s\n", dev_name); dev_name = skipdev(dev_name); if (!strncmp(dev_name, "hd", 2)) return CONTROLLER_ATA; if (!strncmp(dev_name, "scsi", 4)) return CONTROLLER_SCSI; return CONTROLLER_UNKNOWN; } // makes a list of ATA or SCSI devices for the DEVICESCAN directive of // smartd. Returns number N of devices, or -1 if out of // memory. Allocates N+1 arrays: one of N pointers (devlist); the // other N arrays each contain null-terminated character strings. In // the case N==0, no arrays are allocated because the array of 0 // pointers has zero length, equivalent to calling malloc(0). int make_device_names (char*** devlist, const char* name) { unsupported(0); return 0; } // Like open(). Return non-negative integer handle, only used by the // functions below. type=="ATA" or "SCSI". If you need to store // extra information about your devices, create a private internal // array within this file (see os_freebsd.cpp for an example). If you // can not open the device (permission denied, does not exist, etc) // set errno as open() does and return <0. int deviceopen(const char *pathname, char *type){ int fd; APIRET rc; ULONG ActionTaken; //printf( "deviceopen pathname %s\n", pathname); rc = DosOpen ("\\DEV\\IBMS506$", &hDevice, &ActionTaken, 0, FILE_SYSTEM, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_SHARE_DENYNONE | OPEN_FLAGS_NOINHERIT | OPEN_ACCESS_READONLY, NULL); if (rc) { char errmsg[256]; snprintf(errmsg,256,"Smartctl open driver IBMS506$ failed (%d)", rc); errmsg[255]='\0'; syserror(errmsg); return -1; } pathname = skipdev(pathname); fd = tolower(pathname[2]) - 'a'; return fd; } // Like close(). Acts only on integer handles returned by // deviceopen() above. int deviceclose(int fd){ DosClose( hDevice); hDevice = NULL; return 0; } static void print_ide_regs(const IDEREGS * r, int out) { pout("%s=0x%02x,%s=0x%02x, SC=0x%02x, NS=0x%02x, CL=0x%02x, CH=0x%02x, SEL=0x%02x\n", (out?"STS":"CMD"), r->bCommandReg, (out?"ERR":" FR"), r->bFeaturesReg, r->bSectorCountReg, r->bSectorNumberReg, r->bCylLowReg, r->bCylHighReg, r->bDriveHeadReg); } // // OS/2 direct ioctl interface to IBMS506$ // int dani_ioctl( int device, int request, void* arg) { unsigned char* buff = (unsigned char*) arg; APIRET rc; DSKSP_CommandParameters Parms; ULONG PLen = 1; ULONG DLen = 512; //sizeof (*buf); UCHAR temp; ULONG value = 0; IDEREGS regs; //printf( "device %d, request 0x%x, arg[0] 0x%x, arg[2] 0x%x\n", device, request, buff[0], buff[2]); Parms.byPhysicalUnit = device; switch( buff[0]) { case WIN_IDENTIFY: rc = DosDevIOCtl (hDevice, DSKSP_CAT_GENERIC, DSKSP_GET_INQUIRY_DATA, (PVOID)&Parms, PLen, &PLen, (PVOID)arg+4, DLen, &DLen); if (rc != 0) { printf ("DANIS506 ATA GET HD Failed (%d,0x%x)\n", rc, rc); return -1; } break; case WIN_SMART: switch( buff[2]) { case SMART_STATUS: DLen = sizeof(value); // OS/2 already checks CL/CH in IBM1S506 code!! see s506rte.c (ddk) // value: -1=not supported, 0=ok, 1=failing rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_GETSTATUS, (PVOID)&Parms, PLen, &PLen, (PVOID)&value, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET SMART_STATUS failed (%d,0x%x)\n", rc, rc); return -1; } buff[4] = (unsigned char)value; break; case SMART_READ_VALUES: rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_GET_ATTRIBUTES, (PVOID)&Parms, PLen, &PLen, (PVOID)arg+4, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_GET_ATTRIBUTES failed (%d,0x%x)\n", rc, rc); return -1; } break; case SMART_READ_THRESHOLDS: rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_GET_THRESHOLDS, (PVOID)&Parms, PLen, &PLen, (PVOID)arg+4, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_GET_THRESHOLDS failed (%d,0x%x)\n", rc, rc); return -1; } break; case SMART_READ_LOG_SECTOR: buff[4] = buff[1]; // copy select field rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_READ_LOG, (PVOID)&Parms, PLen, &PLen, (PVOID)arg+4, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_READ_LOG failed (%d,0x%x)\n", rc, rc); return -1; } break; case SMART_ENABLE: buff[0] = 1; // enable DLen = 1; rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_ONOFF, (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_ONOFF failed (%d,0x%x)\n", rc, rc); return -1; } break; case SMART_DISABLE: buff[0] = 0; // disable DLen = 1; rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_ONOFF, (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_ONOFF failed (%d,0x%x)\n", rc, rc); return -1; } break; #if 0 case SMART_AUTO_OFFLINE: buff[0] = buff[3]; // select field DLen = 1; rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_AUTO_OFFLINE, (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_ONOFF failed (%d,0x%x)\n", rc, rc); return -1; } break; #endif case SMART_AUTOSAVE: buff[0] = buff[3]; // select field DLen = 1; rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_AUTOSAVE_ONOFF, (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen); if (rc) { printf ("DANIS506 ATA DSKSP_SMART_AUTOSAVE_ONOFF failed (%d,0x%x)\n", rc, rc); return -1; } break; case SMART_IMMEDIATE_OFFLINE: buff[0] = buff[1]; // select field DLen = 1; rc = DosDevIOCtl (hDevice, DSKSP_CAT_SMART, DSKSP_SMART_EOLI, (PVOID)&Parms, PLen, &PLen, (PVOID)buff, DLen, &DLen); if (rc) { printf ("DANIS506 ATA GET DSKSP_SMART_EXEC_OFFLINE failed (%d,0x%x)\n", rc, rc); return -1; } break; default: fprintf( stderr, "device %d, request 0x%x, arg[0] 0x%x, arg[2] 0x%x\n", device, request, buff[0], buff[2]); fprintf( stderr, "unknown ioctl\n"); return -1; break; } break; //case WIN_PIDENTIFY: // break; default: fprintf( stderr, "unknown ioctl\n"); return -1; break; } // ok return 0; } // Interface to ATA devices. See os_linux.cpp for the cannonical example. // DETAILED DESCRIPTION OF ARGUMENTS // device: is the integer handle provided by deviceopen() // command: defines the different operations, see atacmds.h // select: additional input data IF NEEDED (which log, which type of // self-test). // data: location to write output data, IF NEEDED (1 or 512 bytes). // Note: not all commands use all arguments. // RETURN VALUES (for all commands BUT command==STATUS_CHECK) // -1 if the command failed // 0 if the command succeeded, // RETURN VALUES if command==STATUS_CHECK // -1 if the command failed OR the disk SMART status can't be determined // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" // huge value of buffer size needed because HDIO_DRIVE_CMD assumes // that buff[3] is the data size. Since the ATA_SMART_AUTOSAVE and // ATA_SMART_AUTO_OFFLINE use values of 0xf1 and 0xf8 we need the space. // Otherwise a 4+512 byte buffer would be enough. #define STRANGE_BUFFER_LENGTH (4+512*0xf8) int ata_command_interface(int device, smart_command_set command, int select, char *data){ unsigned char buff[STRANGE_BUFFER_LENGTH]; // positive: bytes to write to caller. negative: bytes to READ from // caller. zero: non-data command int copydata=0; const int HDIO_DRIVE_CMD_OFFSET = 4; // See struct hd_drive_cmd_hdr in hdreg.h. Before calling ioctl() // buff[0]: ATA COMMAND CODE REGISTER // buff[1]: ATA SECTOR NUMBER REGISTER == LBA LOW REGISTER // buff[2]: ATA FEATURES REGISTER // buff[3]: ATA SECTOR COUNT REGISTER // Note that on return: // buff[2] contains the ATA SECTOR COUNT REGISTER // clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes) memset(buff, 0, STRANGE_BUFFER_LENGTH); //printf( "command, select %d,%d\n", command, select); buff[0]=ATA_SMART_CMD; switch (command){ case CHECK_POWER_MODE: buff[0]=ATA_CHECK_POWER_MODE; copydata=1; break; case READ_VALUES: buff[2]=ATA_SMART_READ_VALUES; buff[3]=1; copydata=512; break; case READ_THRESHOLDS: buff[2]=ATA_SMART_READ_THRESHOLDS; buff[1]=buff[3]=1; copydata=512; break; case READ_LOG: buff[2]=ATA_SMART_READ_LOG_SECTOR; buff[1]=select; buff[3]=1; copydata=512; break; case WRITE_LOG: break; case IDENTIFY: buff[0]=ATA_IDENTIFY_DEVICE; buff[3]=1; copydata=512; break; case PIDENTIFY: buff[0]=ATA_IDENTIFY_PACKET_DEVICE; buff[3]=1; copydata=512; break; case ENABLE: buff[2]=ATA_SMART_ENABLE; buff[1]=1; break; case DISABLE: buff[2]=ATA_SMART_DISABLE; buff[1]=1; break; case STATUS: case STATUS_CHECK: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. buff[2]=ATA_SMART_STATUS; buff[4]=0; break; case AUTO_OFFLINE: buff[2]=ATA_SMART_AUTO_OFFLINE; buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case AUTOSAVE: buff[2]=ATA_SMART_AUTOSAVE; buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case IMMEDIATE_OFFLINE: buff[2]=ATA_SMART_IMMEDIATE_OFFLINE; buff[1]=select; break; //case STATUS_CHECK: // // This command uses HDIO_DRIVE_TASK and has different syntax than // // the other commands. // buff[1]=ATA_SMART_STATUS; // break; default: pout("Unrecognized command %d in linux_ata_command_interface()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); errno=ENOSYS; return -1; } #if 0 // This command uses the HDIO_DRIVE_TASKFILE ioctl(). This is the // only ioctl() that can be used to WRITE data to the disk. if (command==WRITE_LOG) { unsigned char task[sizeof(ide_task_request_t)+512]; ide_task_request_t *reqtask=(ide_task_request_t *) task; task_struct_t *taskfile=(task_struct_t *) reqtask->io_ports; int retval; memset(task, 0, sizeof(task)); taskfile->data = 0; taskfile->feature = ATA_SMART_WRITE_LOG_SECTOR; taskfile->sector_count = 1; taskfile->sector_number = select; taskfile->low_cylinder = 0x4f; taskfile->high_cylinder = 0xc2; taskfile->device_head = 0; taskfile->command = ATA_SMART_CMD; reqtask->data_phase = TASKFILE_OUT; reqtask->req_cmd = IDE_DRIVE_TASK_OUT; reqtask->out_size = 512; reqtask->in_size = 0; // copy user data into the task request structure memcpy(task+sizeof(ide_task_request_t), data, 512); if ((retval=dani_ioctl(device, HDIO_DRIVE_TASKFILE, task))) { if (retval==-EINVAL) pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASKFILE_IO set\n"); return -1; } return 0; } #endif // 0 // We are now doing the HDIO_DRIVE_CMD type ioctl. if ((dani_ioctl(device, HDIO_DRIVE_CMD, buff))) return -1; // There are two different types of ioctls(). The HDIO_DRIVE_TASK // one is this: if (command==STATUS_CHECK){ int retval; // Cyl low and Cyl high unchanged means "Good SMART status" if (buff[4]==0) return 0; // These values mean "Bad SMART status" if (buff[4]==1) return 1; // We haven't gotten output that makes sense; print out some debugging info syserror("Error SMART Status command failed"); pout("Please get assistance from " PACKAGE_HOMEPAGE "\n"); return -1; } // CHECK POWER MODE command returns information in the Sector Count // register (buff[3]). Copy to return data buffer. if (command==CHECK_POWER_MODE) buff[HDIO_DRIVE_CMD_OFFSET]=buff[2]; // if the command returns data then copy it back if (copydata) memcpy(data, buff+HDIO_DRIVE_CMD_OFFSET, copydata); return 0; } // Interface to SCSI devices. See os_linux.c int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) { unsupported(3); return -ENOSYS; } �����������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartd.cpp�����������������������������������������������������������0000644�0000000�0000000�00000535032�12123643645�017075� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net> * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #include "config.h" #include "int64.h" // unconditionally included files #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> // umask #include <signal.h> #include <fcntl.h> #include <string.h> #include <syslog.h> #include <stdarg.h> #include <stdlib.h> #include <errno.h> #include <time.h> #include <limits.h> #include <getopt.h> #include <stdexcept> #include <string> #include <vector> #include <algorithm> // std::replace() // conditionally included files #ifndef _WIN32 #include <sys/wait.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif #ifdef HAVE_NETDB_H #include <netdb.h> #endif #ifdef _WIN32 #ifdef _MSC_VER #pragma warning(disable:4761) // "conversion supplied" typedef unsigned short mode_t; typedef int pid_t; #endif #include <io.h> // umask() #include <process.h> // getpid() #endif // _WIN32 #ifdef __CYGWIN__ #include <io.h> // setmode() #endif // __CYGWIN__ #ifdef HAVE_LIBCAP_NG #include <cap-ng.h> #endif // LIBCAP_NG // locally included files #include "atacmds.h" #include "dev_interface.h" #include "knowndrives.h" #include "scsicmds.h" #include "utility.h" // This is for solaris, where signal() resets the handler to SIG_DFL // after the first signal is caught. #ifdef HAVE_SIGSET #define SIGNALFN sigset #else #define SIGNALFN signal #endif #ifdef _WIN32 // fork()/signal()/initd simulation for native Windows #include "daemon_win32.h" // daemon_main/detach/signal() #undef SIGNALFN #define SIGNALFN daemon_signal #define strsignal daemon_strsignal #define sleep daemon_sleep // SIGQUIT does not exist, CONTROL-Break signals SIGBREAK. #define SIGQUIT SIGBREAK #define SIGQUIT_KEYNAME "CONTROL-Break" #else // _WIN32 #define SIGQUIT_KEYNAME "CONTROL-\\" #endif // _WIN32 #if defined (__SVR4) && defined (__sun) extern "C" int getdomainname(char *, int); // no declaration in header files! #endif const char * smartd_cpp_cvsid = "$Id: smartd.cpp 3802 2013-03-24 18:36:21Z chrfranke $" CONFIG_H_CVSID; // smartd exit codes #define EXIT_BADCMD 1 // command line did not parse #define EXIT_BADCONF 2 // syntax error in config file #define EXIT_STARTUP 3 // problem forking daemon #define EXIT_PID 4 // problem creating pid file #define EXIT_NOCONF 5 // config file does not exist #define EXIT_READCONF 6 // config file exists but cannot be read #define EXIT_NOMEM 8 // out of memory #define EXIT_BADCODE 10 // internal error - should NEVER happen #define EXIT_BADDEV 16 // we can't monitor this device #define EXIT_NODEV 17 // no devices to monitor #define EXIT_SIGNAL 254 // abort on signal // command-line: 1=debug mode, 2=print presets static unsigned char debugmode = 0; // command-line: how long to sleep between checks #define CHECKTIME 1800 static int checktime=CHECKTIME; // command-line: name of PID file (empty for no pid file) static std::string pid_file; // command-line: path prefix of persistent state file, empty if no persistence. static std::string state_path_prefix #ifdef SMARTMONTOOLS_SAVESTATES = SMARTMONTOOLS_SAVESTATES #endif ; // command-line: path prefix of attribute log file, empty if no logs. static std::string attrlog_path_prefix #ifdef SMARTMONTOOLS_ATTRIBUTELOG = SMARTMONTOOLS_ATTRIBUTELOG #endif ; // configuration file name static const char * configfile; // configuration file "name" if read from stdin static const char * const configfile_stdin = "<stdin>"; // path of alternate configuration file static std::string configfile_alt; // warning script file static std::string warning_script; // command-line: when should we exit? static int quit=0; // command-line; this is the default syslog(3) log facility to use. static int facility=LOG_DAEMON; #ifndef _WIN32 // command-line: fork into background? static bool do_fork=true; #endif #ifdef HAVE_LIBCAP_NG // command-line: enable capabilities? static bool enable_capabilities = false; #endif // TODO: This smartctl only variable is also used in os_win32.cpp unsigned char failuretest_permissive = 0; // set to one if we catch a USR1 (check devices now) static volatile int caughtsigUSR1=0; #ifdef _WIN32 // set to one if we catch a USR2 (toggle debug mode) static volatile int caughtsigUSR2=0; #endif // set to one if we catch a HUP (reload config file). In debug mode, // set to two, if we catch INT (also reload config file). static volatile int caughtsigHUP=0; // set to signal value if we catch INT, QUIT, or TERM static volatile int caughtsigEXIT=0; // This function prints either to stdout or to the syslog as needed. static void PrintOut(int priority, const char *fmt, ...) __attribute_format_printf(2, 3); // Attribute monitoring flags. // See monitor_attr_flags below. enum { MONITOR_IGN_FAILUSE = 0x01, MONITOR_IGNORE = 0x02, MONITOR_RAW_PRINT = 0x04, MONITOR_RAW = 0x08, MONITOR_AS_CRIT = 0x10, MONITOR_RAW_AS_CRIT = 0x20, }; // Array of flags for each attribute. class attribute_flags { public: attribute_flags() { memset(m_flags, 0, sizeof(m_flags)); } bool is_set(int id, unsigned char flag) const { return (0 < id && id < (int)sizeof(m_flags) && (m_flags[id] & flag)); } void set(int id, unsigned char flags) { if (0 < id && id < (int)sizeof(m_flags)) m_flags[id] |= flags; } private: unsigned char m_flags[256]; }; /// Configuration data for a device. Read from smartd.conf. /// Supports copy & assignment and is compatible with STL containers. struct dev_config { int lineno; // Line number of entry in file std::string name; // Device name (with optional extra info) std::string dev_name; // Device name (plain, for SMARTD_DEVICE variable) std::string dev_type; // Device type argument from -d directive, empty if none std::string dev_idinfo; // Device identify info for warning emails std::string state_file; // Path of the persistent state file, empty if none std::string attrlog_file; // Path of the persistent attrlog file, empty if none bool ignore; // Ignore this entry bool smartcheck; // Check SMART status bool usagefailed; // Check for failed Usage Attributes bool prefail; // Track changes in Prefail Attributes bool usage; // Track changes in Usage Attributes bool selftest; // Monitor number of selftest errors bool errorlog; // Monitor number of ATA errors bool xerrorlog; // Monitor number of ATA errors (Extended Comprehensive error log) bool offlinests; // Monitor changes in offline data collection status bool offlinests_ns; // Disable auto standby if in progress bool selfteststs; // Monitor changes in self-test execution status bool selfteststs_ns; // Disable auto standby if in progress bool permissive; // Ignore failed SMART commands char autosave; // 1=disable, 2=enable Autosave Attributes char autoofflinetest; // 1=disable, 2=enable Auto Offline Test firmwarebug_defs firmwarebugs; // -F directives from drivedb or smartd.conf bool ignorepresets; // Ignore database of -v options bool showpresets; // Show database entry for this device bool removable; // Device may disappear (not be present) char powermode; // skip check, if disk in idle or standby mode bool powerquiet; // skip powermode 'skipping checks' message int powerskipmax; // how many times can be check skipped unsigned char tempdiff; // Track Temperature changes >= this limit unsigned char tempinfo, tempcrit; // Track Temperatures >= these limits as LOG_INFO, LOG_CRIT+mail regular_expression test_regex; // Regex for scheduled testing // Configuration of email warning messages std::string emailcmdline; // script to execute, empty if no messages std::string emailaddress; // email address, or empty unsigned char emailfreq; // Emails once (1) daily (2) diminishing (3) bool emailtest; // Send test email? // ATA ONLY int dev_rpm; // rotation rate, 0 = unknown, 1 = SSD, >1 = HDD int set_aam; // disable(-1), enable(1..255->0..254) Automatic Acoustic Management int set_apm; // disable(-1), enable(2..255->1..254) Advanced Power Management int set_lookahead; // disable(-1), enable(1) read look-ahead int set_standby; // set(1..255->0..254) standby timer bool set_security_freeze; // Freeze ATA security int set_wcache; // disable(-1), enable(1) write cache bool sct_erc_set; // set SCT ERC to: unsigned short sct_erc_readtime; // ERC read time (deciseconds) unsigned short sct_erc_writetime; // ERC write time (deciseconds) unsigned char curr_pending_id; // ID of current pending sector count, 0 if none unsigned char offl_pending_id; // ID of offline uncorrectable sector count, 0 if none bool curr_pending_incr, offl_pending_incr; // True if current/offline pending values increase bool curr_pending_set, offl_pending_set; // True if '-C', '-U' set in smartd.conf attribute_flags monitor_attr_flags; // MONITOR_* flags for each attribute ata_vendor_attr_defs attribute_defs; // -v options dev_config(); }; dev_config::dev_config() : lineno(0), ignore(false), smartcheck(false), usagefailed(false), prefail(false), usage(false), selftest(false), errorlog(false), xerrorlog(false), offlinests(false), offlinests_ns(false), selfteststs(false), selfteststs_ns(false), permissive(false), autosave(0), autoofflinetest(0), ignorepresets(false), showpresets(false), removable(false), powermode(0), powerquiet(false), powerskipmax(0), tempdiff(0), tempinfo(0), tempcrit(0), emailfreq(0), emailtest(false), dev_rpm(0), set_aam(0), set_apm(0), set_lookahead(0), set_standby(0), set_security_freeze(false), set_wcache(0), sct_erc_set(false), sct_erc_readtime(0), sct_erc_writetime(0), curr_pending_id(0), offl_pending_id(0), curr_pending_incr(false), offl_pending_incr(false), curr_pending_set(false), offl_pending_set(false) { } // Number of allowed mail message types static const int SMARTD_NMAIL = 13; // Type for '-M test' mails (state not persistent) static const int MAILTYPE_TEST = 0; // TODO: Add const or enum for all mail types. struct mailinfo { int logged;// number of times an email has been sent time_t firstsent;// time first email was sent, as defined by time(2) time_t lastsent; // time last email was sent, as defined by time(2) mailinfo() : logged(0), firstsent(0), lastsent(0) { } }; /// Persistent state data for a device. struct persistent_dev_state { unsigned char tempmin, tempmax; // Min/Max Temperatures unsigned char selflogcount; // total number of self-test errors unsigned short selfloghour; // lifetime hours of last self-test error time_t scheduled_test_next_check; // Time of next check for scheduled self-tests uint64_t selective_test_last_start; // Start LBA of last scheduled selective self-test uint64_t selective_test_last_end; // End LBA of last scheduled selective self-test mailinfo maillog[SMARTD_NMAIL]; // log info on when mail sent // ATA ONLY int ataerrorcount; // Total number of ATA errors // Persistent part of ata_smart_values: struct ata_attribute { unsigned char id; unsigned char val; unsigned char worst; // Byte needed for 'raw64' attribute only. uint64_t raw; unsigned char resvd; ata_attribute() : id(0), val(0), worst(0), raw(0), resvd(0) { } }; ata_attribute ata_attributes[NUMBER_ATA_SMART_ATTRIBUTES]; // SCSI ONLY struct scsi_error_counter { struct scsiErrorCounter errCounter; unsigned char found; scsi_error_counter() : found(0) { } }; scsi_error_counter scsi_error_counters[3]; struct scsi_nonmedium_error { struct scsiNonMediumError nme; unsigned char found; scsi_nonmedium_error() : found(0) { } }; scsi_nonmedium_error scsi_nonmedium_error; persistent_dev_state(); }; persistent_dev_state::persistent_dev_state() : tempmin(0), tempmax(0), selflogcount(0), selfloghour(0), scheduled_test_next_check(0), selective_test_last_start(0), selective_test_last_end(0), ataerrorcount(0) { } /// Non-persistent state data for a device. struct temp_dev_state { bool must_write; // true if persistent part should be written bool not_cap_offline; // true == not capable of offline testing bool not_cap_conveyance; bool not_cap_short; bool not_cap_long; bool not_cap_selective; unsigned char temperature; // last recorded Temperature (in Celsius) time_t tempmin_delay; // time where Min Temperature tracking will start bool powermodefail; // true if power mode check failed int powerskipcnt; // Number of checks skipped due to idle or standby mode // SCSI ONLY unsigned char SmartPageSupported; // has log sense IE page (0x2f) unsigned char TempPageSupported; // has log sense temperature page (0xd) unsigned char ReadECounterPageSupported; unsigned char WriteECounterPageSupported; unsigned char VerifyECounterPageSupported; unsigned char NonMediumErrorPageSupported; unsigned char SuppressReport; // minimize nuisance reports unsigned char modese_len; // mode sense/select cmd len: 0 (don't // know yet) 6 or 10 // ATA ONLY uint64_t num_sectors; // Number of sectors ata_smart_values smartval; // SMART data ata_smart_thresholds_pvt smartthres; // SMART thresholds bool offline_started; // true if offline data collection was started bool selftest_started; // true if self-test was started temp_dev_state(); }; temp_dev_state::temp_dev_state() : must_write(false), not_cap_offline(false), not_cap_conveyance(false), not_cap_short(false), not_cap_long(false), not_cap_selective(false), temperature(0), tempmin_delay(0), powermodefail(false), powerskipcnt(0), SmartPageSupported(false), TempPageSupported(false), ReadECounterPageSupported(false), WriteECounterPageSupported(false), VerifyECounterPageSupported(false), NonMediumErrorPageSupported(false), SuppressReport(false), modese_len(0), num_sectors(0), offline_started(false), selftest_started(false) { memset(&smartval, 0, sizeof(smartval)); memset(&smartthres, 0, sizeof(smartthres)); } /// Runtime state data for a device. struct dev_state : public persistent_dev_state, public temp_dev_state { void update_persistent_state(); void update_temp_state(); }; /// Container for configuration info for each device. typedef std::vector<dev_config> dev_config_vector; /// Container for state info for each device. typedef std::vector<dev_state> dev_state_vector; // Copy ATA attributes to persistent state. void dev_state::update_persistent_state() { for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const ata_smart_attribute & ta = smartval.vendor_attributes[i]; ata_attribute & pa = ata_attributes[i]; pa.id = ta.id; if (ta.id == 0) { pa.val = pa.worst = 0; pa.raw = 0; continue; } pa.val = ta.current; pa.worst = ta.worst; pa.raw = ta.raw[0] | ( ta.raw[1] << 8) | ( ta.raw[2] << 16) | ((uint64_t)ta.raw[3] << 24) | ((uint64_t)ta.raw[4] << 32) | ((uint64_t)ta.raw[5] << 40); pa.resvd = ta.reserv; } } // Copy ATA from persistent to temp state. void dev_state::update_temp_state() { for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const ata_attribute & pa = ata_attributes[i]; ata_smart_attribute & ta = smartval.vendor_attributes[i]; ta.id = pa.id; if (pa.id == 0) { ta.current = ta.worst = 0; memset(ta.raw, 0, sizeof(ta.raw)); continue; } ta.current = pa.val; ta.worst = pa.worst; ta.raw[0] = (unsigned char) pa.raw; ta.raw[1] = (unsigned char)(pa.raw >> 8); ta.raw[2] = (unsigned char)(pa.raw >> 16); ta.raw[3] = (unsigned char)(pa.raw >> 24); ta.raw[4] = (unsigned char)(pa.raw >> 32); ta.raw[5] = (unsigned char)(pa.raw >> 40); ta.reserv = pa.resvd; } } // Parse a line from a state file. static bool parse_dev_state_line(const char * line, persistent_dev_state & state) { static const regular_expression regex( "^ *" "((temperature-min)" // (1 (2) "|(temperature-max)" // (3) "|(self-test-errors)" // (4) "|(self-test-last-err-hour)" // (5) "|(scheduled-test-next-check)" // (6) "|(selective-test-last-start)" // (7) "|(selective-test-last-end)" // (8) "|(ata-error-count)" // (9) "|(mail\\.([0-9]+)\\." // (10 (11) "((count)" // (12 (13) "|(first-sent-time)" // (14) "|(last-sent-time)" // (15) ")" // 12) ")" // 10) "|(ata-smart-attribute\\.([0-9]+)\\." // (16 (17) "((id)" // (18 (19) "|(val)" // (20) "|(worst)" // (21) "|(raw)" // (22) "|(resvd)" // (23) ")" // 18) ")" // 16) ")" // 1) " *= *([0-9]+)[ \n]*$", // (24) REG_EXTENDED ); const int nmatch = 1+24; regmatch_t match[nmatch]; if (!regex.execute(line, nmatch, match)) return false; if (match[nmatch-1].rm_so < 0) return false; uint64_t val = strtoull(line + match[nmatch-1].rm_so, (char **)0, 10); int m = 1; if (match[++m].rm_so >= 0) state.tempmin = (unsigned char)val; else if (match[++m].rm_so >= 0) state.tempmax = (unsigned char)val; else if (match[++m].rm_so >= 0) state.selflogcount = (unsigned char)val; else if (match[++m].rm_so >= 0) state.selfloghour = (unsigned short)val; else if (match[++m].rm_so >= 0) state.scheduled_test_next_check = (time_t)val; else if (match[++m].rm_so >= 0) state.selective_test_last_start = val; else if (match[++m].rm_so >= 0) state.selective_test_last_end = val; else if (match[++m].rm_so >= 0) state.ataerrorcount = (int)val; else if (match[m+=2].rm_so >= 0) { int i = atoi(line+match[m].rm_so); if (!(0 <= i && i < SMARTD_NMAIL)) return false; if (i == MAILTYPE_TEST) // Don't suppress test mails return true; if (match[m+=2].rm_so >= 0) state.maillog[i].logged = (int)val; else if (match[++m].rm_so >= 0) state.maillog[i].firstsent = (time_t)val; else if (match[++m].rm_so >= 0) state.maillog[i].lastsent = (time_t)val; else return false; } else if (match[m+=5+1].rm_so >= 0) { int i = atoi(line+match[m].rm_so); if (!(0 <= i && i < NUMBER_ATA_SMART_ATTRIBUTES)) return false; if (match[m+=2].rm_so >= 0) state.ata_attributes[i].id = (unsigned char)val; else if (match[++m].rm_so >= 0) state.ata_attributes[i].val = (unsigned char)val; else if (match[++m].rm_so >= 0) state.ata_attributes[i].worst = (unsigned char)val; else if (match[++m].rm_so >= 0) state.ata_attributes[i].raw = val; else if (match[++m].rm_so >= 0) state.ata_attributes[i].resvd = (unsigned char)val; else return false; } else return false; return true; } // Read a state file. static bool read_dev_state(const char * path, persistent_dev_state & state) { stdio_file f(path, "r"); if (!f) { if (errno != ENOENT) pout("Cannot read state file \"%s\"\n", path); return false; } #ifdef __CYGWIN__ setmode(fileno(f), O_TEXT); // Allow files with \r\n #endif persistent_dev_state new_state; int good = 0, bad = 0; char line[256]; while (fgets(line, sizeof(line), f)) { const char * s = line + strspn(line, " \t"); if (!*s || *s == '#') continue; if (!parse_dev_state_line(line, new_state)) bad++; else good++; } if (bad) { if (!good) { pout("%s: format error\n", path); return false; } pout("%s: %d invalid line(s) ignored\n", path, bad); } // This sets the values missing in the file to 0. state = new_state; return true; } static void write_dev_state_line(FILE * f, const char * name, uint64_t val) { if (val) fprintf(f, "%s = %"PRIu64"\n", name, val); } static void write_dev_state_line(FILE * f, const char * name1, int id, const char * name2, uint64_t val) { if (val) fprintf(f, "%s.%d.%s = %"PRIu64"\n", name1, id, name2, val); } // Write a state file static bool write_dev_state(const char * path, const persistent_dev_state & state) { // Rename old "file" to "file~" std::string pathbak = path; pathbak += '~'; unlink(pathbak.c_str()); rename(path, pathbak.c_str()); stdio_file f(path, "w"); if (!f) { pout("Cannot create state file \"%s\"\n", path); return false; } fprintf(f, "# smartd state file\n"); write_dev_state_line(f, "temperature-min", state.tempmin); write_dev_state_line(f, "temperature-max", state.tempmax); write_dev_state_line(f, "self-test-errors", state.selflogcount); write_dev_state_line(f, "self-test-last-err-hour", state.selfloghour); write_dev_state_line(f, "scheduled-test-next-check", state.scheduled_test_next_check); write_dev_state_line(f, "selective-test-last-start", state.selective_test_last_start); write_dev_state_line(f, "selective-test-last-end", state.selective_test_last_end); int i; for (i = 0; i < SMARTD_NMAIL; i++) { if (i == MAILTYPE_TEST) // Don't suppress test mails continue; const mailinfo & mi = state.maillog[i]; if (!mi.logged) continue; write_dev_state_line(f, "mail", i, "count", mi.logged); write_dev_state_line(f, "mail", i, "first-sent-time", mi.firstsent); write_dev_state_line(f, "mail", i, "last-sent-time", mi.lastsent); } // ATA ONLY write_dev_state_line(f, "ata-error-count", state.ataerrorcount); for (i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const persistent_dev_state::ata_attribute & pa = state.ata_attributes[i]; if (!pa.id) continue; write_dev_state_line(f, "ata-smart-attribute", i, "id", pa.id); write_dev_state_line(f, "ata-smart-attribute", i, "val", pa.val); write_dev_state_line(f, "ata-smart-attribute", i, "worst", pa.worst); write_dev_state_line(f, "ata-smart-attribute", i, "raw", pa.raw); write_dev_state_line(f, "ata-smart-attribute", i, "resvd", pa.resvd); } return true; } // Write to the attrlog file static bool write_dev_attrlog(const char * path, const dev_state & state) { stdio_file f(path, "a"); if (!f) { pout("Cannot create attribute log file \"%s\"\n", path); return false; } time_t now = time(0); struct tm * tms = gmtime(&now); fprintf(f, "%d-%02d-%02d %02d:%02d:%02d;", 1900+tms->tm_year, 1+tms->tm_mon, tms->tm_mday, tms->tm_hour, tms->tm_min, tms->tm_sec); // ATA ONLY for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { const persistent_dev_state::ata_attribute & pa = state.ata_attributes[i]; if (!pa.id) continue; fprintf(f, "\t%d;%d;%"PRIu64";", pa.id, pa.val, pa.raw); } // SCSI ONLY const struct scsiErrorCounter * ecp; const char * pageNames[3] = {"read", "write", "verify"}; for (int k = 0; k < 3; ++k) { if ( !state.scsi_error_counters[k].found ) continue; ecp = &state.scsi_error_counters[k].errCounter; fprintf(f, "\t%s-corr-by-ecc-fast;%"PRIu64";" "\t%s-corr-by-ecc-delayed;%"PRIu64";" "\t%s-corr-by-retry;%"PRIu64";" "\t%s-total-err-corrected;%"PRIu64";" "\t%s-corr-algorithm-invocations;%"PRIu64";" "\t%s-gb-processed;%.3f;" "\t%s-total-unc-errors;%"PRIu64";", pageNames[k], ecp->counter[0], pageNames[k], ecp->counter[1], pageNames[k], ecp->counter[2], pageNames[k], ecp->counter[3], pageNames[k], ecp->counter[4], pageNames[k], (ecp->counter[5] / 1000000000.0), pageNames[k], ecp->counter[6]); } if(state.scsi_nonmedium_error.found && state.scsi_nonmedium_error.nme.gotPC0) { fprintf(f, "\tnon-medium-errors;%"PRIu64";", state.scsi_nonmedium_error.nme.counterPC0); } // write SCSI current temperature if it is monitored if(state.TempPageSupported && state.temperature) fprintf(f, "\ttemperature;%d;", state.temperature); // end of line fprintf(f, "\n"); return true; } // Write all state files. If write_always is false, don't write // unless must_write is set. static void write_all_dev_states(const dev_config_vector & configs, dev_state_vector & states, bool write_always = true) { for (unsigned i = 0; i < states.size(); i++) { const dev_config & cfg = configs.at(i); if (cfg.state_file.empty()) continue; dev_state & state = states[i]; if (!write_always && !state.must_write) continue; if (!write_dev_state(cfg.state_file.c_str(), state)) continue; state.must_write = false; if (write_always || debugmode) PrintOut(LOG_INFO, "Device: %s, state written to %s\n", cfg.name.c_str(), cfg.state_file.c_str()); } } // Write to all attrlog files static void write_all_dev_attrlogs(const dev_config_vector & configs, dev_state_vector & states) { for (unsigned i = 0; i < states.size(); i++) { const dev_config & cfg = configs.at(i); if (cfg.attrlog_file.empty()) continue; dev_state & state = states[i]; write_dev_attrlog(cfg.attrlog_file.c_str(), state); } } // remove the PID file static void RemovePidFile() { if (!pid_file.empty()) { if (unlink(pid_file.c_str())) PrintOut(LOG_CRIT,"Can't unlink PID file %s (%s).\n", pid_file.c_str(), strerror(errno)); pid_file.clear(); } return; } extern "C" { // signal handlers require C-linkage // Note if we catch a SIGUSR1 static void USR1handler(int sig) { if (SIGUSR1==sig) caughtsigUSR1=1; return; } #ifdef _WIN32 // Note if we catch a SIGUSR2 static void USR2handler(int sig) { if (SIGUSR2==sig) caughtsigUSR2=1; return; } #endif // Note if we catch a HUP (or INT in debug mode) static void HUPhandler(int sig) { if (sig==SIGHUP) caughtsigHUP=1; else caughtsigHUP=2; return; } // signal handler for TERM, QUIT, and INT (if not in debug mode) static void sighandler(int sig) { if (!caughtsigEXIT) caughtsigEXIT=sig; return; } } // extern "C" // Cleanup, print Goodbye message and remove pidfile static int Goodbye(int status) { // delete PID file, if one was created RemovePidFile(); // if we are exiting because of a code bug, tell user if (status==EXIT_BADCODE) PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n"); // and this should be the final output from smartd before it exits PrintOut(status?LOG_CRIT:LOG_INFO, "smartd is exiting (exit status %d)\n", status); return status; } // a replacement for setenv() which is not available on all platforms. // Note that the string passed to putenv must not be freed or made // invalid, since a pointer to it is kept by putenv(). This means that // it must either be a static buffer or allocated off the heap. The // string can be freed if the environment variable is redefined via // another call to putenv(). There is no portable way to unset a variable // with putenv(). So we manage the buffer in a static object. // Using setenv() if available is not considered because some // implementations may produce memory leaks. class env_buffer { public: env_buffer() : m_buf((char *)0) { } void set(const char * name, const char * value); private: char * m_buf; env_buffer(const env_buffer &); void operator=(const env_buffer &); }; void env_buffer::set(const char * name, const char * value) { int size = strlen(name) + 1 + strlen(value) + 1; char * newbuf = new char[size]; snprintf(newbuf, size, "%s=%s", name, value); if (putenv(newbuf)) throw std::runtime_error("putenv() failed"); // This assumes that the same NAME is passed on each call delete [] m_buf; m_buf = newbuf; } #define EBUFLEN 1024 static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) __attribute_format_printf(4, 5); // If either address or executable path is non-null then send and log // a warning email, or execute executable static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) { static const char * const whichfail[] = { "EmailTest", // 0 "Health", // 1 "Usage", // 2 "SelfTest", // 3 "ErrorCount", // 4 "FailedHealthCheck", // 5 "FailedReadSmartData", // 6 "FailedReadSmartErrorLog", // 7 "FailedReadSmartSelfTestLog", // 8 "FailedOpenDevice", // 9 "CurrentPendingSector", // 10 "OfflineUncorrectableSector", // 11 "Temperature" // 12 }; // See if user wants us to send mail if (cfg.emailaddress.empty() && cfg.emailcmdline.empty()) return; std::string address = cfg.emailaddress; const char * executable = cfg.emailcmdline.c_str(); // which type of mail are we sending? mailinfo * mail=(state.maillog)+which; // checks for sanity if (cfg.emailfreq<1 || cfg.emailfreq>3) { PrintOut(LOG_CRIT,"internal error in MailWarning(): cfg.mailwarn->emailfreq=%d\n",cfg.emailfreq); return; } if (which<0 || which>=SMARTD_NMAIL || sizeof(whichfail)!=SMARTD_NMAIL*sizeof(char *)) { PrintOut(LOG_CRIT,"Contact " PACKAGE_BUGREPORT "; internal error in MailWarning(): which=%d, size=%d\n", which, (int)sizeof(whichfail)); return; } // Return if a single warning mail has been sent. if ((cfg.emailfreq==1) && mail->logged) return; // Return if this is an email test and one has already been sent. if (which == 0 && mail->logged) return; // To decide if to send mail, we need to know what time it is. time_t epoch = time(0); // Return if less than one day has gone by const int day = 24*3600; if (cfg.emailfreq==2 && mail->logged && epoch<(mail->lastsent+day)) return; // Return if less than 2^(logged-1) days have gone by if (cfg.emailfreq==3 && mail->logged) { int days = 0x01 << (mail->logged - 1); days*=day; if (epoch<(mail->lastsent+days)) return; } #ifdef HAVE_LIBCAP_NG if (enable_capabilities) { PrintOut(LOG_ERR, "Sending a mail was supressed. " "Mails can't be send when capabilites are enabled\n"); return; } #endif // record the time of this mail message, and the first mail message if (!mail->logged) mail->firstsent=epoch; mail->lastsent=epoch; // print warning string into message char message[256]; va_list ap; va_start(ap, fmt); vsnprintf(message, sizeof(message), fmt, ap); va_end(ap); // replace commas by spaces to separate recipients std::replace(address.begin(), address.end(), ',', ' '); // Export information in environment variables that will be useful // for user scripts static env_buffer env[12]; env[0].set("SMARTD_MAILER", executable); env[1].set("SMARTD_MESSAGE", message); char dates[DATEANDEPOCHLEN]; snprintf(dates, sizeof(dates), "%d", mail->logged); env[2].set("SMARTD_PREVCNT", dates); dateandtimezoneepoch(dates, mail->firstsent); env[3].set("SMARTD_TFIRST", dates); snprintf(dates, DATEANDEPOCHLEN,"%d", (int)mail->firstsent); env[4].set("SMARTD_TFIRSTEPOCH", dates); env[5].set("SMARTD_FAILTYPE", whichfail[which]); env[6].set("SMARTD_ADDRESS", address.c_str()); env[7].set("SMARTD_DEVICESTRING", cfg.name.c_str()); // Allow 'smartctl ... -d $SMARTD_DEVICETYPE $SMARTD_DEVICE' env[8].set("SMARTD_DEVICETYPE", (!cfg.dev_type.empty() ? cfg.dev_type.c_str() : "auto")); env[9].set("SMARTD_DEVICE", cfg.dev_name.c_str()); env[10].set("SMARTD_DEVICEINFO", cfg.dev_idinfo.c_str()); dates[0] = 0; if (which) switch (cfg.emailfreq) { case 2: dates[0] = '1'; dates[1] = 0; break; case 3: snprintf(dates, sizeof(dates), "%d", (0x01)<<mail->logged); } env[11].set("SMARTD_NEXTDAYS", dates); // now construct a command to send this as EMAIL char command[2048]; if (!*executable) executable = "<mail>"; const char * newadd = (!address.empty()? address.c_str() : "<nomailer>"); const char * newwarn = (which? "Warning via" : "Test of"); #ifndef _WIN32 snprintf(command, sizeof(command), "%s 2>&1", warning_script.c_str()); // tell SYSLOG what we are about to do... PrintOut(LOG_INFO,"%s %s to %s ...\n", which?"Sending warning via":"Executing test of", executable, newadd); // issue the command to send mail or to run the user's executable errno=0; FILE * pfp; if (!(pfp=popen(command, "r"))) // failed to popen() mail process PrintOut(LOG_CRIT,"%s %s to %s: failed (fork or pipe failed, or no memory) %s\n", newwarn, executable, newadd, errno?strerror(errno):""); else { // pipe suceeded! int len, status; char buffer[EBUFLEN]; // if unexpected output on stdout/stderr, null terminate, print, and flush if ((len=fread(buffer, 1, EBUFLEN, pfp))) { int count=0; int newlen = len<EBUFLEN ? len : EBUFLEN-1; buffer[newlen]='\0'; PrintOut(LOG_CRIT,"%s %s to %s produced unexpected output (%s%d bytes) to STDOUT/STDERR: \n%s\n", newwarn, executable, newadd, len!=newlen?"here truncated to ":"", newlen, buffer); // flush pipe if needed while (fread(buffer, 1, EBUFLEN, pfp) && count<EBUFLEN) count++; // tell user that pipe was flushed, or that something is really wrong if (count && count<EBUFLEN) PrintOut(LOG_CRIT,"%s %s to %s: flushed remaining STDOUT/STDERR\n", newwarn, executable, newadd); else if (count) PrintOut(LOG_CRIT,"%s %s to %s: more than 1 MB STDOUT/STDERR flushed, breaking pipe\n", newwarn, executable, newadd); } // if something went wrong with mail process, print warning errno=0; if (-1==(status=pclose(pfp))) PrintOut(LOG_CRIT,"%s %s to %s: pclose(3) failed %s\n", newwarn, executable, newadd, errno?strerror(errno):""); else { // mail process apparently succeeded. Check and report exit status int status8; if (WIFEXITED(status)) { // exited 'normally' (but perhaps with nonzero status) status8=WEXITSTATUS(status); if (status8>128) PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d) perhaps caught signal %d [%s]\n", newwarn, executable, newadd, status, status8, status8-128, strsignal(status8-128)); else if (status8) PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d)\n", newwarn, executable, newadd, status, status8); else PrintOut(LOG_INFO,"%s %s to %s: successful\n", newwarn, executable, newadd); } if (WIFSIGNALED(status)) PrintOut(LOG_INFO,"%s %s to %s: exited because of uncaught signal %d [%s]\n", newwarn, executable, newadd, WTERMSIG(status), strsignal(WTERMSIG(status))); // this branch is probably not possible. If subprocess is // stopped then pclose() should not return. if (WIFSTOPPED(status)) PrintOut(LOG_CRIT,"%s %s to %s: process STOPPED because it caught signal %d [%s]\n", newwarn, executable, newadd, WSTOPSIG(status), strsignal(WSTOPSIG(status))); } } #else // _WIN32 { snprintf(command, sizeof(command), "cmd /c \"%s\"", warning_script.c_str()); char stdoutbuf[800]; // < buffer in syslog_win32::vsyslog() int rc; // run command PrintOut(LOG_INFO,"%s %s to %s ...\n", (which?"Sending warning via":"Executing test of"), executable, newadd); rc = daemon_spawn(command, "", 0, stdoutbuf, sizeof(stdoutbuf)); if (rc >= 0 && stdoutbuf[0]) PrintOut(LOG_CRIT,"%s %s to %s produced unexpected output (%d bytes) to STDOUT/STDERR:\n%s\n", newwarn, executable, newadd, (int)strlen(stdoutbuf), stdoutbuf); if (rc != 0) PrintOut(LOG_CRIT,"%s %s to %s: failed, exit status %d\n", newwarn, executable, newadd, rc); else PrintOut(LOG_INFO,"%s %s to %s: successful\n", newwarn, executable, newadd); } #endif // _WIN32 // increment mail sent counter mail->logged++; } static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) __attribute_format_printf(4, 5); static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...) { if (!(0 <= which && which < SMARTD_NMAIL)) return; // Return if no mail sent yet mailinfo & mi = state.maillog[which]; if (!mi.logged) return; // Format & print message char msg[256]; va_list ap; va_start(ap, fmt); vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); PrintOut(LOG_INFO, "Device: %s, %s, warning condition reset after %d email%s\n", cfg.name.c_str(), msg, mi.logged, (mi.logged==1 ? "" : "s")); // Clear mail counter and timestamps mi = mailinfo(); state.must_write = true; } #ifndef _WIN32 // Output multiple lines via separate syslog(3) calls. static void vsyslog_lines(int priority, const char * fmt, va_list ap) { char buf[512+EBUFLEN]; // enough space for exec cmd output in MailWarning() vsnprintf(buf, sizeof(buf), fmt, ap); for (char * p = buf, * q; p && *p; p = q) { if ((q = strchr(p, '\n'))) *q++ = 0; if (*p) syslog(priority, "%s\n", p); } } #else // _WIN32 // os_win32/syslog_win32.cpp supports multiple lines. #define vsyslog_lines vsyslog #endif // _WIN32 // Printing function for watching ataprint commands, or losing them // [From GLIBC Manual: Since the prototype doesn't specify types for // optional arguments, in a call to a variadic function the default // argument promotions are performed on the optional argument // values. This means the objects of type char or short int (whether // signed or not) are promoted to either int or unsigned int, as // appropriate.] void pout(const char *fmt, ...){ va_list ap; // get the correct time in syslog() FixGlibcTimeZoneBug(); // initialize variable argument list va_start(ap,fmt); // in debugmode==1 mode we will print the output from the ataprint.o functions! if (debugmode && debugmode != 2) { FILE * f = stdout; #ifdef _WIN32 if (facility == LOG_LOCAL1) // logging to stdout f = stderr; #endif vfprintf(f, fmt, ap); fflush(f); } // in debugmode==2 mode we print output from knowndrives.o functions else if (debugmode==2 || ata_debugmode || scsi_debugmode) { openlog("smartd", LOG_PID, facility); vsyslog_lines(LOG_INFO, fmt, ap); closelog(); } va_end(ap); return; } // This function prints either to stdout or to the syslog as needed. static void PrintOut(int priority, const char *fmt, ...){ va_list ap; // get the correct time in syslog() FixGlibcTimeZoneBug(); // initialize variable argument list va_start(ap,fmt); if (debugmode) { FILE * f = stdout; #ifdef _WIN32 if (facility == LOG_LOCAL1) // logging to stdout f = stderr; #endif vfprintf(f, fmt, ap); fflush(f); } else { openlog("smartd", LOG_PID, facility); vsyslog_lines(priority, fmt, ap); closelog(); } va_end(ap); return; } // Used to warn users about invalid checksums. Called from atacmds.cpp. void checksumwarning(const char * string) { pout("Warning! %s error: invalid SMART checksum.\n", string); } #ifndef _WIN32 // Wait for the pid file to show up, this makes sure a calling program knows // that the daemon is really up and running and has a pid to kill it static bool WaitForPidFile() { int waited, max_wait = 10; struct stat stat_buf; if (pid_file.empty() || debugmode) return true; for(waited = 0; waited < max_wait; ++waited) { if (!stat(pid_file.c_str(), &stat_buf)) { return true; } else sleep(1); } return false; } #endif // _WIN32 // Forks new process, closes ALL file descriptors, redirects stdin, // stdout, and stderr. Not quite daemon(). See // http://www.linuxjournal.com/article/2335 // for a good description of why we do things this way. static void DaemonInit() { #ifndef _WIN32 pid_t pid; int i; // flush all buffered streams. Else we might get two copies of open // streams since both parent and child get copies of the buffers. fflush(NULL); if (do_fork) { if ((pid=fork()) < 0) { // unable to fork! PrintOut(LOG_CRIT,"smartd unable to fork daemon process!\n"); EXIT(EXIT_STARTUP); } else if (pid) { // we are the parent process, wait for pid file, then exit cleanly if(!WaitForPidFile()) { PrintOut(LOG_CRIT,"PID file %s didn't show up!\n", pid_file.c_str()); EXIT(EXIT_STARTUP); } else EXIT(0); } // from here on, we are the child process. setsid(); // Fork one more time to avoid any possibility of having terminals if ((pid=fork()) < 0) { // unable to fork! PrintOut(LOG_CRIT,"smartd unable to fork daemon process!\n"); EXIT(EXIT_STARTUP); } else if (pid) // we are the parent process -- exit cleanly EXIT(0); // Now we are the child's child... } // close any open file descriptors for (i=getdtablesize();i>=0;--i) close(i); #define NO_warn_unused_result(cmd) { if (cmd) {} ; } // redirect any IO attempts to /dev/null for stdin i=open("/dev/null",O_RDWR); if (i>=0) { // stdout NO_warn_unused_result(dup(i)); // stderr NO_warn_unused_result(dup(i)); }; umask(0022); NO_warn_unused_result(chdir("/")); if (do_fork) PrintOut(LOG_INFO, "smartd has fork()ed into background mode. New PID=%d.\n", (int)getpid()); #else // _WIN32 // No fork() on native Win32 // Detach this process from console fflush(NULL); if (daemon_detach("smartd")) { PrintOut(LOG_CRIT,"smartd unable to detach from console!\n"); EXIT(EXIT_STARTUP); } // stdin/out/err now closed if not redirected #endif // _WIN32 return; } // create a PID file containing the current process id static void WritePidFile() { if (!pid_file.empty()) { pid_t pid = getpid(); mode_t old_umask; #ifndef __CYGWIN__ old_umask = umask(0077); // rwx------ #else // Cygwin: smartd service runs on system account, ensure PID file can be read by admins old_umask = umask(0033); // rwxr--r-- #endif stdio_file f(pid_file.c_str(), "w"); umask(old_umask); if (!(f && fprintf(f, "%d\n", (int)pid) > 0 && f.close())) { PrintOut(LOG_CRIT, "unable to write PID file %s - exiting.\n", pid_file.c_str()); EXIT(EXIT_PID); } PrintOut(LOG_INFO, "file %s written containing PID %d\n", pid_file.c_str(), (int)pid); } } // Prints header identifying version of code and home static void PrintHead() { PrintOut(LOG_INFO, "%s\n", format_version_info("smartd").c_str()); } // prints help info for configuration file Directives static void Directives() { PrintOut(LOG_INFO, "Configuration file (%s) Directives (after device name):\n" " -d TYPE Set the device type: auto, ignore, removable,\n" " %s\n" " -T TYPE Set the tolerance to one of: normal, permissive\n" " -o VAL Enable/disable automatic offline tests (on/off)\n" " -S VAL Enable/disable attribute autosave (on/off)\n" " -n MODE No check if: never, sleep[,N][,q], standby[,N][,q], idle[,N][,q]\n" " -H Monitor SMART Health Status, report if failed\n" " -s REG Do Self-Test at time(s) given by regular expression REG\n" " -l TYPE Monitor SMART log or self-test status:\n" " error, selftest, xerror, offlinests[,ns], selfteststs[,ns]\n" " -l scterc,R,W Set SCT Error Recovery Control\n" " -e Change device setting: aam,[N|off], apm,[N|off], lookahead,[on|off],\n" " security-freeze, standby,[N|off], wcache,[on|off]\n" " -f Monitor 'Usage' Attributes, report failures\n" " -m ADD Send email warning to address ADD\n" " -M TYPE Modify email warning behavior (see man page)\n" " -p Report changes in 'Prefailure' Attributes\n" " -u Report changes in 'Usage' Attributes\n" " -t Equivalent to -p and -u Directives\n" " -r ID Also report Raw values of Attribute ID with -p, -u or -t\n" " -R ID Track changes in Attribute ID Raw value with -p, -u or -t\n" " -i ID Ignore Attribute ID for -f Directive\n" " -I ID Ignore Attribute ID for -p, -u or -t Directive\n" " -C ID[+] Monitor [increases of] Current Pending Sectors in Attribute ID\n" " -U ID[+] Monitor [increases of] Offline Uncorrectable Sectors in Attribute ID\n" " -W D,I,C Monitor Temperature D)ifference, I)nformal limit, C)ritical limit\n" " -v N,ST Modifies labeling of Attribute N (see man page) \n" " -P TYPE Drive-specific presets: use, ignore, show, showall\n" " -a Default: -H -f -t -l error -l selftest -l selfteststs -C 197 -U 198\n" " -F TYPE Use firmware bug workaround:\n" " %s\n" " # Comment: text after a hash sign is ignored\n" " \\ Line continuation character\n" "Attribute ID is a decimal integer 1 <= ID <= 255\n" "Use ID = 0 to turn off -C and/or -U Directives\n" "Example: /dev/sda -a\n", configfile, smi()->get_valid_dev_types_str().c_str(), get_valid_firmwarebug_args()); } /* Returns a pointer to a static string containing a formatted list of the valid arguments to the option opt or NULL on failure. */ static const char *GetValidArgList(char opt) { switch (opt) { case 'A': case 's': return "<PATH_PREFIX>"; case 'c': return "<FILE_NAME>, -"; case 'l': return "daemon, local0, local1, local2, local3, local4, local5, local6, local7"; case 'q': return "nodev, errors, nodevstartup, never, onecheck, showtests"; case 'r': return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; case 'B': case 'p': case 'w': return "<FILE_NAME>"; case 'i': return "<INTEGER_SECONDS>"; default: return NULL; } } /* prints help information for command syntax */ static void Usage() { PrintOut(LOG_INFO,"Usage: smartd [options]\n\n"); PrintOut(LOG_INFO," -A PREFIX, --attributelog=PREFIX\n"); PrintOut(LOG_INFO," Log ATA attribute information to {PREFIX}MODEL-SERIAL.ata.csv\n"); #ifdef SMARTMONTOOLS_ATTRIBUTELOG PrintOut(LOG_INFO," [default is "SMARTMONTOOLS_ATTRIBUTELOG"MODEL-SERIAL.ata.csv]\n"); #endif PrintOut(LOG_INFO,"\n"); PrintOut(LOG_INFO," -B [+]FILE, --drivedb=[+]FILE\n"); PrintOut(LOG_INFO," Read and replace [add] drive database from FILE\n"); PrintOut(LOG_INFO," [default is +%s", get_drivedb_path_add()); #ifdef SMARTMONTOOLS_DRIVEDBDIR PrintOut(LOG_INFO,"\n"); PrintOut(LOG_INFO," and then %s", get_drivedb_path_default()); #endif PrintOut(LOG_INFO,"]\n\n"); PrintOut(LOG_INFO," -c NAME|-, --configfile=NAME|-\n"); PrintOut(LOG_INFO," Read configuration file NAME or stdin\n"); PrintOut(LOG_INFO," [default is %s]\n\n", configfile); #ifdef HAVE_LIBCAP_NG PrintOut(LOG_INFO," -C, --capabilities\n"); PrintOut(LOG_INFO," Use capabilities.\n" " Warning: Mail notification does not work when used.\n\n"); #endif PrintOut(LOG_INFO," -d, --debug\n"); PrintOut(LOG_INFO," Start smartd in debug mode\n\n"); PrintOut(LOG_INFO," -D, --showdirectives\n"); PrintOut(LOG_INFO," Print the configuration file Directives and exit\n\n"); PrintOut(LOG_INFO," -h, --help, --usage\n"); PrintOut(LOG_INFO," Display this help and exit\n\n"); PrintOut(LOG_INFO," -i N, --interval=N\n"); PrintOut(LOG_INFO," Set interval between disk checks to N seconds, where N >= 10\n\n"); PrintOut(LOG_INFO," -l local[0-7], --logfacility=local[0-7]\n"); #ifndef _WIN32 PrintOut(LOG_INFO," Use syslog facility local0 - local7 or daemon [default]\n\n"); #else PrintOut(LOG_INFO," Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n"); #endif #ifndef _WIN32 PrintOut(LOG_INFO," -n, --no-fork\n"); PrintOut(LOG_INFO," Do not fork into background\n\n"); #endif // _WIN32 PrintOut(LOG_INFO," -p NAME, --pidfile=NAME\n"); PrintOut(LOG_INFO," Write PID file NAME\n\n"); PrintOut(LOG_INFO," -q WHEN, --quit=WHEN\n"); PrintOut(LOG_INFO," Quit on one of: %s\n\n", GetValidArgList('q')); PrintOut(LOG_INFO," -r, --report=TYPE\n"); PrintOut(LOG_INFO," Report transactions for one of: %s\n\n", GetValidArgList('r')); PrintOut(LOG_INFO," -s PREFIX, --savestates=PREFIX\n"); PrintOut(LOG_INFO," Save disk states to {PREFIX}MODEL-SERIAL.TYPE.state\n"); #ifdef SMARTMONTOOLS_SAVESTATES PrintOut(LOG_INFO," [default is "SMARTMONTOOLS_SAVESTATES"MODEL-SERIAL.TYPE.state]\n"); #endif PrintOut(LOG_INFO,"\n"); PrintOut(LOG_INFO," -w NAME, --warnexec=NAME\n"); PrintOut(LOG_INFO," Run executable NAME on warnings\n"); #ifndef _WIN32 PrintOut(LOG_INFO," [default is "SMARTMONTOOLS_SYSCONFDIR"/smartd_warning.sh]\n\n"); #else PrintOut(LOG_INFO," [default is %s/smartd_warning.cmd]\n\n", get_exe_dir().c_str()); #endif #ifdef _WIN32 PrintOut(LOG_INFO," --service\n"); PrintOut(LOG_INFO," Running as windows service (see man page), install with:\n"); PrintOut(LOG_INFO," smartd install [options]\n"); PrintOut(LOG_INFO," Remove service with:\n"); PrintOut(LOG_INFO," smartd remove\n\n"); #endif // _WIN32 PrintOut(LOG_INFO," -V, --version, --license, --copyright\n"); PrintOut(LOG_INFO," Print License, Copyright, and version information\n"); } static int CloseDevice(smart_device * device, const char * name) { if (!device->close()){ PrintOut(LOG_INFO,"Device: %s, %s, close() failed\n", name, device->get_errmsg()); return 1; } // device sucessfully closed return 0; } // return true if a char is not allowed in a state file name static bool not_allowed_in_filename(char c) { return !( ('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')); } // Read error count from Summary or Extended Comprehensive SMART error log // Return -1 on error static int read_ata_error_count(ata_device * device, const char * name, firmwarebug_defs firmwarebugs, bool extended) { if (!extended) { ata_smart_errorlog log; if (ataReadErrorLog(device, &log, firmwarebugs)){ PrintOut(LOG_INFO,"Device: %s, Read Summary SMART Error Log failed\n",name); return -1; } return (log.error_log_pointer ? log.ata_error_count : 0); } else { ata_smart_exterrlog logx; if (!ataReadExtErrorLog(device, &logx, 1 /*first sector only*/, firmwarebugs)) { PrintOut(LOG_INFO,"Device: %s, Read Extended Comprehensive SMART Error Log failed\n",name); return -1; } // Some disks use the reserved byte as index, see ataprint.cpp. return (logx.error_log_index || logx.reserved1 ? logx.device_error_count : 0); } } // returns <0 if problem. Otherwise, bottom 8 bits are the self test // error count, and top bits are the power-on hours of the last error. static int SelfTestErrorCount(ata_device * device, const char * name, firmwarebug_defs firmwarebugs) { struct ata_smart_selftestlog log; if (ataReadSelfTestLog(device, &log, firmwarebugs)){ PrintOut(LOG_INFO,"Device: %s, Read SMART Self Test Log Failed\n",name); return -1; } // return current number of self-test errors return ataPrintSmartSelfTestlog(&log, false, firmwarebugs); } #define SELFTEST_ERRORCOUNT(x) (x & 0xff) #define SELFTEST_ERRORHOURS(x) ((x >> 8) & 0xffff) // Check offline data collection status static inline bool is_offl_coll_in_progress(unsigned char status) { return ((status & 0x7f) == 0x03); } // Check self-test execution status static inline bool is_self_test_in_progress(unsigned char status) { return ((status >> 4) == 0xf); } // Log offline data collection status static void log_offline_data_coll_status(const char * name, unsigned char status) { const char * msg; switch (status & 0x7f) { case 0x00: msg = "was never started"; break; case 0x02: msg = "was completed without error"; break; case 0x03: msg = "is in progress"; break; case 0x04: msg = "was suspended by an interrupting command from host"; break; case 0x05: msg = "was aborted by an interrupting command from host"; break; case 0x06: msg = "was aborted by the device with a fatal error"; break; default: msg = 0; } if (msg) PrintOut(((status & 0x7f) == 0x06 ? LOG_CRIT : LOG_INFO), "Device: %s, offline data collection %s%s\n", name, msg, ((status & 0x80) ? " (auto:on)" : "")); else PrintOut(LOG_INFO, "Device: %s, unknown offline data collection status 0x%02x\n", name, status); } // Log self-test execution status static void log_self_test_exec_status(const char * name, unsigned char status) { const char * msg; switch (status >> 4) { case 0x0: msg = "completed without error"; break; case 0x1: msg = "was aborted by the host"; break; case 0x2: msg = "was interrupted by the host with a reset"; break; case 0x3: msg = "could not complete due to a fatal or unknown error"; break; case 0x4: msg = "completed with error (unknown test element)"; break; case 0x5: msg = "completed with error (electrical test element)"; break; case 0x6: msg = "completed with error (servo/seek test element)"; break; case 0x7: msg = "completed with error (read test element)"; break; case 0x8: msg = "completed with error (handling damage?)"; break; default: msg = 0; } if (msg) PrintOut(((status >> 4) >= 0x4 ? LOG_CRIT : LOG_INFO), "Device: %s, previous self-test %s\n", name, msg); else if ((status >> 4) == 0xf) PrintOut(LOG_INFO, "Device: %s, self-test in progress, %u0%% remaining\n", name, status & 0x0f); else PrintOut(LOG_INFO, "Device: %s, unknown self-test status 0x%02x\n", name, status); } // Check pending sector count id (-C, -U directives). static bool check_pending_id(const dev_config & cfg, const dev_state & state, unsigned char id, const char * msg) { // Check attribute index int i = ata_find_attr_index(id, state.smartval); if (i < 0) { PrintOut(LOG_INFO, "Device: %s, can't monitor %s count - no Attribute %d\n", cfg.name.c_str(), msg, id); return false; } // Check value uint64_t rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs); if (rawval >= (state.num_sectors ? state.num_sectors : 0xffffffffULL)) { PrintOut(LOG_INFO, "Device: %s, ignoring %s count - bogus Attribute %d value %"PRIu64" (0x%"PRIx64")\n", cfg.name.c_str(), msg, id, rawval, rawval); return false; } return true; } // Called by ATA/SCSIDeviceScan() after successful device check static void finish_device_scan(dev_config & cfg, dev_state & state) { // Set cfg.emailfreq if user hasn't set it if ((!cfg.emailaddress.empty() || !cfg.emailcmdline.empty()) && !cfg.emailfreq) { // Avoid that emails are suppressed forever due to state persistence if (cfg.state_file.empty()) cfg.emailfreq = 1; // '-M once' else cfg.emailfreq = 2; // '-M daily' } // Start self-test regex check now if time was not read from state file if (!cfg.test_regex.empty() && !state.scheduled_test_next_check) state.scheduled_test_next_check = time(0); } // Common function to format result message for ATA setting static void format_set_result_msg(std::string & msg, const char * name, bool ok, int set_option = 0, bool has_value = false) { if (!msg.empty()) msg += ", "; msg += name; if (!ok) msg += ":--"; else if (set_option < 0) msg += ":off"; else if (has_value) msg += strprintf(":%d", set_option-1); else if (set_option > 0) msg += ":on"; } // TODO: Add '-F swapid' directive const bool fix_swapped_id = false; // scan to see what ata devices there are, and if they support SMART static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atadev) { int supported=0; struct ata_identify_device drive; const char *name = cfg.name.c_str(); int retid; // Device must be open // Get drive identity structure if ((retid = ata_read_identity(atadev, &drive, fix_swapped_id))) { if (retid<0) // Unable to read Identity structure PrintOut(LOG_INFO,"Device: %s, not ATA, no IDENTIFY DEVICE Structure\n",name); else PrintOut(LOG_INFO,"Device: %s, packet devices [this device %s] not SMART capable\n", name, packetdevicetype(retid-1)); CloseDevice(atadev, name); return 2; } // Get drive identity, size and rotation rate (HDD/SSD) char model[40+1], serial[20+1], firmware[8+1]; ata_format_id_string(model, drive.model, sizeof(model)-1); ata_format_id_string(serial, drive.serial_no, sizeof(serial)-1); ata_format_id_string(firmware, drive.fw_rev, sizeof(firmware)-1); ata_size_info sizes; ata_get_size_info(&drive, sizes); state.num_sectors = sizes.sectors; cfg.dev_rpm = ata_get_rotation_rate(&drive); char wwn[30]; wwn[0] = 0; unsigned oui = 0; uint64_t unique_id = 0; int naa = ata_get_wwn(&drive, oui, unique_id); if (naa >= 0) snprintf(wwn, sizeof(wwn), "WWN:%x-%06x-%09"PRIx64", ", naa, oui, unique_id); // Format device id string for warning emails char cap[32]; cfg.dev_idinfo = strprintf("%s, S/N:%s, %sFW:%s, %s", model, serial, wwn, firmware, format_capacity(cap, sizeof(cap), sizes.capacity, ".")); PrintOut(LOG_INFO, "Device: %s, %s\n", name, cfg.dev_idinfo.c_str()); // Show if device in database, and use preset vendor attribute // options unless user has requested otherwise. if (cfg.ignorepresets) PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name); else { // Apply vendor specific presets, print warning if present const drive_settings * dbentry = lookup_drive_apply_presets( &drive, cfg.attribute_defs, cfg.firmwarebugs); if (!dbentry) PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name); else { PrintOut(LOG_INFO, "Device: %s, found in smartd database%s%s\n", name, (*dbentry->modelfamily ? ": " : "."), (*dbentry->modelfamily ? dbentry->modelfamily : "")); if (*dbentry->warningmsg) PrintOut(LOG_CRIT, "Device: %s, WARNING: %s\n", name, dbentry->warningmsg); } } // Set default '-C 197[+]' if no '-C ID' is specified. if (!cfg.curr_pending_set) cfg.curr_pending_id = get_unc_attr_id(false, cfg.attribute_defs, cfg.curr_pending_incr); // Set default '-U 198[+]' if no '-U ID' is specified. if (!cfg.offl_pending_set) cfg.offl_pending_id = get_unc_attr_id(true, cfg.attribute_defs, cfg.offl_pending_incr); // If requested, show which presets would be used for this drive if (cfg.showpresets) { int savedebugmode=debugmode; PrintOut(LOG_INFO, "Device %s: presets are:\n", name); if (!debugmode) debugmode=2; show_presets(&drive); debugmode=savedebugmode; } // see if drive supports SMART supported=ataSmartSupport(&drive); if (supported!=1) { if (supported==0) // drive does NOT support SMART PrintOut(LOG_INFO,"Device: %s, lacks SMART capability\n",name); else // can't tell if drive supports SMART PrintOut(LOG_INFO,"Device: %s, ATA IDENTIFY DEVICE words 82-83 don't specify if SMART capable.\n",name); // should we proceed anyway? if (cfg.permissive) { PrintOut(LOG_INFO,"Device: %s, proceeding since '-T permissive' Directive given.\n",name); } else { PrintOut(LOG_INFO,"Device: %s, to proceed anyway, use '-T permissive' Directive.\n",name); CloseDevice(atadev, name); return 2; } } if (ataEnableSmart(atadev)) { // Enable SMART command has failed PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); CloseDevice(atadev, name); return 2; } // disable device attribute autosave... if (cfg.autosave==1) { if (ataDisableAutoSave(atadev)) PrintOut(LOG_INFO,"Device: %s, could not disable SMART Attribute Autosave.\n",name); else PrintOut(LOG_INFO,"Device: %s, disabled SMART Attribute Autosave.\n",name); } // or enable device attribute autosave if (cfg.autosave==2) { if (ataEnableAutoSave(atadev)) PrintOut(LOG_INFO,"Device: %s, could not enable SMART Attribute Autosave.\n",name); else PrintOut(LOG_INFO,"Device: %s, enabled SMART Attribute Autosave.\n",name); } // capability check: SMART status if (cfg.smartcheck && ataSmartStatus2(atadev) == -1) { PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name); cfg.smartcheck = false; } // capability check: Read smart values and thresholds. Note that // smart values are ALSO needed even if we ONLY want to know if the // device is self-test log or error-log capable! After ATA-5, this // information was ALSO reproduced in the IDENTIFY DEVICE response, // but sadly not for ATA-5. Sigh. // do we need to get SMART data? bool smart_val_ok = false; if ( cfg.autoofflinetest || cfg.selftest || cfg.errorlog || cfg.xerrorlog || cfg.offlinests || cfg.selfteststs || cfg.usagefailed || cfg.prefail || cfg.usage || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit || cfg.curr_pending_id || cfg.offl_pending_id ) { if (ataReadSmartValues(atadev, &state.smartval)) { PrintOut(LOG_INFO, "Device: %s, Read SMART Values failed\n", name); cfg.usagefailed = cfg.prefail = cfg.usage = false; cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0; cfg.curr_pending_id = cfg.offl_pending_id = 0; } else { smart_val_ok = true; if (ataReadSmartThresholds(atadev, &state.smartthres)) { PrintOut(LOG_INFO, "Device: %s, Read SMART Thresholds failed%s\n", name, (cfg.usagefailed ? ", ignoring -f Directive" : "")); cfg.usagefailed = false; // Let ata_get_attr_state() return ATTRSTATE_NO_THRESHOLD: memset(&state.smartthres, 0, sizeof(state.smartthres)); } } // see if the necessary Attribute is there to monitor offline or // current pending sectors or temperature if ( cfg.curr_pending_id && !check_pending_id(cfg, state, cfg.curr_pending_id, "Current_Pending_Sector")) cfg.curr_pending_id = 0; if ( cfg.offl_pending_id && !check_pending_id(cfg, state, cfg.offl_pending_id, "Offline_Uncorrectable")) cfg.offl_pending_id = 0; if ( (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) && !ata_return_temperature_value(&state.smartval, cfg.attribute_defs)) { PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n", name, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit); cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0; } // Report ignored '-r' or '-R' directives for (int id = 1; id <= 255; id++) { if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) { char opt = (!cfg.monitor_attr_flags.is_set(id, MONITOR_RAW) ? 'r' : 'R'); const char * excl = (cfg.monitor_attr_flags.is_set(id, (opt == 'r' ? MONITOR_AS_CRIT : MONITOR_RAW_AS_CRIT)) ? "!" : ""); int idx = ata_find_attr_index(id, state.smartval); if (idx < 0) PrintOut(LOG_INFO,"Device: %s, no Attribute %d, ignoring -%c %d%s\n", name, id, opt, id, excl); else { bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(state.smartval.vendor_attributes[idx].flags); if (!((prefail && cfg.prefail) || (!prefail && cfg.usage))) PrintOut(LOG_INFO,"Device: %s, not monitoring %s Attributes, ignoring -%c %d%s\n", name, (prefail ? "Prefailure" : "Usage"), opt, id, excl); } } } } // enable/disable automatic on-line testing if (cfg.autoofflinetest) { // is this an enable or disable request? const char *what=(cfg.autoofflinetest==1)?"disable":"enable"; if (!smart_val_ok) PrintOut(LOG_INFO,"Device: %s, could not %s SMART Automatic Offline Testing.\n",name, what); else { // if command appears unsupported, issue a warning... if (!isSupportAutomaticTimer(&state.smartval)) PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name); // ... but then try anyway if ((cfg.autoofflinetest==1)?ataDisableAutoOffline(atadev):ataEnableAutoOffline(atadev)) PrintOut(LOG_INFO,"Device: %s, %s SMART Automatic Offline Testing failed.\n", name, what); else PrintOut(LOG_INFO,"Device: %s, %sd SMART Automatic Offline Testing.\n", name, what); } } // Read log directories if required for capability check ata_smart_log_directory smart_logdir, gp_logdir; bool smart_logdir_ok = false, gp_logdir_ok = false; if ( isGeneralPurposeLoggingCapable(&drive) && (cfg.errorlog || cfg.selftest) && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) { if (!ataReadLogDirectory(atadev, &smart_logdir, false)) smart_logdir_ok = true; } if (cfg.xerrorlog && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) { if (!ataReadLogDirectory(atadev, &gp_logdir, true)) gp_logdir_ok = true; } // capability check: self-test-log state.selflogcount = 0; state.selfloghour = 0; if (cfg.selftest) { int retval; if (!( cfg.permissive || ( smart_logdir_ok && smart_logdir.entry[0x06-1].numsectors) || (!smart_logdir_ok && smart_val_ok && isSmartTestLogCapable(&state.smartval, &drive)))) { PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest (override with -T permissive)\n", name); cfg.selftest = false; } else if ((retval = SelfTestErrorCount(atadev, name, cfg.firmwarebugs)) < 0) { PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest\n", name); cfg.selftest = false; } else { state.selflogcount=SELFTEST_ERRORCOUNT(retval); state.selfloghour =SELFTEST_ERRORHOURS(retval); } } // capability check: ATA error log state.ataerrorcount = 0; if (cfg.errorlog) { int errcnt1; if (!( cfg.permissive || ( smart_logdir_ok && smart_logdir.entry[0x01-1].numsectors) || (!smart_logdir_ok && smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) { PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error (override with -T permissive)\n", name); cfg.errorlog = false; } else if ((errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false)) < 0) { PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error\n", name); cfg.errorlog = false; } else state.ataerrorcount = errcnt1; } if (cfg.xerrorlog) { int errcnt2; if (!( cfg.permissive || cfg.firmwarebugs.is_set(BUG_NOLOGDIR) || (gp_logdir_ok && gp_logdir.entry[0x03-1].numsectors) )) { PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror (override with -T permissive)\n", name); cfg.xerrorlog = false; } else if ((errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true)) < 0) { PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name); cfg.xerrorlog = false; } else if (cfg.errorlog && state.ataerrorcount != errcnt2) { PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n", name, state.ataerrorcount, errcnt2); // Record max error count if (errcnt2 > state.ataerrorcount) state.ataerrorcount = errcnt2; } else state.ataerrorcount = errcnt2; } // capability check: self-test and offline data collection status if (cfg.offlinests || cfg.selfteststs) { if (!(cfg.permissive || (smart_val_ok && state.smartval.offline_data_collection_capability))) { if (cfg.offlinests) PrintOut(LOG_INFO, "Device: %s, no SMART Offline Data Collection capability, ignoring -l offlinests (override with -T permissive)\n", name); if (cfg.selfteststs) PrintOut(LOG_INFO, "Device: %s, no SMART Self-test capability, ignoring -l selfteststs (override with -T permissive)\n", name); cfg.offlinests = cfg.selfteststs = false; } } // capabilities check -- does it support powermode? if (cfg.powermode) { int powermode = ataCheckPowerMode(atadev); if (-1 == powermode) { PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name); cfg.powermode=0; } else if (powermode!=0 && powermode!=0x80 && powermode!=0xff) { PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n", name, powermode); cfg.powermode=0; } } // Apply ATA settings std::string msg; if (cfg.set_aam) format_set_result_msg(msg, "AAM", (cfg.set_aam > 0 ? ata_set_features(atadev, ATA_ENABLE_AAM, cfg.set_aam-1) : ata_set_features(atadev, ATA_DISABLE_AAM)), cfg.set_aam, true); if (cfg.set_apm) format_set_result_msg(msg, "APM", (cfg.set_apm > 0 ? ata_set_features(atadev, ATA_ENABLE_APM, cfg.set_apm-1) : ata_set_features(atadev, ATA_DISABLE_APM)), cfg.set_apm, true); if (cfg.set_lookahead) format_set_result_msg(msg, "Rd-ahead", ata_set_features(atadev, (cfg.set_lookahead > 0 ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD)), cfg.set_lookahead); if (cfg.set_wcache) format_set_result_msg(msg, "Wr-cache", ata_set_features(atadev, (cfg.set_wcache > 0? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE)), cfg.set_wcache); if (cfg.set_security_freeze) format_set_result_msg(msg, "Security freeze", ata_nodata_command(atadev, ATA_SECURITY_FREEZE_LOCK)); if (cfg.set_standby) format_set_result_msg(msg, "Standby", ata_nodata_command(atadev, ATA_IDLE, cfg.set_standby-1), cfg.set_standby, true); // Report as one log entry if (!msg.empty()) PrintOut(LOG_INFO, "Device: %s, ATA settings applied: %s\n", name, msg.c_str()); // set SCT Error Recovery Control if requested if (cfg.sct_erc_set) { if (!isSCTErrorRecoveryControlCapable(&drive)) PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n", name); else if ( ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime ) || ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime)) PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name); else PrintOut(LOG_INFO, "Device: %s, SCT Error Recovery Control set to: Read: %u, Write: %u\n", name, cfg.sct_erc_readtime, cfg.sct_erc_writetime); } // If no tests available or selected, return if (!( cfg.smartcheck || cfg.selftest || cfg.errorlog || cfg.xerrorlog || cfg.offlinests || cfg.selfteststs || cfg.usagefailed || cfg.prefail || cfg.usage || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) { CloseDevice(atadev, name); return 3; } // tell user we are registering device PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name); // close file descriptor CloseDevice(atadev, name); if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) { // Build file name for state file std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_'); std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_'); if (!state_path_prefix.empty()) { cfg.state_file = strprintf("%s%s-%s.ata.state", state_path_prefix.c_str(), model, serial); // Read previous state if (read_dev_state(cfg.state_file.c_str(), state)) { PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str()); // Copy ATA attribute values to temp state state.update_temp_state(); } } if (!attrlog_path_prefix.empty()) cfg.attrlog_file = strprintf("%s%s-%s.ata.csv", attrlog_path_prefix.c_str(), model, serial); } finish_device_scan(cfg, state); return 0; } // on success, return 0. On failure, return >0. Never return <0, // please. static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scsidev) { int k, err, req_len, avail_len, version, len; const char *device = cfg.name.c_str(); struct scsi_iec_mode_page iec; UINT8 tBuf[64]; UINT8 inqBuf[96]; UINT8 vpdBuf[252]; char lu_id[64], serial[256], vendor[40], model[40]; // Device must be open memset(inqBuf, 0, 96); req_len = 36; if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) { /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */ req_len = 64; if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) { PrintOut(LOG_INFO, "Device: %s, Both 36 and 64 byte INQUIRY failed; " "skip device\n", device); return 2; } } version = (inqBuf[2] & 0x7f); /* Accept old ISO/IEC 9316:1995 variants */ avail_len = inqBuf[4] + 5; len = (avail_len < req_len) ? avail_len : req_len; if (len < 36) { PrintOut(LOG_INFO, "Device: %s, INQUIRY response less than 36 bytes; " "skip device\n", device); return 2; } int pdt = inqBuf[0] & 0x1f; if (! ((0 == pdt) || (4 == pdt) || (5 == pdt) || (7 == pdt) || (0xe == pdt))) { PrintOut(LOG_INFO, "Device: %s, not a disk like device [PDT=0x%x], " "skip\n", device, pdt); return 2; } if (supported_vpd_pages_p) { delete supported_vpd_pages_p; supported_vpd_pages_p = NULL; } supported_vpd_pages_p = new supported_vpd_pages(scsidev); lu_id[0] = '\0'; if ((version >= 0x3) && (version < 0x8)) { /* SPC to SPC-5 */ if (0 == scsiInquiryVpd(scsidev, SCSI_VPD_DEVICE_IDENTIFICATION, vpdBuf, sizeof(vpdBuf))) { len = vpdBuf[3]; scsi_decode_lu_dev_id(vpdBuf + 4, len, lu_id, sizeof(lu_id), NULL); } } serial[0] = '\0'; if (0 == scsiInquiryVpd(scsidev, SCSI_VPD_UNIT_SERIAL_NUMBER, vpdBuf, sizeof(vpdBuf))) { len = vpdBuf[3]; vpdBuf[4 + len] = '\0'; scsi_format_id_string(serial, (const unsigned char *)&vpdBuf[4], len); } unsigned int lb_size; char si_str[64]; uint64_t capacity = scsiGetSize(scsidev, &lb_size, NULL); if (capacity) format_capacity(si_str, sizeof(si_str), capacity); else si_str[0] = '\0'; // Format device id string for warning emails cfg.dev_idinfo = strprintf("[%.8s %.16s %.4s]%s%s%s%s%s%s", (char *)&inqBuf[8], (char *)&inqBuf[16], (char *)&inqBuf[32], (lu_id[0] ? ", lu id: " : ""), (lu_id[0] ? lu_id : ""), (serial[0] ? ", S/N: " : ""), (serial[0] ? serial : ""), (si_str[0] ? ", " : ""), (si_str[0] ? si_str : "")); // format "model" string scsi_format_id_string(vendor, (const unsigned char *)&inqBuf[8], 8); scsi_format_id_string(model, (const unsigned char *)&inqBuf[16], 16); PrintOut(LOG_INFO, "Device: %s, %s\n", device, cfg.dev_idinfo.c_str()); // check that device is ready for commands. IE stores its stuff on // the media. if ((err = scsiTestUnitReady(scsidev))) { if (SIMPLE_ERR_NOT_READY == err) PrintOut(LOG_INFO, "Device: %s, NOT READY (e.g. spun down); skip device\n", device); else if (SIMPLE_ERR_NO_MEDIUM == err) PrintOut(LOG_INFO, "Device: %s, NO MEDIUM present; skip device\n", device); else if (SIMPLE_ERR_BECOMING_READY == err) PrintOut(LOG_INFO, "Device: %s, BECOMING (but not yet) READY; skip device\n", device); else PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err); CloseDevice(scsidev, device); return 2; } // Badly-conforming USB storage devices may fail this check. // The response to the following IE mode page fetch (current and // changeable values) is carefully examined. It has been found // that various USB devices that malform the response will lock up // if asked for a log page (e.g. temperature) so it is best to // bail out now. if (!(err = scsiFetchIECmpage(scsidev, &iec, state.modese_len))) state.modese_len = iec.modese_len; else if (SIMPLE_ERR_BAD_FIELD == err) ; /* continue since it is reasonable not to support IE mpage */ else { /* any other error (including malformed response) unreasonable */ PrintOut(LOG_INFO, "Device: %s, Bad IEC (SMART) mode page, err=%d, skip device\n", device, err); CloseDevice(scsidev, device); return 3; } // N.B. The following is passive (i.e. it doesn't attempt to turn on // smart if it is off). This may change to be the same as the ATA side. if (!scsi_IsExceptionControlEnabled(&iec)) { PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n" "Try 'smartctl -s on %s' to turn on SMART features\n", device, device); CloseDevice(scsidev, device); return 3; } // Flag that certain log pages are supported (information may be // available from other sources). if (0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0)) { for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { switch (tBuf[k]) { case TEMPERATURE_LPAGE: state.TempPageSupported = 1; break; case IE_LPAGE: state.SmartPageSupported = 1; break; case READ_ERROR_COUNTER_LPAGE: state.ReadECounterPageSupported = 1; break; case WRITE_ERROR_COUNTER_LPAGE: state.WriteECounterPageSupported = 1; break; case VERIFY_ERROR_COUNTER_LPAGE: state.VerifyECounterPageSupported = 1; break; case NON_MEDIUM_ERROR_LPAGE: state.NonMediumErrorPageSupported = 1; break; default: break; } } } // Check if scsiCheckIE() is going to work { UINT8 asc = 0; UINT8 ascq = 0; UINT8 currenttemp = 0; UINT8 triptemp = 0; if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported, &asc, &ascq, ¤ttemp, &triptemp)) { PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device); state.SuppressReport = 1; if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) { PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n", device, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit); cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0; } } } // capability check: self-test-log if (cfg.selftest){ int retval = scsiCountFailedSelfTests(scsidev, 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 = false; state.selflogcount = 0; state.selfloghour = 0; } else { // register starting values to watch for changes state.selflogcount=SELFTEST_ERRORCOUNT(retval); state.selfloghour =SELFTEST_ERRORHOURS(retval); } } // disable autosave (set GLTSD bit) if (cfg.autosave==1){ if (scsiSetControlGLTSD(scsidev, 1, state.modese_len)) PrintOut(LOG_INFO,"Device: %s, could not disable autosave (set GLTSD bit).\n",device); else PrintOut(LOG_INFO,"Device: %s, disabled autosave (set GLTSD bit).\n",device); } // or enable autosave (clear GLTSD bit) if (cfg.autosave==2){ if (scsiSetControlGLTSD(scsidev, 0, state.modese_len)) PrintOut(LOG_INFO,"Device: %s, could not enable autosave (clear GLTSD bit).\n",device); else PrintOut(LOG_INFO,"Device: %s, enabled autosave (cleared GLTSD bit).\n",device); } // tell user we are registering device PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device); // Make sure that init_standby_check() ignores SCSI devices cfg.offlinests_ns = cfg.selfteststs_ns = false; // close file descriptor CloseDevice(scsidev, device); if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) { // Build file name for state file std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_'); std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_'); if (!state_path_prefix.empty()) { cfg.state_file = strprintf("%s%s-%s-%s.scsi.state", state_path_prefix.c_str(), vendor, model, serial); // Read previous state if (read_dev_state(cfg.state_file.c_str(), state)) { PrintOut(LOG_INFO, "Device: %s, state read from %s\n", device, cfg.state_file.c_str()); // Copy ATA attribute values to temp state state.update_temp_state(); } } if (!attrlog_path_prefix.empty()) cfg.attrlog_file = strprintf("%s%s-%s-%s.scsi.csv", attrlog_path_prefix.c_str(), vendor, model, serial); } finish_device_scan(cfg, state); return 0; } // If the self-test log has got more self-test errors (or more recent // self-test errors) recorded, then notify user. static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi) { const char * name = cfg.name.c_str(); if (newi<0) // command failed MailWarning(cfg, state, 8, "Device: %s, Read SMART Self-Test Log Failed", name); else { reset_warning_mail(cfg, state, 8, "Read SMART Self-Test Log worked again"); // old and new error counts int oldc=state.selflogcount; int newc=SELFTEST_ERRORCOUNT(newi); // old and new error timestamps in hours int oldh=state.selfloghour; int newh=SELFTEST_ERRORHOURS(newi); if (oldc<newc) { // increase in error count PrintOut(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n", name, oldc, newc); MailWarning(cfg, state, 3, "Device: %s, Self-Test Log error count increased from %d to %d", name, oldc, newc); state.must_write = true; } else if (newc > 0 && oldh != newh) { // more recent error // a 'more recent' error might actually be a smaller hour number, // if the hour number has wrapped. // There's still a bug here. You might just happen to run a new test // exactly 32768 hours after the previous failure, and have run exactly // 20 tests between the two, in which case smartd will miss the // new failure. PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %d\n", name, newh); MailWarning(cfg, state, 3, "Device: %s, new Self-Test Log error at hour timestamp %d", name, newh); state.must_write = true; } // Print info if error entries have disappeared // or newer successful successful extended self-test exits if (oldc > newc) { PrintOut(LOG_INFO, "Device: %s, Self-Test Log error count decreased from %d to %d\n", name, oldc, newc); if (newc == 0) reset_warning_mail(cfg, state, 3, "Self-Test Log does no longer report errors"); } // Needed since self-test error count may DECREASE. Hour might // also have changed. state.selflogcount= newc; state.selfloghour = newh; } return; } // Test types, ordered by priority. static const char test_type_chars[] = "LncrSCO"; static const unsigned num_test_types = sizeof(test_type_chars)-1; // returns test type if time to do test of type testtype, // 0 if not time to do test. static char next_scheduled_test(const dev_config & cfg, dev_state & state, bool scsi, time_t usetime = 0) { // check that self-testing has been requested if (cfg.test_regex.empty()) return 0; // Exit if drive not capable of any test if ( state.not_cap_long && state.not_cap_short && (scsi || (state.not_cap_conveyance && state.not_cap_offline))) return 0; // since we are about to call localtime(), be sure glibc is informed // of any timezone changes we make. if (!usetime) FixGlibcTimeZoneBug(); // Is it time for next check? time_t now = (!usetime ? time(0) : usetime); if (now < state.scheduled_test_next_check) return 0; // Limit time check interval to 90 days if (state.scheduled_test_next_check + (3600L*24*90) < now) state.scheduled_test_next_check = now - (3600L*24*90); // Check interval [state.scheduled_test_next_check, now] for scheduled tests char testtype = 0; time_t testtime = 0; int testhour = 0; int maxtest = num_test_types-1; for (time_t t = state.scheduled_test_next_check; ; ) { struct tm * tms = localtime(&t); // tm_wday is 0 (Sunday) to 6 (Saturday). We use 1 (Monday) to 7 (Sunday). int weekday = (tms->tm_wday ? tms->tm_wday : 7); for (int i = 0; i <= maxtest; i++) { // Skip if drive not capable of this test switch (test_type_chars[i]) { case 'L': if (state.not_cap_long) continue; break; case 'S': if (state.not_cap_short) continue; break; case 'C': if (scsi || state.not_cap_conveyance) continue; break; case 'O': if (scsi || state.not_cap_offline) continue; break; case 'c': case 'n': case 'r': if (scsi || state.not_cap_selective) continue; break; default: continue; } // Try match of "T/MM/DD/d/HH" char pattern[16]; snprintf(pattern, sizeof(pattern), "%c/%02d/%02d/%1d/%02d", test_type_chars[i], tms->tm_mon+1, tms->tm_mday, weekday, tms->tm_hour); if (cfg.test_regex.full_match(pattern)) { // Test found testtype = pattern[0]; testtime = t; testhour = tms->tm_hour; // Limit further matches to higher priority self-tests maxtest = i-1; break; } } // Exit if no tests left or current time reached if (maxtest < 0) break; if (t >= now) break; // Check next hour if ((t += 3600) > now) t = now; } // Do next check not before next hour. struct tm * tmnow = localtime(&now); state.scheduled_test_next_check = now + (3600 - tmnow->tm_min*60 - tmnow->tm_sec); if (testtype) { state.must_write = true; // Tell user if an old test was found. if (!usetime && !(testhour == tmnow->tm_hour && testtime + 3600 > now)) { char datebuf[DATEANDEPOCHLEN]; dateandtimezoneepoch(datebuf, testtime); PrintOut(LOG_INFO, "Device: %s, old test of type %c not run at %s, starting now.\n", cfg.name.c_str(), testtype, datebuf); } } return testtype; } // Print a list of future tests. static void PrintTestSchedule(const dev_config_vector & configs, dev_state_vector & states, const smart_device_list & devices) { unsigned numdev = configs.size(); if (!numdev) return; std::vector<int> testcnts(numdev * num_test_types, 0); PrintOut(LOG_INFO, "\nNext scheduled self tests (at most 5 of each type per device):\n"); // FixGlibcTimeZoneBug(); // done in PrintOut() time_t now = time(0); char datenow[DATEANDEPOCHLEN], date[DATEANDEPOCHLEN]; dateandtimezoneepoch(datenow, now); long seconds; for (seconds=checktime; seconds<3600L*24*90; seconds+=checktime) { // Check for each device whether a test will be run time_t testtime = now + seconds; for (unsigned i = 0; i < numdev; i++) { const dev_config & cfg = configs.at(i); dev_state & state = states.at(i); const char * p; char testtype = next_scheduled_test(cfg, state, devices.at(i)->is_scsi(), testtime); if (testtype && (p = strchr(test_type_chars, testtype))) { unsigned t = (p - test_type_chars); // Report at most 5 tests of each type if (++testcnts[i*num_test_types + t] <= 5) { dateandtimezoneepoch(date, testtime); PrintOut(LOG_INFO, "Device: %s, will do test %d of type %c at %s\n", cfg.name.c_str(), testcnts[i*num_test_types + t], testtype, date); } } } } // Report totals dateandtimezoneepoch(date, now+seconds); PrintOut(LOG_INFO, "\nTotals [%s - %s]:\n", datenow, date); for (unsigned i = 0; i < numdev; i++) { const dev_config & cfg = configs.at(i); bool scsi = devices.at(i)->is_scsi(); for (unsigned t = 0; t < num_test_types; t++) { int cnt = testcnts[i*num_test_types + t]; if (cnt == 0 && !strchr((scsi ? "LS" : "LSCO"), test_type_chars[t])) continue; PrintOut(LOG_INFO, "Device: %s, will do %3d test%s of type %c\n", cfg.name.c_str(), cnt, (cnt==1?"":"s"), test_type_chars[t]); } } } // Return zero on success, nonzero on failure. Perform offline (background) // short or long (extended) self test on given scsi device. static int DoSCSISelfTest(const dev_config & cfg, dev_state & state, scsi_device * device, char testtype) { int retval = 0; const char *testname = 0; const char *name = cfg.name.c_str(); int inProgress; if (scsiSelfTestInProgress(device, &inProgress)) { PrintOut(LOG_CRIT, "Device: %s, does not support Self-Tests\n", name); state.not_cap_short = state.not_cap_long = true; return 1; } if (1 == inProgress) { PrintOut(LOG_INFO, "Device: %s, skip since Self-Test already in " "progress.\n", name); return 1; } switch (testtype) { case 'S': testname = "Short Self"; retval = scsiSmartShortSelfTest(device); break; case 'L': testname = "Long Self"; retval = scsiSmartExtendSelfTest(device); break; } // If we can't do the test, exit if (NULL == testname) { PrintOut(LOG_CRIT, "Device: %s, not capable of %c Self-Test\n", name, testtype); return 1; } if (retval) { if ((SIMPLE_ERR_BAD_OPCODE == retval) || (SIMPLE_ERR_BAD_FIELD == retval)) { PrintOut(LOG_CRIT, "Device: %s, not capable of %s-Test\n", name, testname); if ('L'==testtype) state.not_cap_long = true; else state.not_cap_short = true; return 1; } PrintOut(LOG_CRIT, "Device: %s, execute %s-Test failed (err: %d)\n", name, testname, retval); return 1; } PrintOut(LOG_INFO, "Device: %s, starting scheduled %s-Test.\n", name, testname); return 0; } // Do an offline immediate or self-test. Return zero on success, // nonzero on failure. static int DoATASelfTest(const dev_config & cfg, dev_state & state, ata_device * device, char testtype) { const char *name = cfg.name.c_str(); // Read current smart data and check status/capability struct ata_smart_values data; if (ataReadSmartValues(device, &data) || !(data.offline_data_collection_capability)) { PrintOut(LOG_CRIT, "Device: %s, not capable of Offline or Self-Testing.\n", name); return 1; } // Check for capability to do the test int dotest = -1, mode = 0; const char *testname = 0; switch (testtype) { case 'O': testname="Offline Immediate "; if (isSupportExecuteOfflineImmediate(&data)) dotest=OFFLINE_FULL_SCAN; else state.not_cap_offline = true; break; case 'C': testname="Conveyance Self-"; if (isSupportConveyanceSelfTest(&data)) dotest=CONVEYANCE_SELF_TEST; else state.not_cap_conveyance = true; break; case 'S': testname="Short Self-"; if (isSupportSelfTest(&data)) dotest=SHORT_SELF_TEST; else state.not_cap_short = true; break; case 'L': testname="Long Self-"; if (isSupportSelfTest(&data)) dotest=EXTEND_SELF_TEST; else state.not_cap_long = true; break; case 'c': case 'n': case 'r': testname = "Selective Self-"; if (isSupportSelectiveSelfTest(&data)) { dotest = SELECTIVE_SELF_TEST; switch (testtype) { case 'c': mode = SEL_CONT; break; case 'n': mode = SEL_NEXT; break; case 'r': mode = SEL_REDO; break; } } else state.not_cap_selective = true; break; } // If we can't do the test, exit if (dotest<0) { PrintOut(LOG_CRIT, "Device: %s, not capable of %sTest\n", name, testname); return 1; } // If currently running a self-test, do not interrupt it to start another. if (15==(data.self_test_exec_status >> 4)) { if (cfg.firmwarebugs.is_set(BUG_SAMSUNG3) && data.self_test_exec_status == 0xf0) { PrintOut(LOG_INFO, "Device: %s, will not skip scheduled %sTest " "despite unclear Self-Test byte (SAMSUNG Firmware bug).\n", name, testname); } else { PrintOut(LOG_INFO, "Device: %s, skip scheduled %sTest; %1d0%% remaining of current Self-Test.\n", name, testname, (int)(data.self_test_exec_status & 0x0f)); return 1; } } if (dotest == SELECTIVE_SELF_TEST) { // Set test span ata_selective_selftest_args selargs, prev_args; selargs.num_spans = 1; selargs.span[0].mode = mode; prev_args.num_spans = 1; prev_args.span[0].start = state.selective_test_last_start; prev_args.span[0].end = state.selective_test_last_end; if (ataWriteSelectiveSelfTestLog(device, selargs, &data, state.num_sectors, &prev_args)) { PrintOut(LOG_CRIT, "Device: %s, prepare %sTest failed\n", name, testname); return 1; } uint64_t start = selargs.span[0].start, end = selargs.span[0].end; PrintOut(LOG_INFO, "Device: %s, %s test span at LBA %"PRIu64" - %"PRIu64" (%"PRIu64" sectors, %u%% - %u%% of disk).\n", name, (selargs.span[0].mode == SEL_NEXT ? "next" : "redo"), start, end, end - start + 1, (unsigned)((100 * start + state.num_sectors/2) / state.num_sectors), (unsigned)((100 * end + state.num_sectors/2) / state.num_sectors)); state.selective_test_last_start = start; state.selective_test_last_end = end; } // execute the test, and return status int retval = smartcommandhandler(device, IMMEDIATE_OFFLINE, dotest, NULL); if (retval) { PrintOut(LOG_CRIT, "Device: %s, execute %sTest failed.\n", name, testname); return retval; } // Report recent test start to do_disable_standby_check() // and force log of next test status if (testtype == 'O') state.offline_started = true; else state.selftest_started = true; PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname); return 0; } // Check pending sector count attribute values (-C, -U directives). static void check_pending(const dev_config & cfg, dev_state & state, unsigned char id, bool increase_only, const ata_smart_values & smartval, int mailtype, const char * msg) { // Find attribute index int i = ata_find_attr_index(id, smartval); if (!(i >= 0 && ata_find_attr_index(id, state.smartval) == i)) return; // No report if no sectors pending. uint64_t rawval = ata_get_attr_raw_value(smartval.vendor_attributes[i], cfg.attribute_defs); if (rawval == 0) { reset_warning_mail(cfg, state, mailtype, "No more %s", msg); return; } // If attribute is not reset, report only sector count increases. uint64_t prev_rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs); if (!(!increase_only || prev_rawval < rawval)) return; // Format message. std::string s = strprintf("Device: %s, %"PRId64" %s", cfg.name.c_str(), rawval, msg); if (prev_rawval > 0 && rawval != prev_rawval) s += strprintf(" (changed %+"PRId64")", rawval - prev_rawval); PrintOut(LOG_CRIT, "%s\n", s.c_str()); MailWarning(cfg, state, mailtype, "%s", s.c_str()); state.must_write = true; } // Format Temperature value static const char * fmt_temp(unsigned char x, char (& buf)[20]) { if (!x) // unset return "??"; snprintf(buf, sizeof(buf), "%u", x); return buf; } // Check Temperature limits static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned char currtemp, unsigned char triptemp) { if (!(0 < currtemp && currtemp < 255)) { PrintOut(LOG_INFO, "Device: %s, failed to read Temperature\n", cfg.name.c_str()); return; } // Update Max Temperature const char * minchg = "", * maxchg = ""; if (currtemp > state.tempmax) { if (state.tempmax) maxchg = "!"; state.tempmax = currtemp; state.must_write = true; } char buf[20]; if (!state.temperature) { // First check if (!state.tempmin || currtemp < state.tempmin) // Delay Min Temperature update by ~ 30 minutes. state.tempmin_delay = time(0) + CHECKTIME - 60; PrintOut(LOG_INFO, "Device: %s, initial Temperature is %d Celsius (Min/Max %s/%u%s)\n", cfg.name.c_str(), (int)currtemp, fmt_temp(state.tempmin, buf), state.tempmax, maxchg); if (triptemp) PrintOut(LOG_INFO, " [trip Temperature is %d Celsius]\n", (int)triptemp); state.temperature = currtemp; } else { if (state.tempmin_delay) { // End Min Temperature update delay if ... if ( (state.tempmin && currtemp > state.tempmin) // current temp exceeds recorded min, || (state.tempmin_delay <= time(0))) { // or delay time is over. state.tempmin_delay = 0; if (!state.tempmin) state.tempmin = 255; } } // Update Min Temperature if (!state.tempmin_delay && currtemp < state.tempmin) { state.tempmin = currtemp; state.must_write = true; if (currtemp != state.temperature) minchg = "!"; } // Track changes if (cfg.tempdiff && (*minchg || *maxchg || abs((int)currtemp - (int)state.temperature) >= cfg.tempdiff)) { PrintOut(LOG_INFO, "Device: %s, Temperature changed %+d Celsius to %u Celsius (Min/Max %s%s/%u%s)\n", cfg.name.c_str(), (int)currtemp-(int)state.temperature, currtemp, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg); state.temperature = currtemp; } } // Check limits if (cfg.tempcrit && currtemp >= cfg.tempcrit) { PrintOut(LOG_CRIT, "Device: %s, Temperature %u Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)\n", cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg); MailWarning(cfg, state, 12, "Device: %s, Temperature %d Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)", cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg); } else if (cfg.tempinfo && currtemp >= cfg.tempinfo) { PrintOut(LOG_INFO, "Device: %s, Temperature %u Celsius reached limit of %u Celsius (Min/Max %s%s/%u%s)\n", cfg.name.c_str(), currtemp, cfg.tempinfo, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg); } else if (cfg.tempcrit) { unsigned char limit = (cfg.tempinfo ? cfg.tempinfo : cfg.tempcrit-5); if (currtemp < limit) reset_warning_mail(cfg, state, 12, "Temperature %u Celsius dropped below %u Celsius", currtemp, limit); } } // Check normalized and raw attribute values. static void check_attribute(const dev_config & cfg, dev_state & state, const ata_smart_attribute & attr, const ata_smart_attribute & prev, int attridx, const ata_smart_threshold_entry * thresholds) { // Check attribute and threshold ata_attr_state attrstate = ata_get_attr_state(attr, attridx, thresholds, cfg.attribute_defs); if (attrstate == ATTRSTATE_NON_EXISTING) return; // If requested, check for usage attributes that have failed. if ( cfg.usagefailed && attrstate == ATTRSTATE_FAILED_NOW && !cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGN_FAILUSE)) { std::string attrname = ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm); PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", cfg.name.c_str(), attr.id, attrname.c_str()); MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", cfg.name.c_str(), attr.id, attrname.c_str()); state.must_write = true; } // Return if we're not tracking this type of attribute bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(attr.flags); if (!( ( prefail && cfg.prefail) || (!prefail && cfg.usage ))) return; // Return if '-I ID' was specified if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGNORE)) return; // Issue warning if they don't have the same ID in all structures. if (attr.id != prev.id) { PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d\n", cfg.name.c_str(), attr.id, prev.id); return; } // Compare normalized values if valid. bool valchanged = false; if (attrstate > ATTRSTATE_NO_NORMVAL) { if (attr.current != prev.current) valchanged = true; } // Compare raw values if requested. bool rawchanged = false; if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW)) { if ( ata_get_attr_raw_value(attr, cfg.attribute_defs) != ata_get_attr_raw_value(prev, cfg.attribute_defs)) rawchanged = true; } // Return if no change if (!(valchanged || rawchanged)) return; // Format value strings std::string currstr, prevstr; if (attrstate == ATTRSTATE_NO_NORMVAL) { // Print raw values only currstr = strprintf("%s (Raw)", ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str()); prevstr = strprintf("%s (Raw)", ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str()); } else if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_PRINT)) { // Print normalized and raw values currstr = strprintf("%d [Raw %s]", attr.current, ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str()); prevstr = strprintf("%d [Raw %s]", prev.current, ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str()); } else { // Print normalized values only currstr = strprintf("%d", attr.current); prevstr = strprintf("%d", prev.current); } // Format message std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %s to %s", cfg.name.c_str(), (prefail ? "Prefailure" : "Usage"), attr.id, ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm).c_str(), prevstr.c_str(), currstr.c_str()); // Report this change as critical ? if ( (valchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_AS_CRIT)) || (rawchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_AS_CRIT))) { PrintOut(LOG_CRIT, "%s\n", msg.c_str()); MailWarning(cfg, state, 2, "%s", msg.c_str()); } else { PrintOut(LOG_INFO, "%s\n", msg.c_str()); } state.must_write = true; } static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev, bool firstpass, bool allow_selftests) { const char * name = cfg.name.c_str(); // If user has asked, test the email warning system if (cfg.emailtest) MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name); // if we can't open device, fail gracefully rather than hard -- // perhaps the next time around we'll be able to open it. ATAPI // cd/dvd devices will hang awaiting media if O_NONBLOCK is not // given (see linux cdrom driver). if (!atadev->open()) { PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, atadev->get_errmsg()); MailWarning(cfg, state, 9, "Device: %s, unable to open device", name); return 1; } if (debugmode) PrintOut(LOG_INFO,"Device: %s, opened ATA device\n", name); reset_warning_mail(cfg, state, 9, "open device worked again"); // user may have requested (with the -n Directive) to leave the disk // alone if it is in idle or sleeping mode. In this case check the // power mode and exit without check if needed if (cfg.powermode && !state.powermodefail) { int dontcheck=0, powermode=ataCheckPowerMode(atadev); const char * mode = 0; if (0 <= powermode && powermode < 0xff) { // wait for possible spin up and check again int powermode2; sleep(5); powermode2 = ataCheckPowerMode(atadev); if (powermode2 > powermode) PrintOut(LOG_INFO, "Device: %s, CHECK POWER STATUS spins up disk (0x%02x -> 0x%02x)\n", name, powermode, powermode2); powermode = powermode2; } switch (powermode){ case -1: // SLEEP mode="SLEEP"; if (cfg.powermode>=1) dontcheck=1; break; case 0: // STANDBY mode="STANDBY"; if (cfg.powermode>=2) dontcheck=1; break; case 0x80: // IDLE mode="IDLE"; if (cfg.powermode>=3) dontcheck=1; break; case 0xff: // ACTIVE/IDLE mode="ACTIVE or IDLE"; break; default: // UNKNOWN PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n", name, powermode); state.powermodefail = true; break; } // if we are going to skip a check, return now if (dontcheck){ // skip at most powerskipmax checks if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) { CloseDevice(atadev, name); if (!state.powerskipcnt && !cfg.powerquiet) // report first only and avoid waking up system disk PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode); state.powerskipcnt++; return 0; } else { PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to reached limit of skipped checks (%d check%s skipped)\n", name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s")); } state.powerskipcnt = 0; state.tempmin_delay = time(0) + CHECKTIME - 60; // Delay Min Temperature update } else if (state.powerskipcnt) { PrintOut(LOG_INFO, "Device: %s, is back in %s mode, resuming checks (%d check%s skipped)\n", name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s")); state.powerskipcnt = 0; state.tempmin_delay = time(0) + CHECKTIME - 60; // Delay Min Temperature update } } // check smart status if (cfg.smartcheck) { int status=ataSmartStatus2(atadev); if (status==-1){ PrintOut(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name); MailWarning(cfg, state, 5, "Device: %s, not capable of SMART self-check", name); state.must_write = true; } else if (status==1){ PrintOut(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name); MailWarning(cfg, state, 1, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!", name); state.must_write = true; } } // Check everything that depends upon SMART Data (eg, Attribute values) if ( cfg.usagefailed || cfg.prefail || cfg.usage || cfg.curr_pending_id || cfg.offl_pending_id || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit || cfg.selftest || cfg.offlinests || cfg.selfteststs) { // Read current attribute values. ata_smart_values curval; if (ataReadSmartValues(atadev, &curval)){ PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name); MailWarning(cfg, state, 6, "Device: %s, failed to read SMART Attribute Data", name); state.must_write = true; } else { reset_warning_mail(cfg, state, 6, "read SMART Attribute Data worked again"); // look for current or offline pending sectors if (cfg.curr_pending_id) check_pending(cfg, state, cfg.curr_pending_id, cfg.curr_pending_incr, curval, 10, (!cfg.curr_pending_incr ? "Currently unreadable (pending) sectors" : "Total unreadable (pending) sectors" )); if (cfg.offl_pending_id) check_pending(cfg, state, cfg.offl_pending_id, cfg.offl_pending_incr, curval, 11, (!cfg.offl_pending_incr ? "Offline uncorrectable sectors" : "Total offline uncorrectable sectors")); // check temperature limits if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) CheckTemperature(cfg, state, ata_return_temperature_value(&curval, cfg.attribute_defs), 0); // look for failed usage attributes, or track usage or prefail attributes if (cfg.usagefailed || cfg.prefail || cfg.usage) { for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { check_attribute(cfg, state, curval.vendor_attributes[i], state.smartval.vendor_attributes[i], i, state.smartthres.thres_entries); } } // Log changes of offline data collection status if (cfg.offlinests) { if ( curval.offline_data_collection_status != state.smartval.offline_data_collection_status || state.offline_started // test was started in previous call || (firstpass && (debugmode || (curval.offline_data_collection_status & 0x7d)))) log_offline_data_coll_status(name, curval.offline_data_collection_status); } // Log changes of self-test execution status if (cfg.selfteststs) { if ( curval.self_test_exec_status != state.smartval.self_test_exec_status || state.selftest_started // test was started in previous call || (firstpass && (debugmode || curval.self_test_exec_status != 0x00))) log_self_test_exec_status(name, curval.self_test_exec_status); } // Save the new values for the next time around state.smartval = curval; } } state.offline_started = state.selftest_started = false; // check if number of selftest errors has increased (note: may also DECREASE) if (cfg.selftest) CheckSelfTestLogs(cfg, state, SelfTestErrorCount(atadev, name, cfg.firmwarebugs)); // check if number of ATA errors has increased if (cfg.errorlog || cfg.xerrorlog) { int errcnt1 = -1, errcnt2 = -1; if (cfg.errorlog) errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false); if (cfg.xerrorlog) errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true); // new number of errors is max of both logs int newc = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2); // did command fail? if (newc<0) // lack of PrintOut here is INTENTIONAL MailWarning(cfg, state, 7, "Device: %s, Read SMART Error Log Failed", name); // has error count increased? int oldc = state.ataerrorcount; if (newc>oldc){ PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", name, oldc, newc); MailWarning(cfg, state, 4, "Device: %s, ATA error count increased from %d to %d", name, oldc, newc); state.must_write = true; } if (newc>=0) state.ataerrorcount=newc; } // if the user has asked, and device is capable (or we're not yet // sure) check whether a self test should be done now. if (allow_selftests && !cfg.test_regex.empty()) { char testtype = next_scheduled_test(cfg, state, false/*!scsi*/); if (testtype) DoATASelfTest(cfg, state, atadev, testtype); } // Don't leave device open -- the OS/user may want to access it // before the next smartd cycle! CloseDevice(atadev, name); // Copy ATA attribute values to persistent state state.update_persistent_state(); return 0; } static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_device * scsidev, bool allow_selftests) { UINT8 asc, ascq; UINT8 currenttemp; UINT8 triptemp; UINT8 tBuf[252]; const char * name = cfg.name.c_str(); const char *cp; // If the user has asked for it, test the email warning system if (cfg.emailtest) MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name); // if we can't open device, fail gracefully rather than hard -- // perhaps the next time around we'll be able to open it if (!scsidev->open()) { PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, scsidev->get_errmsg()); MailWarning(cfg, state, 9, "Device: %s, unable to open device", name); return 1; } else if (debugmode) PrintOut(LOG_INFO,"Device: %s, opened SCSI device\n", name); reset_warning_mail(cfg, state, 9, "open device worked again"); currenttemp = 0; asc = 0; ascq = 0; if (!state.SuppressReport) { if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported, &asc, &ascq, ¤ttemp, &triptemp)) { PrintOut(LOG_INFO, "Device: %s, failed to read SMART values\n", name); MailWarning(cfg, state, 6, "Device: %s, failed to read SMART values", name); state.SuppressReport = 1; } } if (asc > 0) { cp = scsiGetIEString(asc, ascq); if (cp) { PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp); MailWarning(cfg, state, 1,"Device: %s, SMART Failure: %s", name, cp); } else if (asc == 4 && ascq == 9) { PrintOut(LOG_INFO,"Device: %s, self-test in progress\n", name); } else if (debugmode) PrintOut(LOG_INFO,"Device: %s, non-SMART asc,ascq: %d,%d\n", name, (int)asc, (int)ascq); } else if (debugmode) PrintOut(LOG_INFO,"Device: %s, SMART health: passed\n", name); // check temperature limits if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit || !cfg.attrlog_file.empty()) CheckTemperature(cfg, state, currenttemp, triptemp); // check if number of selftest errors has increased (note: may also DECREASE) if (cfg.selftest) CheckSelfTestLogs(cfg, state, scsiCountFailedSelfTests(scsidev, 0)); if (allow_selftests && !cfg.test_regex.empty()) { char testtype = next_scheduled_test(cfg, state, true/*scsi*/); if (testtype) DoSCSISelfTest(cfg, state, scsidev, testtype); } if (!cfg.attrlog_file.empty()){ // saving error counters to state if (state.ReadECounterPageSupported && (0 == scsiLogSense(scsidev, READ_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[0].errCounter); state.scsi_error_counters[0].found=1; } if (state.WriteECounterPageSupported && (0 == scsiLogSense(scsidev, WRITE_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[1].errCounter); state.scsi_error_counters[1].found=1; } if (state.VerifyECounterPageSupported && (0 == scsiLogSense(scsidev, VERIFY_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[2].errCounter); state.scsi_error_counters[2].found=1; } if (state.NonMediumErrorPageSupported && (0 == scsiLogSense(scsidev, NON_MEDIUM_ERROR_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { scsiDecodeNonMediumErrPage(tBuf, &state.scsi_nonmedium_error.nme); state.scsi_nonmedium_error.found=1; } } CloseDevice(scsidev, name); return 0; } // 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled static int standby_disable_state = 0; static void init_disable_standby_check(dev_config_vector & configs) { // Check for '-l offlinests,ns' or '-l selfteststs,ns' directives bool sts1 = false, sts2 = false; for (unsigned i = 0; i < configs.size() && !(sts1 || sts2); i++) { const dev_config & cfg = configs.at(i); if (cfg.offlinests_ns) sts1 = true; if (cfg.selfteststs_ns) sts2 = true; } // Check for support of disable auto standby // Reenable standby if smartd.conf was reread if (sts1 || sts2 || standby_disable_state == 3) { if (!smi()->disable_system_auto_standby(false)) { if (standby_disable_state == 3) PrintOut(LOG_CRIT, "System auto standby enable failed: %s\n", smi()->get_errmsg()); if (sts1 || sts2) { PrintOut(LOG_INFO, "Disable auto standby not supported, ignoring ',ns' from %s%s%s\n", (sts1 ? "-l offlinests,ns" : ""), (sts1 && sts2 ? " and " : ""), (sts2 ? "-l selfteststs,ns" : "")); sts1 = sts2 = false; } } } standby_disable_state = (sts1 || sts2 ? 1 : 0); } static void do_disable_standby_check(const dev_config_vector & configs, const dev_state_vector & states) { if (!standby_disable_state) return; // Check for just started or still running self-tests bool running = false; for (unsigned i = 0; i < configs.size() && !running; i++) { const dev_config & cfg = configs.at(i); const dev_state & state = states.at(i); if ( ( cfg.offlinests_ns && (state.offline_started || is_offl_coll_in_progress(state.smartval.offline_data_collection_status))) || ( cfg.selfteststs_ns && (state.selftest_started || is_self_test_in_progress(state.smartval.self_test_exec_status))) ) running = true; // state.offline/selftest_started will be reset after next logging of test status } // Disable/enable auto standby and log state changes if (!running) { if (standby_disable_state != 1) { if (!smi()->disable_system_auto_standby(false)) PrintOut(LOG_CRIT, "Self-test(s) completed, system auto standby enable failed: %s\n", smi()->get_errmsg()); else PrintOut(LOG_INFO, "Self-test(s) completed, system auto standby enabled\n"); standby_disable_state = 1; } } else if (!smi()->disable_system_auto_standby(true)) { if (standby_disable_state != 2) { PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disable rejected: %s\n", smi()->get_errmsg()); standby_disable_state = 2; } } else { if (standby_disable_state != 3) { PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disabled\n"); standby_disable_state = 3; } } } // Checks the SMART status of all ATA and SCSI devices static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector & states, smart_device_list & devices, bool firstpass, bool allow_selftests) { for (unsigned i = 0; i < configs.size(); i++) { const dev_config & cfg = configs.at(i); dev_state & state = states.at(i); smart_device * dev = devices.at(i); if (dev->is_ata()) ATACheckDevice(cfg, state, dev->to_ata(), firstpass, allow_selftests); else if (dev->is_scsi()) SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests); } do_disable_standby_check(configs, states); } // Set if Initialize() was called static bool is_initialized = false; // Does initialization right after fork to daemon mode static void Initialize(time_t *wakeuptime) { // Call Goodbye() on exit is_initialized = true; // write PID file if (!debugmode) WritePidFile(); // install signal handlers. On Solaris, can't use signal() because // it resets the handler to SIG_DFL after each call. So use sigset() // instead. So SIGNALFN()==signal() or SIGNALFN()==sigset(). // normal and abnormal exit if (SIGNALFN(SIGTERM, sighandler)==SIG_IGN) SIGNALFN(SIGTERM, SIG_IGN); if (SIGNALFN(SIGQUIT, sighandler)==SIG_IGN) SIGNALFN(SIGQUIT, SIG_IGN); // in debug mode, <CONTROL-C> ==> HUP if (SIGNALFN(SIGINT, debugmode?HUPhandler:sighandler)==SIG_IGN) SIGNALFN(SIGINT, SIG_IGN); // Catch HUP and USR1 if (SIGNALFN(SIGHUP, HUPhandler)==SIG_IGN) SIGNALFN(SIGHUP, SIG_IGN); if (SIGNALFN(SIGUSR1, USR1handler)==SIG_IGN) SIGNALFN(SIGUSR1, SIG_IGN); #ifdef _WIN32 if (SIGNALFN(SIGUSR2, USR2handler)==SIG_IGN) SIGNALFN(SIGUSR2, SIG_IGN); #endif // initialize wakeup time to CURRENT time *wakeuptime=time(NULL); return; } #ifdef _WIN32 // Toggle debug mode implemented for native windows only // (there is no easy way to reopen tty on *nix) static void ToggleDebugMode() { if (!debugmode) { PrintOut(LOG_INFO,"Signal USR2 - enabling debug mode\n"); if (!daemon_enable_console("smartd [Debug]")) { debugmode = 1; daemon_signal(SIGINT, HUPhandler); PrintOut(LOG_INFO,"smartd debug mode enabled, PID=%d\n", getpid()); } else PrintOut(LOG_INFO,"enable console failed\n"); } else if (debugmode == 1) { daemon_disable_console(); debugmode = 0; daemon_signal(SIGINT, sighandler); PrintOut(LOG_INFO,"Signal USR2 - debug mode disabled\n"); } else PrintOut(LOG_INFO,"Signal USR2 - debug mode %d not changed\n", debugmode); } #endif static time_t dosleep(time_t wakeuptime, bool & sigwakeup) { // If past wake-up-time, compute next wake-up-time time_t timenow=time(NULL); while (wakeuptime<=timenow){ int intervals=1+(timenow-wakeuptime)/checktime; wakeuptime+=intervals*checktime; } // sleep until we catch SIGUSR1 or have completed sleeping int addtime = 0; while (timenow < wakeuptime+addtime && !caughtsigUSR1 && !caughtsigHUP && !caughtsigEXIT) { // protect user again system clock being adjusted backwards if (wakeuptime>timenow+checktime){ PrintOut(LOG_CRIT, "System clock time adjusted to the past. Resetting next wakeup time.\n"); wakeuptime=timenow+checktime; } // Exit sleep when time interval has expired or a signal is received sleep(wakeuptime+addtime-timenow); #ifdef _WIN32 // toggle debug mode? if (caughtsigUSR2) { ToggleDebugMode(); caughtsigUSR2 = 0; } #endif timenow=time(NULL); // Actual sleep time too long? if (!addtime && timenow > wakeuptime+60) { if (debugmode) PrintOut(LOG_INFO, "Sleep time was %d seconds too long, assuming wakeup from standby mode.\n", (int)(timenow-wakeuptime)); // Wait another 20 seconds to avoid I/O errors during disk spin-up addtime = timenow-wakeuptime+20; // Use next wake-up-time if close int nextcheck = checktime - addtime % checktime; if (nextcheck <= 20) addtime += nextcheck; } } // if we caught a SIGUSR1 then print message and clear signal if (caughtsigUSR1){ PrintOut(LOG_INFO,"Signal USR1 - checking devices now rather than in %d seconds.\n", wakeuptime-timenow>0?(int)(wakeuptime-timenow):0); caughtsigUSR1=0; sigwakeup = true; } // return adjusted wakeuptime return wakeuptime; } // Print out a list of valid arguments for the Directive d static void printoutvaliddirectiveargs(int priority, char d) { switch (d) { case 'n': PrintOut(priority, "never[,N][,q], sleep[,N][,q], standby[,N][,q], idle[,N][,q]"); break; case 's': PrintOut(priority, "valid_regular_expression"); break; case 'd': PrintOut(priority, "%s", smi()->get_valid_dev_types_str().c_str()); break; case 'T': PrintOut(priority, "normal, permissive"); break; case 'o': case 'S': PrintOut(priority, "on, off"); break; case 'l': PrintOut(priority, "error, selftest"); break; case 'M': PrintOut(priority, "\"once\", \"daily\", \"diminishing\", \"test\", \"exec\""); break; case 'v': PrintOut(priority, "\n%s\n", create_vendor_attribute_arg_list().c_str()); break; case 'P': PrintOut(priority, "use, ignore, show, showall"); break; case 'F': PrintOut(priority, "%s", get_valid_firmwarebug_args()); break; case 'e': PrintOut(priority, "aam,[N|off], apm,[N|off], lookahead,[on|off], " "security-freeze, standby,[N|off], wcache,[on|off]"); break; } } // exits with an error message, or returns integer value of token static int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile, int min, int max, char * suffix = 0) { // make sure argument is there if (!arg) { PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n", cfgfile, lineno, name, token, min, max); return -1; } // get argument value (base 10), check that it's integer, and in-range char *endptr; int val = strtol(arg,&endptr,10); // optional suffix present? if (suffix) { if (!strcmp(endptr, suffix)) endptr += strlen(suffix); else *suffix = 0; } if (!(!*endptr && min <= val && val <= max)) { PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n", cfgfile, lineno, name, token, arg, min, max); return -1; } // all is well; return value return val; } // Get 1-3 small integer(s) for '-W' directive static int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile, unsigned char *val1, unsigned char *val2, unsigned char *val3) { unsigned v1 = 0, v2 = 0, v3 = 0; int n1 = -1, n2 = -1, n3 = -1, len; if (!arg) { PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes 1-3 integer argument(s) from 0 to 255.\n", cfgfile, lineno, name, token); return -1; } len = strlen(arg); if (!( sscanf(arg, "%u%n,%u%n,%u%n", &v1, &n1, &v2, &n2, &v3, &n3) >= 1 && (n1 == len || n2 == len || n3 == len) && v1 <= 255 && v2 <= 255 && v3 <= 255)) { PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs 1-3 integer(s) from 0 to 255.\n", cfgfile, lineno, name, token, arg); return -1; } *val1 = (unsigned char)v1; *val2 = (unsigned char)v2; *val3 = (unsigned char)v3; return 0; } #ifdef _WIN32 // Concatenate strtok() results if quoted with "..." static const char * strtok_dequote(const char * delimiters) { const char * t = strtok(0, delimiters); if (!t || t[0] != '"') return t; static std::string token; token = t+1; for (;;) { t = strtok(0, delimiters); if (!t || !*t) return "\""; token += ' '; int len = strlen(t); if (t[len-1] == '"') { token += std::string(t, len-1); break; } token += t; } return token.c_str(); } #endif // _WIN32 // This function returns 1 if it has correctly parsed one token (and // any arguments), else zero if no tokens remain. It returns -1 if an // error was encountered. static int ParseToken(char * token, dev_config & cfg) { char sym; const char * name = cfg.name.c_str(); int lineno=cfg.lineno; const char *delim = " \n\t"; int badarg = 0; int missingarg = 0; const char *arg = 0; // is the rest of the line a comment if (*token=='#') return 1; // is the token not recognized? if (*token!='-' || strlen(token)!=2) { PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n", configfile, lineno, name, token); PrintOut(LOG_CRIT, "Run smartd -D to print a list of valid Directives.\n"); return -1; } // token we will be parsing: sym=token[1]; // parse the token and swallow its argument int val; char plus[] = "+", excl[] = "!"; switch (sym) { case 'C': // monitor current pending sector count (default 197) if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255, plus)) < 0) return -1; cfg.curr_pending_id = (unsigned char)val; cfg.curr_pending_incr = (*plus == '+'); cfg.curr_pending_set = true; break; case 'U': // monitor offline uncorrectable sectors (default 198) if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255, plus)) < 0) return -1; cfg.offl_pending_id = (unsigned char)val; cfg.offl_pending_incr = (*plus == '+'); cfg.offl_pending_set = true; break; case 'T': // Set tolerance level for SMART command failures if ((arg = strtok(NULL, delim)) == NULL) { missingarg = 1; } else if (!strcmp(arg, "normal")) { // Normal mode: exit on failure of a mandatory S.M.A.R.T. command, but // not on failure of an optional S.M.A.R.T. command. // This is the default so we don't need to actually do anything here. cfg.permissive = false; } else if (!strcmp(arg, "permissive")) { // Permissive mode; ignore errors from Mandatory SMART commands cfg.permissive = true; } else { badarg = 1; } break; case 'd': // specify the device type if ((arg = strtok(NULL, delim)) == NULL) { missingarg = 1; } else if (!strcmp(arg, "ignore")) { cfg.ignore = true; } else if (!strcmp(arg, "removable")) { cfg.removable = true; } else if (!strcmp(arg, "auto")) { cfg.dev_type = ""; } else { cfg.dev_type = arg; } break; case 'F': // fix firmware bug if (!(arg = strtok(0, delim))) missingarg = 1; else if (!parse_firmwarebug_def(arg, cfg.firmwarebugs)) badarg = 1; break; case 'H': // check SMART status cfg.smartcheck = true; break; case 'f': // check for failure of usage attributes cfg.usagefailed = true; break; case 't': // track changes in all vendor attributes cfg.prefail = true; cfg.usage = true; break; case 'p': // track changes in prefail vendor attributes cfg.prefail = true; break; case 'u': // track changes in usage vendor attributes cfg.usage = true; break; case 'l': // track changes in SMART logs if ((arg = strtok(NULL, delim)) == NULL) { missingarg = 1; } else if (!strcmp(arg, "selftest")) { // track changes in self-test log cfg.selftest = true; } else if (!strcmp(arg, "error")) { // track changes in ATA error log cfg.errorlog = true; } else if (!strcmp(arg, "xerror")) { // track changes in Extended Comprehensive SMART error log cfg.xerrorlog = true; } else if (!strcmp(arg, "offlinests")) { // track changes in offline data collection status cfg.offlinests = true; } else if (!strcmp(arg, "offlinests,ns")) { // track changes in offline data collection status, disable auto standby cfg.offlinests = cfg.offlinests_ns = true; } else if (!strcmp(arg, "selfteststs")) { // track changes in self-test execution status cfg.selfteststs = true; } else if (!strcmp(arg, "selfteststs,ns")) { // track changes in self-test execution status, disable auto standby cfg.selfteststs = cfg.selfteststs_ns = true; } else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) { // set SCT Error Recovery Control unsigned rt = ~0, wt = ~0; int nc = -1; sscanf(arg,"scterc,%u,%u%n", &rt, &wt, &nc); if (nc == (int)strlen(arg) && rt <= 999 && wt <= 999) { cfg.sct_erc_set = true; cfg.sct_erc_readtime = rt; cfg.sct_erc_writetime = wt; } else badarg = 1; } else { badarg = 1; } break; case 'a': // monitor everything cfg.smartcheck = true; cfg.prefail = true; cfg.usagefailed = true; cfg.usage = true; cfg.selftest = true; cfg.errorlog = true; cfg.selfteststs = true; break; case 'o': // automatic offline testing enable/disable if ((arg = strtok(NULL, delim)) == NULL) { missingarg = 1; } else if (!strcmp(arg, "on")) { cfg.autoofflinetest = 2; } else if (!strcmp(arg, "off")) { cfg.autoofflinetest = 1; } else { badarg = 1; } break; case 'n': // skip disk check if in idle or standby mode if (!(arg = strtok(NULL, delim))) missingarg = 1; else { char *endptr = NULL; char *next = strchr(const_cast<char*>(arg), ','); cfg.powerquiet = false; cfg.powerskipmax = 0; if (next!=NULL) *next='\0'; if (!strcmp(arg, "never")) cfg.powermode = 0; else if (!strcmp(arg, "sleep")) cfg.powermode = 1; else if (!strcmp(arg, "standby")) cfg.powermode = 2; else if (!strcmp(arg, "idle")) cfg.powermode = 3; else badarg = 1; // if optional arguments are present if (!badarg && next!=NULL) { next++; cfg.powerskipmax = strtol(next, &endptr, 10); if (endptr == next) cfg.powerskipmax = 0; else { next = endptr + (*endptr != '\0'); if (cfg.powerskipmax <= 0) badarg = 1; } if (*next != '\0') { if (!strcmp("q", next)) cfg.powerquiet = true; else { badarg = 1; } } } } break; case 'S': // automatic attribute autosave enable/disable if ((arg = strtok(NULL, delim)) == NULL) { missingarg = 1; } else if (!strcmp(arg, "on")) { cfg.autosave = 2; } else if (!strcmp(arg, "off")) { cfg.autosave = 1; } else { badarg = 1; } break; case 's': // warn user, and delete any previously given -s REGEXP Directives if (!cfg.test_regex.empty()){ PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Test Directive -s %s\n", configfile, lineno, name, cfg.test_regex.get_pattern()); cfg.test_regex = regular_expression(); } // check for missing argument if (!(arg = strtok(NULL, delim))) { missingarg = 1; } // Compile regex else { if (!cfg.test_regex.compile(arg, REG_EXTENDED)) { // not a valid regular expression! PrintOut(LOG_CRIT, "File %s line %d (drive %s): -s argument \"%s\" is INVALID extended regular expression. %s.\n", configfile, lineno, name, arg, cfg.test_regex.get_errmsg()); return -1; } } // Do a bit of sanity checking and warn user if we think that // their regexp is "strange". User probably confused about shell // glob(3) syntax versus regular expression syntax regexp(7). if (arg[(val = strspn(arg, "0123456789/.-+*|()?^$[]SLCOcnr"))]) PrintOut(LOG_INFO, "File %s line %d (drive %s): warning, character %d (%c) looks odd in extended regular expression %s\n", configfile, lineno, name, val+1, arg[val], arg); break; case 'm': // send email to address that follows if (!(arg = strtok(NULL,delim))) missingarg = 1; else { if (!cfg.emailaddress.empty()) PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n", configfile, lineno, name, cfg.emailaddress.c_str()); #ifdef _WIN32 if ( !strcmp(arg, "msgbox") || !strcmp(arg, "sysmsgbox") || str_starts_with(arg, "msgbox,") || str_starts_with(arg, "sysmsgbox,")) { cfg.emailaddress = "console"; const char * arg2 = strchr(arg, ','); if (arg2) cfg.emailaddress += arg2; PrintOut(LOG_INFO, "File %s line %d (drive %s): Deprecated -m %s changed to -m %s\n", configfile, lineno, name, arg, cfg.emailaddress.c_str()); } else #endif cfg.emailaddress = arg; } break; case 'M': // email warning options if (!(arg = strtok(NULL, delim))) missingarg = 1; else if (!strcmp(arg, "once")) cfg.emailfreq = 1; else if (!strcmp(arg, "daily")) cfg.emailfreq = 2; else if (!strcmp(arg, "diminishing")) cfg.emailfreq = 3; else if (!strcmp(arg, "test")) cfg.emailtest = 1; else if (!strcmp(arg, "exec")) { // Get the next argument (the command line) #ifdef _WIN32 // Allow "/path name/with spaces/..." on Windows arg = strtok_dequote(delim); if (arg && arg[0] == '"') { PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument: missing closing quote\n", configfile, lineno, name, token); return -1; } #else arg = strtok(0, delim); #endif if (!arg) { PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument must be followed by executable path.\n", configfile, lineno, name, token); return -1; } // Free the last cmd line given if any, and copy new one if (!cfg.emailcmdline.empty()) PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous mail Directive -M exec %s\n", configfile, lineno, name, cfg.emailcmdline.c_str()); cfg.emailcmdline = arg; } else badarg = 1; break; case 'i': // ignore failure of usage attribute if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0) return -1; cfg.monitor_attr_flags.set(val, MONITOR_IGN_FAILUSE); break; case 'I': // ignore attribute for tracking purposes if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0) return -1; cfg.monitor_attr_flags.set(val, MONITOR_IGNORE); break; case 'r': // print raw value when tracking if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255, excl)) < 0) return -1; cfg.monitor_attr_flags.set(val, MONITOR_RAW_PRINT); if (*excl == '!') // attribute change is critical cfg.monitor_attr_flags.set(val, MONITOR_AS_CRIT); break; case 'R': // track changes in raw value (forces printing of raw value) if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255, excl)) < 0) return -1; cfg.monitor_attr_flags.set(val, MONITOR_RAW_PRINT|MONITOR_RAW); if (*excl == '!') // raw value change is critical cfg.monitor_attr_flags.set(val, MONITOR_RAW_AS_CRIT); break; case 'W': // track Temperature if ((val=Get3Integers(arg=strtok(NULL,delim), name, token, lineno, configfile, &cfg.tempdiff, &cfg.tempinfo, &cfg.tempcrit))<0) return -1; break; case 'v': // non-default vendor-specific attribute meaning if (!(arg=strtok(NULL,delim))) { missingarg = 1; } else if (!parse_attribute_def(arg, cfg.attribute_defs, PRIOR_USER)) { badarg = 1; } break; case 'P': // Define use of drive-specific presets. if (!(arg = strtok(NULL, delim))) { missingarg = 1; } else if (!strcmp(arg, "use")) { cfg.ignorepresets = false; } else if (!strcmp(arg, "ignore")) { cfg.ignorepresets = true; } else if (!strcmp(arg, "show")) { cfg.showpresets = true; } else if (!strcmp(arg, "showall")) { showallpresets(); } else { badarg = 1; } break; case 'e': // Various ATA settings if (!(arg = strtok(NULL, delim))) { missingarg = true; } else { char arg2[16+1]; unsigned val; int n1 = -1, n2 = -1, n3 = -1, len = strlen(arg); if (sscanf(arg, "%16[^,=]%n%*[,=]%n%u%n", arg2, &n1, &n2, &val, &n3) >= 1 && (n1 == len || n2 > 0)) { bool on = (n2 > 0 && !strcmp(arg+n2, "on")); bool off = (n2 > 0 && !strcmp(arg+n2, "off")); if (n3 != len) val = ~0U; if (!strcmp(arg2, "aam")) { if (off) cfg.set_aam = -1; else if (val <= 254) cfg.set_aam = val + 1; else badarg = true; } else if (!strcmp(arg2, "apm")) { if (off) cfg.set_apm = -1; else if (1 <= val && val <= 254) cfg.set_apm = val + 1; else badarg = true; } else if (!strcmp(arg2, "lookahead")) { if (off) cfg.set_lookahead = -1; else if (on) cfg.set_lookahead = 1; else badarg = true; } else if (!strcmp(arg, "security-freeze")) { cfg.set_security_freeze = true; } else if (!strcmp(arg2, "standby")) { if (off) cfg.set_standby = 0 + 1; else if (val <= 255) cfg.set_standby = val + 1; else badarg = true; } else if (!strcmp(arg2, "wcache")) { if (off) cfg.set_wcache = -1; else if (on) cfg.set_wcache = 1; else badarg = true; } else badarg = true; } else badarg = true; } break; default: // Directive not recognized PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n", configfile, lineno, name, token); Directives(); return -1; } if (missingarg) { PrintOut(LOG_CRIT, "File %s line %d (drive %s): Missing argument to %s Directive\n", configfile, lineno, name, token); } if (badarg) { PrintOut(LOG_CRIT, "File %s line %d (drive %s): Invalid argument to %s Directive: %s\n", configfile, lineno, name, token, arg); } if (missingarg || badarg) { PrintOut(LOG_CRIT, "Valid arguments to %s Directive are: ", token); printoutvaliddirectiveargs(LOG_CRIT, sym); PrintOut(LOG_CRIT, "\n"); return -1; } return 1; } // Scan directive for configuration file #define SCANDIRECTIVE "DEVICESCAN" // This is the routine that adds things to the conf_entries list. // // Return values are: // 1: parsed a normal line // 0: found DEFAULT setting or comment or blank line // -1: found SCANDIRECTIVE line // -2: found an error // // Note: this routine modifies *line from the caller! static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf, int lineno, /*const*/ char * line) { const char *delim = " \n\t"; // get first token: device name. If a comment, skip line const char * name = strtok(line, delim); if (!name || *name == '#') return 0; // Check device name for DEFAULT or DEVICESCAN int retval; if (!strcmp("DEFAULT", name)) { retval = 0; // Restart with empty defaults default_conf = dev_config(); } else { retval = (!strcmp(SCANDIRECTIVE, name) ? -1 : 1); // Init new entry with current defaults conf_entries.push_back(default_conf); } dev_config & cfg = (retval ? conf_entries.back() : default_conf); cfg.name = name; // Later replaced by dev->get_info().info_name cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name cfg.lineno = lineno; // parse tokens one at a time from the file. while (char * token = strtok(0, delim)) { int rc = ParseToken(token, cfg); if (rc < 0) // error found on the line return -2; if (rc == 0) // No tokens left break; // PrintOut(LOG_INFO,"Parsed token %s\n",token); } // Don't perform checks below for DEFAULT entries if (retval == 0) return retval; // If NO monitoring directives are set, then set all of them. if (!( cfg.smartcheck || cfg.selftest || cfg.errorlog || cfg.xerrorlog || cfg.offlinests || cfg.selfteststs || cfg.usagefailed || cfg.prefail || cfg.usage || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) { PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n", cfg.name.c_str(), cfg.lineno, configfile); cfg.smartcheck = true; cfg.usagefailed = true; cfg.prefail = true; cfg.usage = true; cfg.selftest = true; cfg.errorlog = true; cfg.selfteststs = true; } // additional sanity check. Has user set -M options without -m? if (cfg.emailaddress.empty() && (!cfg.emailcmdline.empty() || cfg.emailfreq || cfg.emailtest)){ PrintOut(LOG_CRIT,"Drive: %s, -M Directive(s) on line %d of file %s need -m ADDRESS Directive\n", cfg.name.c_str(), cfg.lineno, configfile); return -2; } // has the user has set <nomailer>? if (cfg.emailaddress == "<nomailer>") { // check that -M exec is also set if (cfg.emailcmdline.empty()){ PrintOut(LOG_CRIT,"Drive: %s, -m <nomailer> Directive on line %d of file %s needs -M exec Directive\n", cfg.name.c_str(), cfg.lineno, configfile); return -2; } // From here on the sign of <nomailer> is cfg.emailaddress.empty() and !cfg.emailcmdline.empty() cfg.emailaddress.clear(); } return retval; } // Parses a configuration file. Return values are: // N=>0: found N entries // -1: syntax error in config file // -2: config file does not exist // -3: config file exists but cannot be read // // In the case where the return value is 0, there are three // possiblities: // Empty configuration file ==> conf_entries.empty() // No configuration file ==> conf_entries[0].lineno == 0 // SCANDIRECTIVE found ==> conf_entries.back().lineno != 0 (size >= 1) static int ParseConfigFile(dev_config_vector & conf_entries) { // maximum line length in configuration file const int MAXLINELEN = 256; // maximum length of a continued line in configuration file const int MAXCONTLINE = 1023; stdio_file f; // Open config file, if it exists and is not <stdin> if (!(configfile == configfile_stdin)) { // pointer comparison ok here if (!f.open(configfile,"r") && (errno!=ENOENT || !configfile_alt.empty())) { // file exists but we can't read it or it should exist due to '-c' option int ret = (errno!=ENOENT ? -3 : -2); PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n", strerror(errno),configfile); return ret; } } else // read from stdin ('-c -' option) f.open(stdin); // Start with empty defaults dev_config default_conf; // No configuration file found -- use fake one int entry = 0; if (!f) { char fakeconfig[] = SCANDIRECTIVE" -a"; // TODO: Remove this hack, build cfg_entry. if (ParseConfigLine(conf_entries, default_conf, 0, fakeconfig) != -1) throw std::logic_error("Internal error parsing "SCANDIRECTIVE); return 0; } #ifdef __CYGWIN__ setmode(fileno(f), O_TEXT); // Allow files with \r\n #endif // configuration file exists PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile); // parse config file line by line int lineno = 1, cont = 0, contlineno = 0; char line[MAXLINELEN+2]; char fullline[MAXCONTLINE+1]; for (;;) { int len=0,scandevice; char *lastslash; char *comment; char *code; // make debugging simpler memset(line,0,sizeof(line)); // get a line code=fgets(line, MAXLINELEN+2, f); // are we at the end of the file? if (!code){ if (cont) { scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline); // See if we found a SCANDIRECTIVE directive if (scandevice==-1) return 0; // did we find a syntax error if (scandevice==-2) return -1; // the final line is part of a continuation line cont=0; entry+=scandevice; } break; } // input file line number contlineno++; // See if line is too long len=strlen(line); if (len>MAXLINELEN){ const char *warn; if (line[len-1]=='\n') warn="(including newline!) "; else warn=""; PrintOut(LOG_CRIT,"Error: line %d of file %s %sis more than MAXLINELEN=%d characters.\n", (int)contlineno,configfile,warn,(int)MAXLINELEN); return -1; } // Ignore anything after comment symbol if ((comment=strchr(line,'#'))){ *comment='\0'; len=strlen(line); } // is the total line (made of all continuation lines) too long? if (cont+len>MAXCONTLINE){ PrintOut(LOG_CRIT,"Error: continued line %d (actual line %d) of file %s is more than MAXCONTLINE=%d characters.\n", lineno, (int)contlineno, configfile, (int)MAXCONTLINE); return -1; } // copy string so far into fullline, and increment length snprintf(fullline+cont, sizeof(fullline)-cont, "%s" ,line); cont+=len; // is this a continuation line. If so, replace \ by space and look at next line if ( (lastslash=strrchr(line,'\\')) && !strtok(lastslash+1," \n\t")){ *(fullline+(cont-len)+(lastslash-line))=' '; continue; } // Not a continuation line. Parse it scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline); // did we find a scandevice directive? if (scandevice==-1) return 0; // did we find a syntax error if (scandevice==-2) return -1; entry+=scandevice; lineno++; cont=0; } // note -- may be zero if syntax of file OK, but no valid entries! return entry; } /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> <=======\n", where <LIST> is the list of valid arguments for option opt. */ static void PrintValidArgs(char opt) { const char *s; PrintOut(LOG_CRIT, "=======> VALID ARGUMENTS ARE: "); if (!(s = GetValidArgList(opt))) PrintOut(LOG_CRIT, "Error constructing argument list for option %c", opt); else PrintOut(LOG_CRIT, "%s", (char *)s); PrintOut(LOG_CRIT, " <=======\n"); } #ifndef _WIN32 // Report error and exit if specified path is not absolute. static void check_abs_path(char option, const std::string & path) { if (path.empty() || path[0] == '/') return; debugmode = 1; PrintHead(); PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <=======\n\n", option, path.c_str()); PrintOut(LOG_CRIT, "Error: relative path names are not allowed\n\n"); EXIT(EXIT_BADCMD); } #endif // !_WIN32 // Parses input line, prints usage message and // version/license/copyright messages static void ParseOpts(int argc, char **argv) { // Init default path names #ifndef _WIN32 configfile = SMARTMONTOOLS_SYSCONFDIR"/smartd.conf"; warning_script = SMARTMONTOOLS_SYSCONFDIR"/smartd_warning.sh"; #else std::string exedir = get_exe_dir(); static std::string configfile_str = exedir + "/smartd.conf"; configfile = configfile_str.c_str(); warning_script = exedir + "/smartd_warning.cmd"; #endif // Please update GetValidArgList() if you edit shortopts static const char shortopts[] = "c:l:q:dDni:p:r:s:A:B:w:Vh?" #ifdef HAVE_LIBCAP_NG "C" #endif ; // Please update GetValidArgList() if you edit longopts struct option longopts[] = { { "configfile", required_argument, 0, 'c' }, { "logfacility", required_argument, 0, 'l' }, { "quit", required_argument, 0, 'q' }, { "debug", no_argument, 0, 'd' }, { "showdirectives", no_argument, 0, 'D' }, { "interval", required_argument, 0, 'i' }, #ifndef _WIN32 { "no-fork", no_argument, 0, 'n' }, #else { "service", no_argument, 0, 'n' }, #endif { "pidfile", required_argument, 0, 'p' }, { "report", required_argument, 0, 'r' }, { "savestates", required_argument, 0, 's' }, { "attributelog", required_argument, 0, 'A' }, { "drivedb", required_argument, 0, 'B' }, { "warnexec", required_argument, 0, 'w' }, { "version", no_argument, 0, 'V' }, { "license", no_argument, 0, 'V' }, { "copyright", no_argument, 0, 'V' }, { "help", no_argument, 0, 'h' }, { "usage", no_argument, 0, 'h' }, #ifdef HAVE_LIBCAP_NG { "capabilities", no_argument, 0, 'C' }, #endif { 0, 0, 0, 0 } }; opterr=optopt=0; bool badarg = false; bool no_defaultdb = false; // set true on '-B FILE' // Parse input options. int optchar; while ((optchar = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { char *arg; char *tailptr; long lchecktime; switch(optchar) { case 'q': // when to quit if (!(strcmp(optarg,"nodev"))) { quit=0; } else if (!(strcmp(optarg,"nodevstartup"))) { quit=1; } else if (!(strcmp(optarg,"never"))) { quit=2; } else if (!(strcmp(optarg,"onecheck"))) { quit=3; debugmode=1; } else if (!(strcmp(optarg,"showtests"))) { quit=4; debugmode=1; } else if (!(strcmp(optarg,"errors"))) { quit=5; } else { badarg = true; } break; case 'l': // set the log facility level if (!strcmp(optarg, "daemon")) facility=LOG_DAEMON; else if (!strcmp(optarg, "local0")) facility=LOG_LOCAL0; else if (!strcmp(optarg, "local1")) facility=LOG_LOCAL1; else if (!strcmp(optarg, "local2")) facility=LOG_LOCAL2; else if (!strcmp(optarg, "local3")) facility=LOG_LOCAL3; else if (!strcmp(optarg, "local4")) facility=LOG_LOCAL4; else if (!strcmp(optarg, "local5")) facility=LOG_LOCAL5; else if (!strcmp(optarg, "local6")) facility=LOG_LOCAL6; else if (!strcmp(optarg, "local7")) facility=LOG_LOCAL7; else badarg = true; break; case 'd': // enable debug mode debugmode = 1; break; case 'n': // don't fork() #ifndef _WIN32 // On Windows, --service is already handled by daemon_main() do_fork = false; #endif break; case 'D': // print summary of all valid directives debugmode = 1; Directives(); EXIT(0); break; case 'i': // Period (time interval) for checking // strtol will set errno in the event of overflow, so we'll check it. errno = 0; lchecktime = strtol(optarg, &tailptr, 10); if (*tailptr != '\0' || lchecktime < 10 || lchecktime > INT_MAX || errno) { debugmode=1; PrintHead(); PrintOut(LOG_CRIT, "======> INVALID INTERVAL: %s <=======\n", optarg); PrintOut(LOG_CRIT, "======> INTERVAL MUST BE INTEGER BETWEEN %d AND %d <=======\n", 10, INT_MAX); PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n"); EXIT(EXIT_BADCMD); } checktime = (int)lchecktime; break; case 'r': // report IOCTL transactions { int i; char *s; // split_report_arg() may modify its first argument string, so use a // copy of optarg in case we want optarg for an error message. if (!(s = strdup(optarg))) { PrintOut(LOG_CRIT, "No memory to process -r option - exiting\n"); EXIT(EXIT_NOMEM); } if (split_report_arg(s, &i)) { badarg = true; } else if (i<1 || i>3) { debugmode=1; PrintHead(); PrintOut(LOG_CRIT, "======> INVALID REPORT LEVEL: %s <=======\n", optarg); PrintOut(LOG_CRIT, "======> LEVEL MUST BE INTEGER BETWEEN 1 AND 3<=======\n"); EXIT(EXIT_BADCMD); } else if (!strcmp(s,"ioctl")) { ata_debugmode = scsi_debugmode = i; } else if (!strcmp(s,"ataioctl")) { ata_debugmode = i; } else if (!strcmp(s,"scsiioctl")) { scsi_debugmode = i; } else { badarg = true; } free(s); // TODO: use std::string } break; case 'c': // alternate configuration file if (strcmp(optarg,"-")) configfile = (configfile_alt = optarg).c_str(); else // read from stdin configfile=configfile_stdin; break; case 'p': // output file with PID number pid_file = optarg; break; case 's': // path prefix of persistent state file state_path_prefix = optarg; break; case 'A': // path prefix of attribute log file attrlog_path_prefix = optarg; break; case 'B': { const char * path = optarg; if (*path == '+' && path[1]) path++; else no_defaultdb = true; unsigned char savedebug = debugmode; debugmode = 1; if (!read_drive_database(path)) EXIT(EXIT_BADCMD); debugmode = savedebug; } break; case 'w': warning_script = optarg; break; case 'V': // print version and CVS info debugmode = 1; PrintOut(LOG_INFO, "%s", format_version_info("smartd", true /*full*/).c_str()); EXIT(0); break; #ifdef HAVE_LIBCAP_NG case 'C': // enable capabilities enable_capabilities = true; break; #endif case 'h': // help: print summary of command-line options debugmode=1; PrintHead(); Usage(); EXIT(0); break; case '?': default: // unrecognized option debugmode=1; PrintHead(); // Point arg to the argument in which this option was found. arg = argv[optind-1]; // Check whether the option is a long option that doesn't map to -h. if (arg[1] == '-' && optchar != 'h') { // Iff optopt holds a valid option then argument must be missing. if (optopt && (strchr(shortopts, optopt) != NULL)) { PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %s <=======\n",arg+2); PrintValidArgs(optopt); } else { PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %s <=======\n\n",arg+2); } PrintOut(LOG_CRIT, "\nUse smartd --help to get a usage summary\n\n"); EXIT(EXIT_BADCMD); } if (optopt) { // Iff optopt holds a valid option then argument must be missing. if (strchr(shortopts, optopt) != NULL){ PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %c <=======\n",optopt); PrintValidArgs(optopt); } else { PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %c <=======\n\n",optopt); } PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n"); EXIT(EXIT_BADCMD); } Usage(); EXIT(0); } // Check to see if option had an unrecognized or incorrect argument. if (badarg) { debugmode=1; PrintHead(); // It would be nice to print the actual option name given by the user // here, but we just print the short form. Please fix this if you know // a clean way to do it. PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <======= \n", optchar, optarg); PrintValidArgs(optchar); PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n"); EXIT(EXIT_BADCMD); } } // non-option arguments are not allowed if (argc > optind) { debugmode=1; PrintHead(); PrintOut(LOG_CRIT, "=======> UNRECOGNIZED ARGUMENT: %s <=======\n\n", argv[optind]); PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n"); EXIT(EXIT_BADCMD); } // no pidfile in debug mode if (debugmode && !pid_file.empty()) { debugmode=1; PrintHead(); PrintOut(LOG_CRIT, "=======> INVALID CHOICE OF OPTIONS: -d and -p <======= \n\n"); PrintOut(LOG_CRIT, "Error: pid file %s not written in debug (-d) mode\n\n", pid_file.c_str()); EXIT(EXIT_BADCMD); } #ifndef _WIN32 if (!debugmode) { // absolute path names are required due to chdir('/') after fork(). check_abs_path('p', pid_file); check_abs_path('s', state_path_prefix); check_abs_path('A', attrlog_path_prefix); } #endif // Read or init drive database if (!no_defaultdb) { unsigned char savedebug = debugmode; debugmode = 1; if (!read_default_drive_databases()) EXIT(EXIT_BADCMD); debugmode = savedebug; } // print header PrintHead(); } // Function we call if no configuration file was found or if the // SCANDIRECTIVE Directive was found. It makes entries for device // names returned by scan_smart_devices() in os_OSNAME.cpp static int MakeConfigEntries(const dev_config & base_cfg, dev_config_vector & conf_entries, smart_device_list & scanned_devs, const char * type) { // make list of devices smart_device_list devlist; if (!smi()->scan_smart_devices(devlist, (*type ? type : 0))) PrintOut(LOG_CRIT,"Problem creating device name scan list\n"); // if no devices, or error constructing list, return if (devlist.size() <= 0) return 0; // add empty device slots for existing config entries while (scanned_devs.size() < conf_entries.size()) scanned_devs.push_back((smart_device *)0); // loop over entries to create for (unsigned i = 0; i < devlist.size(); i++) { // Move device pointer smart_device * dev = devlist.release(i); scanned_devs.push_back(dev); // Copy configuration, update device and type name conf_entries.push_back(base_cfg); dev_config & cfg = conf_entries.back(); cfg.name = dev->get_info().info_name; cfg.dev_name = dev->get_info().dev_name; cfg.dev_type = type; } return devlist.size(); } static void CanNotRegister(const char *name, const char *type, int line, bool scandirective) { if (!debugmode && scandirective) return; if (line) PrintOut(scandirective?LOG_INFO:LOG_CRIT, "Unable to register %s device %s at line %d of file %s\n", type, name, line, configfile); else PrintOut(LOG_INFO,"Unable to register %s device %s\n", type, name); return; } // Returns negative value (see ParseConfigFile()) if config file // had errors, else number of entries which may be zero or positive. static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_device_list & scanned_devs) { // parse configuration file configfile (normally /etc/smartd.conf) int entries = ParseConfigFile(conf_entries); if (entries < 0) { // There was an error reading the configuration file. conf_entries.clear(); if (entries == -1) PrintOut(LOG_CRIT, "Configuration file %s has fatal syntax errors.\n", configfile); return entries; } // no error parsing config file. if (entries) { // we did not find a SCANDIRECTIVE and did find valid entries PrintOut(LOG_INFO, "Configuration file %s parsed.\n", configfile); } else if (!conf_entries.empty()) { // we found a SCANDIRECTIVE or there was no configuration file so // scan. Configuration file's last entry contains all options // that were set dev_config first = conf_entries.back(); conf_entries.pop_back(); if (first.lineno) PrintOut(LOG_INFO,"Configuration file %s was parsed, found %s, scanning devices\n", configfile, SCANDIRECTIVE); else PrintOut(LOG_INFO,"No configuration file %s found, scanning devices\n", configfile); // make config list of devices to search for MakeConfigEntries(first, conf_entries, scanned_devs, first.dev_type.c_str()); // warn user if scan table found no devices if (conf_entries.empty()) PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n"); } else PrintOut(LOG_CRIT,"Configuration file %s parsed but has no entries (like /dev/hda)\n",configfile); return conf_entries.size(); } // Return true if TYPE contains a RAID drive number static bool is_raid_type(const char * type) { if (str_starts_with(type, "sat,")) return false; int i; if (sscanf(type, "%*[^,],%d", &i) != 1) return false; return true; } // Return true if DEV is already in DEVICES[0..NUMDEVS) or IGNORED[*] static bool is_duplicate_device(const smart_device * dev, const smart_device_list & devices, unsigned numdevs, const dev_config_vector & ignored) { const smart_device::device_info & info1 = dev->get_info(); bool is_raid1 = is_raid_type(info1.dev_type.c_str()); for (unsigned i = 0; i < numdevs; i++) { const smart_device::device_info & info2 = devices.at(i)->get_info(); // -d TYPE options must match if RAID drive number is specified if ( info1.dev_name == info2.dev_name && ( info1.dev_type == info2.dev_type || !is_raid1 || !is_raid_type(info2.dev_type.c_str()))) return true; } for (unsigned i = 0; i < ignored.size(); i++) { const dev_config & cfg2 = ignored.at(i); if ( info1.dev_name == cfg2.dev_name && ( info1.dev_type == cfg2.dev_type || !is_raid1 || !is_raid_type(cfg2.dev_type.c_str()))) return true; } return false; } // This function tries devices from conf_entries. Each one that can be // registered is moved onto the [ata|scsi]devices lists and removed // from the conf_entries list. static void RegisterDevices(const dev_config_vector & conf_entries, smart_device_list & scanned_devs, dev_config_vector & configs, dev_state_vector & states, smart_device_list & devices) { // start by clearing lists/memory of ALL existing devices configs.clear(); devices.clear(); states.clear(); // Register entries dev_config_vector ignored_entries; unsigned numnoscan = 0; for (unsigned i = 0; i < conf_entries.size(); i++){ dev_config cfg = conf_entries[i]; if (cfg.ignore) { // Store for is_duplicate_device() check and ignore PrintOut(LOG_INFO, "Device: %s%s%s%s, ignored\n", cfg.name.c_str(), (!cfg.dev_type.empty() ? " [" : ""), cfg.dev_type.c_str(), (!cfg.dev_type.empty() ? "]" : "")); ignored_entries.push_back(cfg); continue; } // get device of appropriate type smart_device_auto_ptr dev; bool scanning = false; // Device may already be detected during devicescan if (i < scanned_devs.size()) { dev = scanned_devs.release(i); if (dev) { // Check for a preceding non-DEVICESCAN entry for the same device if ( (numnoscan || !ignored_entries.empty()) && is_duplicate_device(dev.get(), devices, numnoscan, ignored_entries)) { PrintOut(LOG_INFO, "Device: %s, duplicate, ignored\n", dev->get_info_name()); continue; } scanning = true; } } if (!dev) { dev = smi()->get_smart_device(cfg.name.c_str(), cfg.dev_type.c_str()); if (!dev) { if (cfg.dev_type.empty()) PrintOut(LOG_INFO,"Device: %s, unable to autodetect device type\n", cfg.name.c_str()); else PrintOut(LOG_INFO,"Device: %s, unsupported device type '%s'\n", cfg.name.c_str(), cfg.dev_type.c_str()); continue; } } // Save old info smart_device::device_info oldinfo = dev->get_info(); // Open with autodetect support, may return 'better' device dev.replace( dev->autodetect_open() ); // Report if type has changed if (oldinfo.dev_type != dev->get_dev_type()) PrintOut(LOG_INFO,"Device: %s, type changed from '%s' to '%s'\n", cfg.name.c_str(), oldinfo.dev_type.c_str(), dev->get_dev_type()); if (!dev->is_open()) { // For linux+devfs, a nonexistent device gives a strange error // message. This makes the error message a bit more sensible. // If no debug and scanning - don't print errors if (debugmode || !scanning) PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", dev->get_info_name(), dev->get_errmsg()); continue; } // Update informal name cfg.name = dev->get_info().info_name; PrintOut(LOG_INFO, "Device: %s, opened\n", cfg.name.c_str()); // Prepare initial state dev_state state; // register ATA devices if (dev->is_ata()){ if (ATADeviceScan(cfg, state, dev->to_ata())) { CanNotRegister(cfg.name.c_str(), "ATA", cfg.lineno, scanning); dev.reset(); } } // or register SCSI devices else if (dev->is_scsi()){ if (SCSIDeviceScan(cfg, state, dev->to_scsi())) { CanNotRegister(cfg.name.c_str(), "SCSI", cfg.lineno, scanning); dev.reset(); } } else { PrintOut(LOG_INFO, "Device: %s, neither ATA nor SCSI device\n", cfg.name.c_str()); dev.reset(); } if (dev) { // move onto the list of devices configs.push_back(cfg); states.push_back(state); devices.push_back(dev); if (!scanning) numnoscan = devices.size(); } // if device is explictly listed and we can't register it, then // exit unless the user has specified that the device is removable else if (!scanning) { if (cfg.removable || quit==2) PrintOut(LOG_INFO, "Device %s not available\n", cfg.name.c_str()); else { PrintOut(LOG_CRIT, "Unable to register device %s (no Directive -d removable). Exiting.\n", cfg.name.c_str()); EXIT(EXIT_BADDEV); } } } init_disable_standby_check(configs); } // Main program without exception handling static int main_worker(int argc, char **argv) { // Initialize interface smart_interface::init(); if (!smi()) return 1; // is it our first pass through? bool firstpass = true; // next time to wake up time_t wakeuptime = 0; // parse input and print header and usage info if needed ParseOpts(argc,argv); // Configuration for each device dev_config_vector configs; // Device states dev_state_vector states; // Devices to monitor smart_device_list devices; bool write_states_always = true; #ifdef HAVE_LIBCAP_NG // Drop capabilities if (enable_capabilities) { capng_clear(CAPNG_SELECT_BOTH); capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE|CAPNG_PERMITTED), CAP_SYS_ADMIN, CAP_MKNOD, CAP_SYS_RAWIO, -1); capng_apply(CAPNG_SELECT_BOTH); } #endif // the main loop of the code for (;;) { // are we exiting from a signal? if (caughtsigEXIT) { // are we exiting with SIGTERM? int isterm=(caughtsigEXIT==SIGTERM); int isquit=(caughtsigEXIT==SIGQUIT); int isok=debugmode?isterm || isquit:isterm; PrintOut(isok?LOG_INFO:LOG_CRIT, "smartd received signal %d: %s\n", caughtsigEXIT, strsignal(caughtsigEXIT)); if (!isok) return EXIT_SIGNAL; // Write state files if (!state_path_prefix.empty()) write_all_dev_states(configs, states); return 0; } // Should we (re)read the config file? if (firstpass || caughtsigHUP){ if (!firstpass) { // Write state files if (!state_path_prefix.empty()) write_all_dev_states(configs, states); PrintOut(LOG_INFO, caughtsigHUP==1? "Signal HUP - rereading configuration file %s\n": "\a\nSignal INT - rereading configuration file %s ("SIGQUIT_KEYNAME" quits)\n\n", configfile); } { dev_config_vector conf_entries; // Entries read from smartd.conf smart_device_list scanned_devs; // Devices found during scan // (re)reads config file, makes >=0 entries int entries = ReadOrMakeConfigEntries(conf_entries, scanned_devs); if (entries>=0) { // checks devices, then moves onto ata/scsi list or deallocates. RegisterDevices(conf_entries, scanned_devs, configs, states, devices); if (!(configs.size() == devices.size() && configs.size() == states.size())) throw std::logic_error("Invalid result from RegisterDevices"); } else if (quit==2 || ((quit==0 || quit==1) && !firstpass)) { // user has asked to continue on error in configuration file if (!firstpass) PrintOut(LOG_INFO,"Reusing previous configuration\n"); } else { // exit with configuration file error status return (entries==-3 ? EXIT_READCONF : entries==-2 ? EXIT_NOCONF : EXIT_BADCONF); } } // Log number of devices we are monitoring... if (devices.size() > 0 || quit==2 || (quit==1 && !firstpass)) { int numata = 0; for (unsigned i = 0; i < devices.size(); i++) { if (devices.at(i)->is_ata()) numata++; } PrintOut(LOG_INFO,"Monitoring %d ATA and %d SCSI devices\n", numata, devices.size() - numata); } else { PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n"); return EXIT_NODEV; } if (quit==4) { // user has asked to print test schedule PrintTestSchedule(configs, states, devices); return 0; } #ifdef HAVE_LIBCAP_NG if (enable_capabilities) { for (unsigned i = 0; i < configs.size(); i++) { if (!configs[i].emailaddress.empty() || !configs[i].emailcmdline.empty()) { PrintOut(LOG_WARNING, "Mail can't be enabled together with --capabilities. All mail will be suppressed.\n"); break; } } } #endif // reset signal caughtsigHUP=0; // Always write state files after (re)configuration write_states_always = true; } // check all devices once, // self tests are not started in first pass unless '-q onecheck' is specified CheckDevicesOnce(configs, states, devices, firstpass, (!firstpass || quit==3)); // Write state files if (!state_path_prefix.empty()) write_all_dev_states(configs, states, write_states_always); write_states_always = false; // Write attribute logs if (!attrlog_path_prefix.empty()) write_all_dev_attrlogs(configs, states); // user has asked us to exit after first check if (quit==3) { PrintOut(LOG_INFO,"Started with '-q onecheck' option. All devices sucessfully checked once.\n" "smartd is exiting (exit status 0)\n"); return 0; } // fork into background if needed if (firstpass && !debugmode) { DaemonInit(); } // set exit and signal handlers, write PID file, set wake-up time if (firstpass){ Initialize(&wakeuptime); firstpass = false; } // sleep until next check time, or a signal arrives wakeuptime = dosleep(wakeuptime, write_states_always); } } #ifndef _WIN32 // Main program int main(int argc, char **argv) #else // Windows: internal main function started direct or by service control manager static int smartd_main(int argc, char **argv) #endif { int status; try { // Do the real work ... status = main_worker(argc, argv); } catch (int ex) { // EXIT(status) arrives here status = ex; } catch (const std::bad_alloc & /*ex*/) { // Memory allocation failed (also thrown by std::operator new) PrintOut(LOG_CRIT, "Smartd: Out of memory\n"); status = EXIT_NOMEM; } catch (const std::exception & ex) { // Other fatal errors PrintOut(LOG_CRIT, "Smartd: Exception: %s\n", ex.what()); status = EXIT_BADCODE; } if (is_initialized) status = Goodbye(status); #ifdef _WIN32 daemon_winsvc_exitcode = status; #endif return status; } #ifdef _WIN32 // Main function for Windows int main(int argc, char **argv){ // Options for smartd windows service static const daemon_winsvc_options svc_opts = { "--service", // cmd_opt "smartd", "SmartD Service", // servicename, displayname // description "Controls and monitors storage devices using the Self-Monitoring, " "Analysis and Reporting Technology System (S.M.A.R.T.) " "built into ATA and SCSI Hard Drives. " PACKAGE_HOMEPAGE }; // daemon_main() handles daemon and service specific commands // and starts smartd_main() direct, from a new process, // or via service control manager return daemon_main("smartd", &svc_opts , smartd_main, argc, argv); } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/megaraid.h�����������������������������������������������������������0000644�0000000�0000000�00000013517�12063433463�017016� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������int megaraid_io_interface(int device, int target, struct scsi_cmnd_io *, int); #undef u32 #define u8 uint8_t #define u16 uint16_t #define u32 uint32_t #define u64 uint64_t /*====================================================== * PERC2/3/4 Passthrough SCSI Command Interface * * Contents from: * drivers/scsi/megaraid/megaraid_ioctl.h * drivers/scsi/megaraid/mbox_defs.h *======================================================*/ #define MEGAIOC_MAGIC 'm' #define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0, struct uioctl_t) /* Following subopcode work for opcode == 0x82 */ #define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | adapno) #define MEGAIOC_QNADAP 'm' #define MEGAIOC_QDRVRVER 'e' #define MEGAIOC_QADAPINFO 'g' #define MEGA_MBOXCMD_PASSTHRU 0x03 #define MAX_REQ_SENSE_LEN 0x20 #define MAX_CDB_LEN 10 typedef struct { uint8_t timeout : 3; uint8_t ars : 1; uint8_t reserved : 3; uint8_t islogical : 1; uint8_t logdrv; uint8_t channel; uint8_t target; uint8_t queuetag; uint8_t queueaction; uint8_t cdb[MAX_CDB_LEN]; uint8_t cdblen; uint8_t reqsenselen; uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; uint8_t numsgelements; uint8_t scsistatus; uint32_t dataxferaddr; uint32_t dataxferlen; } __attribute__((packed)) mega_passthru; typedef struct { uint8_t cmd; uint8_t cmdid; uint8_t opcode; uint8_t subopcode; uint32_t lba; uint32_t xferaddr; uint8_t logdrv; uint8_t resvd[3]; uint8_t numstatus; uint8_t status; } __attribute__((packed)) megacmd_t; typedef union { uint8_t *pointer; uint8_t pad[8]; } ptr_t; // The above definition assumes sizeof(void*) <= 8. // This assumption also exists in the linux megaraid device driver. // So define a macro to check expected size of ptr_t at compile time using // a dummy typedef. On size mismatch, compiler reports a negative array // size. If you see an error message of this form, it means that // you have an unexpected pointer size on your platform and can not // use megaraid support in smartmontools. typedef char assert_sizeof_ptr_t[sizeof(ptr_t) == 8 ? 1 : -1]; struct uioctl_t { uint32_t inlen; uint32_t outlen; union { uint8_t fca[16]; struct { uint8_t opcode; uint8_t subopcode; uint16_t adapno; ptr_t buffer; uint32_t length; } __attribute__((packed)) fcs; } __attribute__((packed)) ui; megacmd_t mbox; mega_passthru pthru; ptr_t data; } __attribute__((packed)); /*=================================================== * PERC5/6 Passthrough SCSI Command Interface * * Contents from: * drivers/scsi/megaraid/megaraid_sas.h *===================================================*/ #define MEGASAS_MAGIC 'M' #define MEGASAS_IOC_FIRMWARE _IOWR(MEGASAS_MAGIC, 1, struct megasas_iocpacket) #define MFI_CMD_PD_SCSI_IO 0x04 #define MFI_CMD_DCMD 0x05 #define MFI_FRAME_SGL64 0x02 #define MFI_STAT_OK 0x00 #define MFI_DCMD_PD_GET_LIST 0x02010000 /* * Number of mailbox bytes in DCMD message frame */ #define MFI_MBOX_SIZE 12 #define MAX_IOCTL_SGE 16 #define MFI_FRAME_DIR_NONE 0x0000 #define MFI_FRAME_DIR_WRITE 0x0008 #define MFI_FRAME_DIR_READ 0x0010 #define MFI_FRAME_DIR_BOTH 0x0018 #define MAX_SYS_PDS 240 struct megasas_sge32 { u32 phys_addr; u32 length; } __attribute__ ((packed)); struct megasas_sge64 { u64 phys_addr; u32 length; } __attribute__ ((packed)); union megasas_sgl { struct megasas_sge32 sge32[1]; struct megasas_sge64 sge64[1]; } __attribute__ ((packed)); struct megasas_header { u8 cmd; /*00h */ u8 sense_len; /*01h */ u8 cmd_status; /*02h */ u8 scsi_status; /*03h */ u8 target_id; /*04h */ u8 lun; /*05h */ u8 cdb_len; /*06h */ u8 sge_count; /*07h */ u32 context; /*08h */ u32 pad_0; /*0Ch */ u16 flags; /*10h */ u16 timeout; /*12h */ u32 data_xferlen; /*14h */ } __attribute__ ((packed)); struct megasas_pthru_frame { u8 cmd; /*00h */ u8 sense_len; /*01h */ u8 cmd_status; /*02h */ u8 scsi_status; /*03h */ u8 target_id; /*04h */ u8 lun; /*05h */ u8 cdb_len; /*06h */ u8 sge_count; /*07h */ u32 context; /*08h */ u32 pad_0; /*0Ch */ u16 flags; /*10h */ u16 timeout; /*12h */ u32 data_xfer_len; /*14h */ u32 sense_buf_phys_addr_lo; /*18h */ u32 sense_buf_phys_addr_hi; /*1Ch */ u8 cdb[16]; /*20h */ union megasas_sgl sgl; /*30h */ } __attribute__ ((packed)); struct megasas_dcmd_frame { u8 cmd; /*00h */ u8 reserved_0; /*01h */ u8 cmd_status; /*02h */ u8 reserved_1[4]; /*03h */ u8 sge_count; /*07h */ u32 context; /*08h */ u32 pad_0; /*0Ch */ u16 flags; /*10h */ u16 timeout; /*12h */ u32 data_xfer_len; /*14h */ u32 opcode; /*18h */ union { /*1Ch */ u8 b[12]; u16 s[6]; u32 w[3]; } mbox; union megasas_sgl sgl; /*28h */ } __attribute__ ((packed)); struct megasas_iocpacket { u16 host_no; u16 __pad1; u32 sgl_off; u32 sge_count; u32 sense_off; u32 sense_len; union { u8 raw[128]; struct megasas_header hdr; struct megasas_pthru_frame pthru; struct megasas_dcmd_frame dcmd; } frame; struct iovec sgl[MAX_IOCTL_SGE]; } __attribute__ ((packed)); struct megasas_pd_address { u16 device_id; u16 encl_device_id; u8 encl_index; u8 slot_number; u8 scsi_dev_type; /* 0 = disk */ u8 connect_port_bitmap; u64 sas_addr[2]; } __attribute__ ((packed)); struct megasas_pd_list { u32 size; u32 count; struct megasas_pd_address addr[MAX_SYS_PDS]; } __attribute__ ((packed)); #undef u8 #undef u16 #undef u32 #undef u64 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/ataidentify.h��������������������������������������������������������0000644�0000000�0000000�00000001437�12026705067�017545� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ataidentify.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef ATAIDENTIFY_H #define ATAIDENTIFY_H #define ATAIDENTIFY_H_CVSID "$Id: ataidentify.h 3610 2012-09-20 21:27:19Z chrfranke $" void ata_print_identify_data(const void * id, bool all_words, int bit_level); #endif // ATAIDENTIFY_H ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartd.conf����������������������������������������������������������0000644�0000000�0000000�00000015123�12040016050�017210� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Sample configuration file for smartd. See man smartd.conf. # Home page is: http://smartmontools.sourceforge.net # $Id: smartd.conf 3651 2012-10-18 15:11:36Z samm2 $ # smartd will re-read the configuration file if it receives a HUP # signal # The file gives a list of devices to monitor using smartd, with one # device per line. Text after a hash (#) is ignored, and you may use # spaces and tabs for white space. You may use '\' to continue lines. # You can usually identify which hard disks are on your system by # looking in /proc/ide and in /proc/scsi. # The word DEVICESCAN will cause any remaining lines in this # configuration file to be ignored: it tells smartd to scan for all # ATA and SCSI devices. DEVICESCAN may be followed by any of the # Directives listed below, which will be applied to all devices that # are found. Most users should comment out DEVICESCAN and explicitly # list the devices that they wish to monitor. DEVICESCAN # Alternative setting to ignore temperature and power-on hours reports # in syslog. #DEVICESCAN -I 194 -I 231 -I 9 # Alternative setting to report more useful raw temperature in syslog. #DEVICESCAN -R 194 -R 231 -I 9 # Alternative setting to report raw temperature changes >= 5 Celsius # and min/max temperatures. #DEVICESCAN -I 194 -I 231 -I 9 -W 5 # First (primary) ATA/IDE hard disk. Monitor all attributes, enable # automatic online data collection, automatic Attribute autosave, and # start a short self-test every day between 2-3am, and a long self test # Saturdays between 3-4am. #/dev/hda -a -o on -S on -s (S/../.././02|L/../../6/03) # Monitor SMART status, ATA Error Log, Self-test log, and track # changes in all attributes except for attribute 194 #/dev/hdb -H -l error -l selftest -t -I 194 # Monitor all attributes except normalized Temperature (usually 194), # but track Temperature changes >= 4 Celsius, report Temperatures # >= 45 Celsius and changes in Raw value of Reallocated_Sector_Ct (5). # Send mail on SMART failures or when Temperature is >= 55 Celsius. #/dev/hdc -a -I 194 -W 4,45,55 -R 5 -m admin@example.com # An ATA disk may appear as a SCSI device to the OS. If a SCSI to # ATA Translation (SAT) layer is between the OS and the device then # this can be flagged with the '-d sat' option. This situation may # become common with SATA disks in SAS and FC environments. # /dev/sda -a -d sat # A very silent check. Only report SMART health status if it fails # But send an email in this case #/dev/hdc -H -C 0 -U 0 -m admin@example.com # First two SCSI disks. This will monitor everything that smartd can # monitor. Start extended self-tests Wednesdays between 6-7pm and # Sundays between 1-2 am #/dev/sda -d scsi -s L/../../3/18 #/dev/sdb -d scsi -s L/../../7/01 # Monitor 4 ATA disks connected to a 3ware 6/7/8000 controller which uses # the 3w-xxxx driver. Start long self-tests Sundays between 1-2, 2-3, 3-4, # and 4-5 am. # NOTE: starting with the Linux 2.6 kernel series, the /dev/sdX interface # is DEPRECATED. Use the /dev/tweN character device interface instead. # For example /dev/twe0, /dev/twe1, and so on. #/dev/sdc -d 3ware,0 -a -s L/../../7/01 #/dev/sdc -d 3ware,1 -a -s L/../../7/02 #/dev/sdc -d 3ware,2 -a -s L/../../7/03 #/dev/sdc -d 3ware,3 -a -s L/../../7/04 # Monitor 2 ATA disks connected to a 3ware 9000 controller which # uses the 3w-9xxx driver (Linux, FreeBSD). Start long self-tests Tuesdays # between 1-2 and 3-4 am. #/dev/twa0 -d 3ware,0 -a -s L/../../2/01 #/dev/twa0 -d 3ware,1 -a -s L/../../2/03 # Monitor 2 SATA (not SAS) disks connected to a 3ware 9000 controller which # uses the 3w-sas driver (Linux). Start long self-tests Tuesdays # between 1-2 and 3-4 am. # On FreeBSD /dev/tws0 should be used instead #/dev/twl0 -d 3ware,0 -a -s L/../../2/01 #/dev/twl0 -d 3ware,1 -a -s L/../../2/03 # Same as above for Windows. Option '-d 3ware,N' is not necessary, # disk (port) number is specified in device name. # NOTE: On Windows, DEVICESCAN works also for 3ware controllers. #/dev/hdc,0 -a -s L/../../2/01 #/dev/hdc,1 -a -s L/../../2/03 # Monitor 3 ATA disks directly connected to a HighPoint RocketRAID. Start long # self-tests Sundays between 1-2, 2-3, and 3-4 am. #/dev/sdd -d hpt,1/1 -a -s L/../../7/01 #/dev/sdd -d hpt,1/2 -a -s L/../../7/02 #/dev/sdd -d hpt,1/3 -a -s L/../../7/03 # Monitor 2 ATA disks connected to the same PMPort which connected to the # HighPoint RocketRAID. Start long self-tests Tuesdays between 1-2 and 3-4 am #/dev/sdd -d hpt,1/4/1 -a -s L/../../2/01 #/dev/sdd -d hpt,1/4/2 -a -s L/../../2/03 # HERE IS A LIST OF DIRECTIVES FOR THIS CONFIGURATION FILE. # PLEASE SEE THE smartd.conf MAN PAGE FOR DETAILS # # -d TYPE Set the device type: ata, scsi, marvell, removable, 3ware,N, hpt,L/M/N # -T TYPE set the tolerance to one of: normal, permissive # -o VAL Enable/disable automatic offline tests (on/off) # -S VAL Enable/disable attribute autosave (on/off) # -n MODE No check. MODE is one of: never, sleep, standby, idle # -H Monitor SMART Health Status, report if failed # -l TYPE Monitor SMART log. Type is one of: error, selftest # -f Monitor for failure of any 'Usage' Attributes # -m ADD Send warning email to ADD for -H, -l error, -l selftest, and -f # -M TYPE Modify email warning behavior (see man page) # -s REGE Start self-test when type/date matches regular expression (see man page) # -p Report changes in 'Prefailure' Normalized Attributes # -u Report changes in 'Usage' Normalized Attributes # -t Equivalent to -p and -u Directives # -r ID Also report Raw values of Attribute ID with -p, -u or -t # -R ID Track changes in Attribute ID Raw value with -p, -u or -t # -i ID Ignore Attribute ID for -f Directive # -I ID Ignore Attribute ID for -p, -u or -t Directive # -C ID Report if Current Pending Sector count non-zero # -U ID Report if Offline Uncorrectable count non-zero # -W D,I,C Monitor Temperature D)ifference, I)nformal limit, C)ritical limit # -v N,ST Modifies labeling of Attribute N (see man page) # -a Default: equivalent to -H -f -t -l error -l selftest -C 197 -U 198 # -F TYPE Use firmware bug workaround. Type is one of: none, samsung # -P TYPE Drive-specific presets: use, ignore, show, showall # # Comment: text after a hash sign is ignored # \ Line continuation character # Attribute ID is a decimal integer 1 <= ID <= 255 # except for -C and -U, where ID = 0 turns them off. # All but -d, -m and -M Directives are only implemented for ATA devices # # If the test string DEVICESCAN is the first uncommented text # then smartd will scan for devices /dev/hd[a-l] and /dev/sd[a-z] # DEVICESCAN may be followed by any desired Directives. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/scsicmds.cpp���������������������������������������������������������0000644�0000000�0000000�00000303351�12157546226�017414� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * scsicmds.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * * Additional SCSI work: * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * * * In the SCSI world "SMART" is a dead or withdrawn standard. In recent * SCSI standards (since SCSI-3) it goes under the awkward name of * "Informational Exceptions" ["IE" or "IEC" (with the "C" for "control")]. * The relevant information is spread around several SCSI draft * standards available at http://www.t10.org . Reference is made in the * code to the following acronyms: * - SAM [SCSI Architectural model, versions 2 or 3] * - SPC [SCSI Primary commands, versions 2 or 3] * - SBC [SCSI Block commands, versions 2] * * Some SCSI disk vendors have snippets of "SMART" information in their * product manuals. */ #include <stdio.h> #include <string.h> #include <errno.h> #include <ctype.h> #include "config.h" #include "int64.h" #include "scsicmds.h" #include "atacmds.h" // FIXME: for smart_command_set only #include "dev_interface.h" #include "utility.h" const char *scsicmds_c_cvsid="$Id: scsicmds.cpp 3820 2013-06-17 08:45:10Z samm2 $" SCSICMDS_H_CVSID; // Print SCSI debug messages? unsigned char scsi_debugmode = 0; supported_vpd_pages * supported_vpd_pages_p = NULL; supported_vpd_pages::supported_vpd_pages(scsi_device * device) : num_valid(0) { unsigned char b[0x1fc]; /* size chosen for old INQUIRY command */ int n; memset(b, 0, sizeof(b)); if (device && (0 == scsiInquiryVpd(device, SCSI_VPD_SUPPORTED_VPD_PAGES, b, sizeof(b)))) { num_valid = (b[2] << 8) + b[3]; n = sizeof(pages); if (num_valid > n) num_valid = n; memcpy(pages, b + 4, num_valid); } } bool supported_vpd_pages::is_supported(int vpd_page_num) const { /* Supported VPD pages numbers start at offset 4 and should be in * ascending order but don't assume that. */ for (int k = 0; k < num_valid; ++k) { if (vpd_page_num == pages[k]) return true; } return false; } /* output binary in hex and optionally ascii */ void dStrHex(const char* str, int len, int no_ascii) { const char* p = str; unsigned char c; char buff[82]; int a = 0; const int bpstart = 5; const int cpstart = 60; int cpos = cpstart; int bpos = bpstart; int i, k; if (len <= 0) return; memset(buff,' ',80); buff[80]='\0'; k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a); buff[k + 1] = ' '; if (bpos >= ((bpstart + (9 * 3)))) bpos++; for(i = 0; i < len; i++) { c = *p++; bpos += 3; if (bpos == (bpstart + (9 * 3))) bpos++; snprintf(buff+bpos, sizeof(buff)-bpos, "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; if (no_ascii) buff[cpos++] = ' '; else { if ((c < ' ') || (c >= 0x7f)) c='.'; buff[cpos++] = c; } if (cpos > (cpstart+15)) { pout("%s\n", buff); bpos = bpstart; cpos = cpstart; a += 16; memset(buff,' ',80); k = snprintf(buff+1, sizeof(buff)-1, "%.2x", a); buff[k + 1] = ' '; } } if (cpos > cpstart) { pout("%s\n", buff); } } struct scsi_opcode_name { UINT8 opcode; const char * name; }; static struct scsi_opcode_name opcode_name_arr[] = { /* in ascending opcode order */ {TEST_UNIT_READY, "test unit ready"}, /* 0x00 */ {REQUEST_SENSE, "request sense"}, /* 0x03 */ {INQUIRY, "inquiry"}, /* 0x12 */ {MODE_SELECT, "mode select(6)"}, /* 0x15 */ {MODE_SENSE, "mode sense(6)"}, /* 0x1a */ {START_STOP_UNIT, "start stop unit"}, /* 0x1b */ {RECEIVE_DIAGNOSTIC, "receive diagnostic"}, /* 0x1c */ {SEND_DIAGNOSTIC, "send diagnostic"}, /* 0x1d */ {READ_CAPACITY_10, "read capacity(10)"}, /* 0x25 */ {READ_DEFECT_10, "read defect list(10)"}, /* 0x37 */ {LOG_SELECT, "log select"}, /* 0x4c */ {LOG_SENSE, "log sense"}, /* 0x4d */ {MODE_SELECT_10, "mode select(10)"}, /* 0x55 */ {MODE_SENSE_10, "mode sense(10)"}, /* 0x5a */ {SAT_ATA_PASSTHROUGH_16, "ata pass-through(16)"}, /* 0x85 */ {READ_CAPACITY_16, "read capacity(16)"}, /* 0x9e,0x10 */ {REPORT_LUNS, "report luns"}, /* 0xa0 */ {SAT_ATA_PASSTHROUGH_12, "ata pass-through(12)"}, /* 0xa1 */ {READ_DEFECT_12, "read defect list(12)"}, /* 0xb7 */ }; static const char * vendor_specific = "<vendor specific>"; /* Need to expand to take service action into account. For commands * of interest the service action is in the 2nd command byte */ const char * scsi_get_opcode_name(UINT8 opcode) { int k; int len = sizeof(opcode_name_arr) / sizeof(opcode_name_arr[0]); struct scsi_opcode_name * onp; if (opcode >= 0xc0) return vendor_specific; for (k = 0; k < len; ++k) { onp = &opcode_name_arr[k]; if (opcode == onp->opcode) return onp->name; else if (opcode < onp->opcode) return NULL; } return NULL; } void scsi_do_sense_disect(const struct scsi_cmnd_io * io_buf, struct scsi_sense_disect * out) { int resp_code; memset(out, 0, sizeof(struct scsi_sense_disect)); if (SCSI_STATUS_CHECK_CONDITION == io_buf->scsi_status) { resp_code = (io_buf->sensep[0] & 0x7f); out->resp_code = resp_code; if (resp_code >= 0x72) { out->sense_key = (io_buf->sensep[1] & 0xf); out->asc = io_buf->sensep[2]; out->ascq = io_buf->sensep[3]; } else if (resp_code >= 0x70) { out->sense_key = (io_buf->sensep[2] & 0xf); if (io_buf->resp_sense_len > 13) { out->asc = io_buf->sensep[12]; out->ascq = io_buf->sensep[13]; } } } } int scsiSimpleSenseFilter(const struct scsi_sense_disect * sinfo) { switch (sinfo->sense_key) { case SCSI_SK_NO_SENSE: case SCSI_SK_RECOVERED_ERR: return SIMPLE_NO_ERROR; case SCSI_SK_NOT_READY: if (SCSI_ASC_NO_MEDIUM == sinfo->asc) return SIMPLE_ERR_NO_MEDIUM; else if (SCSI_ASC_NOT_READY == sinfo->asc) { if (0x1 == sinfo->ascq) return SIMPLE_ERR_BECOMING_READY; else return SIMPLE_ERR_NOT_READY; } else return SIMPLE_ERR_NOT_READY; case SCSI_SK_MEDIUM_ERROR: case SCSI_SK_HARDWARE_ERROR: return SIMPLE_ERR_MEDIUM_HARDWARE; case SCSI_SK_ILLEGAL_REQUEST: if (SCSI_ASC_UNKNOWN_OPCODE == sinfo->asc) return SIMPLE_ERR_BAD_OPCODE; else if (SCSI_ASC_INVALID_FIELD == sinfo->asc) return SIMPLE_ERR_BAD_FIELD; else if (SCSI_ASC_UNKNOWN_PARAM == sinfo->asc) return SIMPLE_ERR_BAD_PARAM; else return SIMPLE_ERR_BAD_PARAM; /* all other illegal request */ case SCSI_SK_UNIT_ATTENTION: return SIMPLE_ERR_TRY_AGAIN; case SCSI_SK_ABORTED_COMMAND: return SIMPLE_ERR_ABORTED_COMMAND; default: return SIMPLE_ERR_UNKNOWN; } } const char * scsiErrString(int scsiErr) { if (scsiErr < 0) return strerror(-scsiErr); switch (scsiErr) { case SIMPLE_NO_ERROR: return "no error"; case SIMPLE_ERR_NOT_READY: return "device not ready"; case SIMPLE_ERR_BAD_OPCODE: return "unsupported scsi opcode"; case SIMPLE_ERR_BAD_FIELD: return "unsupported field in scsi command"; case SIMPLE_ERR_BAD_PARAM: return "badly formed scsi parameters"; case SIMPLE_ERR_BAD_RESP: return "scsi response fails sanity test"; case SIMPLE_ERR_NO_MEDIUM: return "no medium present"; case SIMPLE_ERR_BECOMING_READY: return "device will be ready soon"; case SIMPLE_ERR_TRY_AGAIN: return "unit attention reported, try again"; case SIMPLE_ERR_MEDIUM_HARDWARE: return "medium or hardware error (serious)"; case SIMPLE_ERR_UNKNOWN: return "unknown error (unexpected sense key)"; case SIMPLE_ERR_ABORTED_COMMAND: return "aborted command"; default: return "unknown error"; } } /* Iterates to next designation descriptor in the device identification * VPD page. The 'initial_desig_desc' should point to start of first * descriptor with 'page_len' being the number of valid bytes in that * and following descriptors. To start, 'off' should point to a negative * value, thereafter it should point to the value yielded by the previous * call. If 0 returned then 'initial_desig_desc + *off' should be a valid * descriptor; returns -1 if normal end condition and -2 for an abnormal * termination. Matches association, designator_type and/or code_set when * any of those values are greater than or equal to zero. */ int scsi_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len, int * off, int m_assoc, int m_desig_type, int m_code_set) { const unsigned char * ucp; int k, c_set, assoc, desig_type; for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) { k = (k < 0) ? 0 : (k + ucp[k + 3] + 4); if ((k + 4) > page_len) break; c_set = (ucp[k] & 0xf); if ((m_code_set >= 0) && (m_code_set != c_set)) continue; assoc = ((ucp[k + 1] >> 4) & 0x3); if ((m_assoc >= 0) && (m_assoc != assoc)) continue; desig_type = (ucp[k + 1] & 0xf); if ((m_desig_type >= 0) && (m_desig_type != desig_type)) continue; *off = k; return 0; } return (k == page_len) ? -1 : -2; } /* Decode VPD page 0x83 logical unit designator into a string. If both * numeric address and SCSI name string present, prefer the former. * Returns 0 on success, -1 on error with error string in s. */ int scsi_decode_lu_dev_id(const unsigned char * b, int blen, char * s, int slen, int * transport) { int m, c_set, assoc, desig_type, i_len, naa, off, u, have_scsi_ns; const unsigned char * ucp; const unsigned char * ip; int si = 0; if (transport) *transport = -1; if (slen < 32) { if (slen > 0) s[0] = '\0'; return -1; } have_scsi_ns = 0; s[0] = '\0'; off = -1; while ((u = scsi_vpd_dev_id_iter(b, blen, &off, -1, -1, -1)) == 0) { ucp = b + off; i_len = ucp[3]; if ((off + i_len + 4) > blen) { snprintf(s+si, slen-si, "error: designator length"); return -1; } assoc = ((ucp[1] >> 4) & 0x3); if (transport && assoc && (ucp[1] & 0x80) && (*transport < 0)) *transport = (ucp[0] >> 4) & 0xf; if (0 != assoc) continue; ip = ucp + 4; c_set = (ucp[0] & 0xf); desig_type = (ucp[1] & 0xf); switch (desig_type) { case 0: /* vendor specific */ case 1: /* T10 vendor identification */ break; case 2: /* EUI-64 based */ if ((8 != i_len) && (12 != i_len) && (16 != i_len)) { snprintf(s+si, slen-si, "error: EUI-64 length"); return -1; } if (have_scsi_ns) si = 0; si += snprintf(s+si, slen-si, "0x"); for (m = 0; m < i_len; ++m) si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); break; case 3: /* NAA */ if (1 != c_set) { snprintf(s+si, slen-si, "error: NAA bad code_set"); return -1; } naa = (ip[0] >> 4) & 0xff; if ((naa < 2) || (naa > 6) || (4 == naa)) { snprintf(s+si, slen-si, "error: unexpected NAA"); return -1; } if (have_scsi_ns) si = 0; if (2 == naa) { /* NAA IEEE Extended */ if (8 != i_len) { snprintf(s+si, slen-si, "error: NAA 2 length"); return -1; } si += snprintf(s+si, slen-si, "0x"); for (m = 0; m < 8; ++m) si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); } else if ((3 == naa ) || (5 == naa)) { /* NAA=3 Locally assigned; NAA=5 IEEE Registered */ if (8 != i_len) { snprintf(s+si, slen-si, "error: NAA 3 or 5 length"); return -1; } si += snprintf(s+si, slen-si, "0x"); for (m = 0; m < 8; ++m) si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); } else if (6 == naa) { /* NAA IEEE Registered extended */ if (16 != i_len) { snprintf(s+si, slen-si, "error: NAA 6 length"); return -1; } si += snprintf(s+si, slen-si, "0x"); for (m = 0; m < 16; ++m) si += snprintf(s+si, slen-si, "%02x", (unsigned int)ip[m]); } break; case 4: /* Relative target port */ case 5: /* (primary) Target port group */ case 6: /* Logical unit group */ case 7: /* MD5 logical unit identifier */ break; case 8: /* SCSI name string */ if (3 != c_set) { snprintf(s+si, slen-si, "error: SCSI name string"); return -1; } /* does %s print out UTF-8 ok?? */ if (si == 0) { si += snprintf(s+si, slen-si, "%s", (const char *)ip); ++have_scsi_ns; } break; default: /* reserved */ break; } } if (-2 == u) { snprintf(s+si, slen-si, "error: bad structure"); return -1; } return 0; } /* Sends LOG SENSE command. Returns 0 if ok, 1 if device NOT READY, 2 if command not supported, 3 if field (within command) not supported or returns negated errno. SPC-3 sections 6.6 and 7.2 (rec 22a). N.B. Sets PC==1 to fetch "current cumulative" log pages. If known_resp_len > 0 then a single fetch is done for this response length. If known_resp_len == 0 then twin fetches are performed, the first to deduce the response length, then send the same command again requesting the deduced response length. This protects certain fragile HBAs. The twin fetch technique should not be used with the TapeAlert log page since it clears its state flags after each fetch. */ int scsiLogSense(scsi_device * device, int pagenum, int subpagenum, UINT8 *pBuf, int bufLen, int known_resp_len) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[10]; UINT8 sense[32]; int pageLen; int status, res; if (known_resp_len > bufLen) return -EIO; if (known_resp_len > 0) pageLen = known_resp_len; else { /* Starting twin fetch strategy: first fetch to find respone length */ pageLen = 4; if (pageLen > bufLen) return -EIO; else memset(pBuf, 0, pageLen); memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = pageLen; io_hdr.dxferp = pBuf; cdb[0] = LOG_SENSE; cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */ cdb[3] = subpagenum; cdb[7] = (pageLen >> 8) & 0xff; cdb[8] = pageLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); if ((res = scsiSimpleSenseFilter(&sinfo))) return res; /* sanity check on response */ if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum)) return SIMPLE_ERR_BAD_RESP; if (0 == ((pBuf[2] << 8) + pBuf[3])) return SIMPLE_ERR_BAD_RESP; pageLen = (pBuf[2] << 8) + pBuf[3] + 4; if (4 == pageLen) /* why define a lpage with no payload? */ pageLen = 252; /* some IBM tape drives don't like double fetch */ /* some SCSI HBA don't like "odd" length transfers */ if (pageLen % 2) pageLen += 1; if (pageLen > bufLen) pageLen = bufLen; } memset(pBuf, 0, 4); memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = pageLen; io_hdr.dxferp = pBuf; cdb[0] = LOG_SENSE; cdb[2] = 0x40 | (pagenum & 0x3f); /* Page control (PC)==1 */ cdb[7] = (pageLen >> 8) & 0xff; cdb[8] = pageLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); status = scsiSimpleSenseFilter(&sinfo); if (0 != status) return status; /* sanity check on response */ if ((SUPPORTED_LPAGES != pagenum) && ((pBuf[0] & 0x3f) != pagenum)) return SIMPLE_ERR_BAD_RESP; if (0 == ((pBuf[2] << 8) + pBuf[3])) return SIMPLE_ERR_BAD_RESP; return 0; } /* Sends a LOG SELECT command. Can be used to set log page values * or reset one log page (or all of them) to its defaults (typically zero). * Returns 0 if ok, 1 if NOT READY, 2 if command not supported, * 3 if * field in command not supported, * 4 if bad parameter to command or * returns negated errno. SPC-4 sections 6.5 and 7.2 (rev 20) */ int scsiLogSelect(scsi_device * device, int pcr, int sp, int pc, int pagenum, int subpagenum, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[10]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = LOG_SELECT; cdb[1] = (pcr ? 2 : 0) | (sp ? 1 : 0); cdb[2] = ((pc << 6) & 0xc0) | (pagenum & 0x3f); cdb[3] = (subpagenum & 0xff); cdb[7] = ((bufLen >> 8) & 0xff); cdb[8] = (bufLen & 0xff); io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* Send MODE SENSE (6 byte) command. Returns 0 if ok, 1 if NOT READY, * 2 if command not supported (then MODE SENSE(10) should be supported), * 3 if field in command not supported or returns negated errno. * SPC-3 sections 6.9 and 7.4 (rev 22a) [mode subpage==0] */ int scsiModeSense(scsi_device * device, int pagenum, int subpagenum, int pc, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[6]; UINT8 sense[32]; int status; if ((bufLen < 0) || (bufLen > 255)) return -EINVAL; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = MODE_SENSE; cdb[2] = (pc << 6) | (pagenum & 0x3f); cdb[3] = subpagenum; cdb[4] = bufLen; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); status = scsiSimpleSenseFilter(&sinfo); if (SIMPLE_ERR_TRY_AGAIN == status) { if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); status = scsiSimpleSenseFilter(&sinfo); } if ((0 == status) && (ALL_MODE_PAGES != pagenum)) { int offset; offset = scsiModePageOffset(pBuf, bufLen, 0); if (offset < 0) return SIMPLE_ERR_BAD_RESP; else if (pagenum != (pBuf[offset] & 0x3f)) return SIMPLE_ERR_BAD_RESP; } return status; } /* Sends a 6 byte MODE SELECT command. Assumes given pBuf is the response * from a corresponding 6 byte MODE SENSE command. Such a response should * have a 4 byte header followed by 0 or more 8 byte block descriptors * (normally 1) and then 1 mode page. Returns 0 if ok, 1 if NOT READY, * 2 if command not supported (then MODE SELECT(10) may be supported), * 3 if field in command not supported, 4 if bad parameter to command * or returns negated errno. SPC-3 sections 6.7 and 7.4 (rev 22a) */ int scsiModeSelect(scsi_device * device, int sp, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[6]; UINT8 sense[32]; int pg_offset, pg_len, hdr_plus_1_pg; pg_offset = 4 + pBuf[3]; if (pg_offset + 2 >= bufLen) return -EINVAL; pg_len = pBuf[pg_offset + 1] + 2; hdr_plus_1_pg = pg_offset + pg_len; if (hdr_plus_1_pg > bufLen) return -EINVAL; pBuf[0] = 0; /* Length of returned mode sense data reserved for SELECT */ pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */ memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = hdr_plus_1_pg; io_hdr.dxferp = pBuf; cdb[0] = MODE_SELECT; cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */ cdb[4] = hdr_plus_1_pg; /* make sure only one page sent */ io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* MODE SENSE (10 byte). Returns 0 if ok, 1 if NOT READY, 2 if command * not supported (then MODE SENSE(6) might be supported), 3 if field in * command not supported or returns negated errno. * SPC-3 sections 6.10 and 7.4 (rev 22a) [mode subpage==0] */ int scsiModeSense10(scsi_device * device, int pagenum, int subpagenum, int pc, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[10]; UINT8 sense[32]; int status; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = MODE_SENSE_10; cdb[2] = (pc << 6) | (pagenum & 0x3f); cdb[3] = subpagenum; cdb[7] = (bufLen >> 8) & 0xff; cdb[8] = bufLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); status = scsiSimpleSenseFilter(&sinfo); if (SIMPLE_ERR_TRY_AGAIN == status) { if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); status = scsiSimpleSenseFilter(&sinfo); } if ((0 == status) && (ALL_MODE_PAGES != pagenum)) { int offset; offset = scsiModePageOffset(pBuf, bufLen, 1); if (offset < 0) return SIMPLE_ERR_BAD_RESP; else if (pagenum != (pBuf[offset] & 0x3f)) return SIMPLE_ERR_BAD_RESP; } return status; } /* Sends a 10 byte MODE SELECT command. Assumes given pBuf is the response * from a corresponding 10 byte MODE SENSE command. Such a response should * have a 8 byte header followed by 0 or more 8 byte block descriptors * (normally 1) and then 1 mode page. Returns 0 if ok, 1 NOT REAFY, 2 if * command not supported (then MODE SELECT(6) may be supported), 3 if field * in command not supported, 4 if bad parameter to command or returns * negated errno. SPC-3 sections 6.8 and 7.4 (rev 22a) */ int scsiModeSelect10(scsi_device * device, int sp, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[10]; UINT8 sense[32]; int pg_offset, pg_len, hdr_plus_1_pg; pg_offset = 8 + (pBuf[6] << 8) + pBuf[7]; if (pg_offset + 2 >= bufLen) return -EINVAL; pg_len = pBuf[pg_offset + 1] + 2; hdr_plus_1_pg = pg_offset + pg_len; if (hdr_plus_1_pg > bufLen) return -EINVAL; pBuf[0] = 0; pBuf[1] = 0; /* Length of returned mode sense data reserved for SELECT */ pBuf[pg_offset] &= 0x7f; /* Mask out PS bit from byte 0 of page data */ memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_TO_DEVICE; io_hdr.dxfer_len = hdr_plus_1_pg; io_hdr.dxferp = pBuf; cdb[0] = MODE_SELECT_10; cdb[1] = 0x10 | (sp & 1); /* set PF (page format) bit always */ cdb[8] = hdr_plus_1_pg; /* make sure only one page sent */ io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* Standard INQUIRY returns 0 for ok, anything else is a major problem. * bufLen should be 36 for unsafe devices (like USB mass storage stuff) * otherwise they can lock up! SPC-3 sections 6.4 and 7.6 (rev 22a) */ int scsiStdInquiry(scsi_device * device, UINT8 *pBuf, int bufLen) { struct scsi_sense_disect sinfo; struct scsi_cmnd_io io_hdr; UINT8 cdb[6]; UINT8 sense[32]; if ((bufLen < 0) || (bufLen > 1023)) return -EINVAL; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = INQUIRY; cdb[3] = (bufLen >> 8) & 0xff; cdb[4] = (bufLen & 0xff); io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* INQUIRY to fetch Vital Page Data. Returns 0 if ok, 1 if NOT READY * (unlikely), 2 if command not supported, 3 if field in command not * supported, 5 if response indicates that EVPD bit ignored or returns * negated errno. SPC-3 section 6.4 and 7.6 (rev 22a) */ int scsiInquiryVpd(scsi_device * device, int vpd_page, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[6]; UINT8 sense[32]; int res; /* Assume SCSI_VPD_SUPPORTED_VPD_PAGES is first VPD page fetched */ if ((SCSI_VPD_SUPPORTED_VPD_PAGES != vpd_page) && supported_vpd_pages_p && (! supported_vpd_pages_p->is_supported(vpd_page))) return 3; if ((bufLen < 0) || (bufLen > 1023)) return -EINVAL; try_again: memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); if (bufLen > 1) pBuf[1] = 0x0; io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = INQUIRY; cdb[1] = 0x1; /* set EVPD bit (enable Vital Product Data) */ cdb[2] = vpd_page; cdb[3] = (bufLen >> 8) & 0xff; cdb[4] = (bufLen & 0xff); io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); if ((SCSI_STATUS_CHECK_CONDITION == io_hdr.scsi_status) && (SCSI_SK_ILLEGAL_REQUEST == sinfo.sense_key) && (SCSI_ASC_INVALID_FIELD == sinfo.asc) && (cdb[3] > 0)) { bufLen &= 0xff; /* make sure cdb[3] is 0 next time around */ goto try_again; } if ((res = scsiSimpleSenseFilter(&sinfo))) return res; /* Guard against devices that ignore EVPD bit and do standard INQUIRY */ if (bufLen > 1) { if (vpd_page == pBuf[1]) { if ((0x80 == vpd_page) && (bufLen > 2) && (0x0 != pBuf[2])) return SIMPLE_ERR_BAD_RESP; } else return SIMPLE_ERR_BAD_RESP; } return 0; } /* REQUEST SENSE command. Returns 0 if ok, anything else major problem. * SPC-3 section 6.27 (rev 22a) */ int scsiRequestSense(scsi_device * device, struct scsi_sense_disect * sense_info) { struct scsi_cmnd_io io_hdr; UINT8 cdb[6]; UINT8 sense[32]; UINT8 buff[18]; int len; UINT8 resp_code; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = sizeof(buff); io_hdr.dxferp = buff; cdb[0] = REQUEST_SENSE; cdb[4] = sizeof(buff); io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); if (sense_info) { resp_code = buff[0] & 0x7f; sense_info->resp_code = resp_code; sense_info->sense_key = buff[2] & 0xf; sense_info->asc = 0; sense_info->ascq = 0; if ((0x70 == resp_code) || (0x71 == resp_code)) { len = buff[7] + 8; if (len > 13) { sense_info->asc = buff[12]; sense_info->ascq = buff[13]; } } // fill progrss indicator, if available sense_info->progress = -1; switch (resp_code) { const unsigned char * ucp; int sk, sk_pr; case 0x70: case 0x71: sk = (buff[2] & 0xf); if ((sizeof(buff) < 18) || ((SCSI_SK_NO_SENSE != sk) && (SCSI_SK_NOT_READY != sk))) { break; } if (buff[15] & 0x80) { /* SKSV bit set */ sense_info->progress = (buff[16] << 8) + buff[17]; break; } else { break; } case 0x72: case 0x73: /* sense key specific progress (0x2) or progress descriptor (0xa) */ sk = (buff[1] & 0xf); sk_pr = (SCSI_SK_NO_SENSE == sk) || (SCSI_SK_NOT_READY == sk); if (sk_pr && ((ucp = sg_scsi_sense_desc_find(buff, sizeof(buff), 2))) && (0x6 == ucp[1]) && (0x80 & ucp[4])) { sense_info->progress = (ucp[5] << 8) + ucp[6]; break; } else if (((ucp = sg_scsi_sense_desc_find(buff, sizeof(buff), 0xa))) && ((0x6 == ucp[1]))) { sense_info->progress = (ucp[6] << 8) + ucp[7]; break; } else break; default: return 0; } } return 0; } /* SEND DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if command * not supported, 3 if field in command not supported or returns negated * errno. SPC-3 section 6.28 (rev 22a) */ int scsiSendDiagnostic(scsi_device * device, int functioncode, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[6]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = bufLen ? DXFER_TO_DEVICE: DXFER_NONE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = SEND_DIAGNOSTIC; if (SCSI_DIAG_DEF_SELF_TEST == functioncode) cdb[1] = 0x4; /* SelfTest bit */ else if (SCSI_DIAG_NO_SELF_TEST != functioncode) cdb[1] = (functioncode & 0x7) << 5; /* SelfTest _code_ */ else /* SCSI_DIAG_NO_SELF_TEST == functioncode */ cdb[1] = 0x10; /* PF bit */ cdb[3] = (bufLen >> 8) & 0xff; cdb[4] = bufLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); /* worst case is an extended foreground self test on a big disk */ io_hdr.timeout = SCSI_TIMEOUT_SELF_TEST; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* RECEIVE DIAGNOSTIC command. Returns 0 if ok, 1 if NOT READY, 2 if * command not supported, 3 if field in command not supported or returns * negated errno. SPC-3 section 6.18 (rev 22a) */ int scsiReceiveDiagnostic(scsi_device * device, int pcv, int pagenum, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[6]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = RECEIVE_DIAGNOSTIC; cdb[1] = pcv; cdb[2] = pagenum; cdb[3] = (bufLen >> 8) & 0xff; cdb[4] = bufLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* TEST UNIT READY command. SPC-3 section 6.33 (rev 22a) */ static int _testunitready(scsi_device * device, struct scsi_sense_disect * sinfo) { struct scsi_cmnd_io io_hdr; UINT8 cdb[6]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_NONE; io_hdr.dxfer_len = 0; io_hdr.dxferp = NULL; cdb[0] = TEST_UNIT_READY; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, sinfo); return 0; } /* Returns 0 for device responds and media ready, 1 for device responds and media not ready, or returns a negated errno value */ int scsiTestUnitReady(scsi_device * device) { struct scsi_sense_disect sinfo; int status; status = _testunitready(device, &sinfo); if (0 != status) return status; status = scsiSimpleSenseFilter(&sinfo); if (SIMPLE_ERR_TRY_AGAIN == status) { /* power on reset, media changed, ok ... try again */ status = _testunitready(device, &sinfo); if (0 != status) return status; status = scsiSimpleSenseFilter(&sinfo); } return status; } /* READ DEFECT (10) command. Returns 0 if ok, 1 if NOT READY, 2 if * command not supported, 3 if field in command not supported or returns * negated errno. SBC-2 section 5.12 (rev 16) */ int scsiReadDefect10(scsi_device * device, int req_plist, int req_glist, int dl_format, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[10]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = READ_DEFECT_10; cdb[2] = (unsigned char)(((req_plist << 4) & 0x10) | ((req_glist << 3) & 0x8) | (dl_format & 0x7)); cdb[7] = (bufLen >> 8) & 0xff; cdb[8] = bufLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* READ DEFECT (12) command. Returns 0 if ok, 1 if NOT READY, 2 if * command not supported, 3 if field in command not supported or returns * negated errno. SBC-3 section 5.18 (rev 35; vale Mark Evans) */ int scsiReadDefect12(scsi_device * device, int req_plist, int req_glist, int dl_format, int addrDescIndex, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[12]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = READ_DEFECT_12; cdb[1] = (unsigned char)(((req_plist << 4) & 0x10) | ((req_glist << 3) & 0x8) | (dl_format & 0x7)); cdb[2] = (addrDescIndex >> 24) & 0xff; cdb[3] = (addrDescIndex >> 16) & 0xff; cdb[4] = (addrDescIndex >> 8) & 0xff; cdb[5] = addrDescIndex & 0xff; cdb[6] = (bufLen >> 24) & 0xff; cdb[7] = (bufLen >> 16) & 0xff; cdb[8] = (bufLen >> 8) & 0xff; cdb[9] = bufLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* READ CAPACITY (10) command. Returns 0 if ok, 1 if NOT READY, 2 if * command not supported, 3 if field in command not supported or returns * negated errno. SBC-3 section 5.15 (rev 26) */ int scsiReadCapacity10(scsi_device * device, unsigned int * last_lbap, unsigned int * lb_sizep) { int res; struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[10]; UINT8 sense[32]; UINT8 resp[8]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); memset(resp, 0, sizeof(resp)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = sizeof(resp); io_hdr.dxferp = resp; cdb[0] = READ_CAPACITY_10; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); res = scsiSimpleSenseFilter(&sinfo); if (res) return res; if (last_lbap) *last_lbap = (resp[0] << 24) | (resp[1] << 16) | (resp[2] << 8) | resp[3]; if (lb_sizep) *lb_sizep = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; return 0; } /* READ CAPACITY (16) command. The bufLen argument should be 32. Returns 0 * if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command * not supported or returns negated errno. SBC-3 section 5.16 (rev 26) */ int scsiReadCapacity16(scsi_device * device, UINT8 *pBuf, int bufLen) { struct scsi_cmnd_io io_hdr; struct scsi_sense_disect sinfo; UINT8 cdb[16]; UINT8 sense[32]; memset(&io_hdr, 0, sizeof(io_hdr)); memset(cdb, 0, sizeof(cdb)); io_hdr.dxfer_dir = DXFER_FROM_DEVICE; io_hdr.dxfer_len = bufLen; io_hdr.dxferp = pBuf; cdb[0] = READ_CAPACITY_16; cdb[1] = SAI_READ_CAPACITY_16; cdb[10] = (bufLen >> 24) & 0xff; cdb[11] = (bufLen >> 16) & 0xff; cdb[12] = (bufLen >> 8) & 0xff; cdb[13] = bufLen & 0xff; io_hdr.cmnd = cdb; io_hdr.cmnd_len = sizeof(cdb); io_hdr.sensep = sense; io_hdr.max_sense_len = sizeof(sense); io_hdr.timeout = SCSI_TIMEOUT_DEFAULT; if (!device->scsi_pass_through(&io_hdr)) return -device->get_errno(); scsi_do_sense_disect(&io_hdr, &sinfo); return scsiSimpleSenseFilter(&sinfo); } /* Return number of bytes of storage in 'device' or 0 if error. If * successful and lb_sizep is not NULL then the logical block size * in bytes is written to the location pointed to by lb_sizep. */ uint64_t scsiGetSize(scsi_device * device, unsigned int * lb_sizep, int * lb_per_pb_expp) { unsigned int last_lba = 0, lb_size = 0; int k, res; uint64_t ret_val = 0; UINT8 rc16resp[32]; res = scsiReadCapacity10(device, &last_lba, &lb_size); if (res) { if (scsi_debugmode) pout("scsiGetSize: READ CAPACITY(10) failed, res=%d\n", res); return 0; } if (0xffffffff == last_lba) { res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp)); if (res) { if (scsi_debugmode) pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res); return 0; } for (k = 0; k < 8; ++k) { if (k > 0) ret_val <<= 8; ret_val |= rc16resp[k + 0]; } if (lb_per_pb_expp) *lb_per_pb_expp = (rc16resp[13] & 0xf); } else { ret_val = last_lba; if (lb_per_pb_expp) *lb_per_pb_expp = 0; } if (lb_sizep) *lb_sizep = lb_size; ++ret_val; /* last_lba is origin 0 so need to bump to get number of */ return ret_val * lb_size; } /* Gets drive Protection and Logical/Physical block information. Writes * back bytes 12 to 31 from a READ CAPACITY 16 command to the rc16_12_31p * pointer. So rc16_12_31p should point to an array of 20 bytes. Returns 0 * if ok, 1 if NOT READY, 2 if command not supported, 3 if field in command * not supported or returns negated errno. */ int scsiGetProtPBInfo(scsi_device * device, unsigned char * rc16_12_31p) { int res; UINT8 rc16resp[32]; res = scsiReadCapacity16(device, rc16resp, sizeof(rc16resp)); if (res) { if (scsi_debugmode) pout("scsiGetSize: READ CAPACITY(16) failed, res=%d\n", res); return res; } if (rc16_12_31p) memcpy(rc16_12_31p, rc16resp + 12, 20); return 0; } /* Offset into mode sense (6 or 10 byte) response that actual mode page * starts at (relative to resp[0]). Returns -1 if problem */ int scsiModePageOffset(const UINT8 * resp, int len, int modese_len) { int resp_len, bd_len; int offset = -1; if (resp) { if (10 == modese_len) { resp_len = (resp[0] << 8) + resp[1] + 2; bd_len = (resp[6] << 8) + resp[7]; offset = bd_len + 8; } else { resp_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + 4; } if ((offset + 2) > len) { pout("scsiModePageOffset: raw_curr too small, offset=%d " "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len); offset = -1; } else if ((offset + 2) > resp_len) { if ((resp_len > 2) || scsi_debugmode) pout("scsiModePageOffset: response length too short, " "resp_len=%d offset=%d bd_len=%d\n", resp_len, offset, bd_len); offset = -1; } } return offset; } /* IEC mode page byte 2 bit masks */ #define DEXCPT_ENABLE 0x08 #define EWASC_ENABLE 0x10 #define DEXCPT_DISABLE 0xf7 #define EWASC_DISABLE 0xef #define TEST_DISABLE 0xfb /* Fetches the Informational Exceptions Control mode page. First tries * the 6 byte MODE SENSE command and if that fails with an illegal opcode * tries a 10 byte MODE SENSE command. Returns 0 if successful, a positive * number if a known error (see SIMPLE_ERR_ ...) or a negative errno * value. */ int scsiFetchIECmpage(scsi_device * device, struct scsi_iec_mode_page *iecp, int modese_len) { int err = 0; memset(iecp, 0, sizeof(*iecp)); iecp->modese_len = modese_len; iecp->requestedCurrent = 1; if (iecp->modese_len <= 6) { if ((err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CURRENT, iecp->raw_curr, sizeof(iecp->raw_curr)))) { if (SIMPLE_ERR_BAD_OPCODE == err) iecp->modese_len = 10; else { iecp->modese_len = 0; return err; } } else if (0 == iecp->modese_len) iecp->modese_len = 6; } if (10 == iecp->modese_len) { err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CURRENT, iecp->raw_curr, sizeof(iecp->raw_curr)); if (err) { iecp->modese_len = 0; return err; } } iecp->gotCurrent = 1; iecp->requestedChangeable = 1; if (10 == iecp->modese_len) err = scsiModeSense10(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, iecp->raw_chg, sizeof(iecp->raw_chg)); else if (6 == iecp->modese_len) err = scsiModeSense(device, INFORMATIONAL_EXCEPTIONS_CONTROL_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, iecp->raw_chg, sizeof(iecp->raw_chg)); if (err) return err; iecp->gotChangeable = 1; return 0; } int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp) { int offset; if (iecp && iecp->gotCurrent) { offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), iecp->modese_len); if (offset >= 0) return (iecp->raw_curr[offset + 2] & DEXCPT_ENABLE) ? 0 : 1; else return 0; } else return 0; } int scsi_IsWarningEnabled(const struct scsi_iec_mode_page *iecp) { int offset; if (iecp && iecp->gotCurrent) { offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), iecp->modese_len); if (offset >= 0) return (iecp->raw_curr[offset + 2] & EWASC_ENABLE) ? 1 : 0; else return 0; } else return 0; } /* set EWASC and clear PERF, EBF, DEXCPT TEST and LOGERR */ #define SCSI_IEC_MP_BYTE2_ENABLED 0x10 #define SCSI_IEC_MP_BYTE2_TEST_MASK 0x4 /* exception/warning via an unrequested REQUEST SENSE command */ #define SCSI_IEC_MP_MRIE 6 #define SCSI_IEC_MP_INTERVAL_T 0 #define SCSI_IEC_MP_REPORT_COUNT 1 /* Try to set (or clear) both Exception Control and Warning in the IE * mode page subject to the "changeable" mask. The object pointed to * by iecp is (possibly) inaccurate after this call, therefore * scsiFetchIECmpage() should be called again if the IEC mode page * is to be re-examined. * When -r ioctl is invoked 3 or more time on 'smartctl -s on ...' * then set the TEST bit (causes asc,ascq pair of 0x5d,0xff). */ int scsiSetExceptionControlAndWarning(scsi_device * device, int enabled, const struct scsi_iec_mode_page *iecp) { int k, offset, resp_len; int err = 0; UINT8 rout[SCSI_IECMP_RAW_LEN]; int sp, eCEnabled, wEnabled; if ((! iecp) || (! iecp->gotCurrent)) return -EINVAL; offset = scsiModePageOffset(iecp->raw_curr, sizeof(iecp->raw_curr), iecp->modese_len); if (offset < 0) return -EINVAL; memcpy(rout, iecp->raw_curr, SCSI_IECMP_RAW_LEN); if (10 == iecp->modese_len) { resp_len = (rout[0] << 8) + rout[1] + 2; rout[3] &= 0xef; /* for disks mask out DPOFUA bit */ } else { resp_len = rout[0] + 1; rout[2] &= 0xef; /* for disks mask out DPOFUA bit */ } sp = (rout[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ if (enabled) { rout[offset + 2] = SCSI_IEC_MP_BYTE2_ENABLED; if (scsi_debugmode > 2) rout[offset + 2] |= SCSI_IEC_MP_BYTE2_TEST_MASK; rout[offset + 3] = SCSI_IEC_MP_MRIE; rout[offset + 4] = (SCSI_IEC_MP_INTERVAL_T >> 24) & 0xff; rout[offset + 5] = (SCSI_IEC_MP_INTERVAL_T >> 16) & 0xff; rout[offset + 6] = (SCSI_IEC_MP_INTERVAL_T >> 8) & 0xff; rout[offset + 7] = SCSI_IEC_MP_INTERVAL_T & 0xff; rout[offset + 8] = (SCSI_IEC_MP_REPORT_COUNT >> 24) & 0xff; rout[offset + 9] = (SCSI_IEC_MP_REPORT_COUNT >> 16) & 0xff; rout[offset + 10] = (SCSI_IEC_MP_REPORT_COUNT >> 8) & 0xff; rout[offset + 11] = SCSI_IEC_MP_REPORT_COUNT & 0xff; if (iecp->gotChangeable) { UINT8 chg2 = iecp->raw_chg[offset + 2]; rout[offset + 2] = chg2 ? (rout[offset + 2] & chg2) : iecp->raw_curr[offset + 2]; for (k = 3; k < 12; ++k) { if (0 == iecp->raw_chg[offset + k]) rout[offset + k] = iecp->raw_curr[offset + k]; } } if (0 == memcmp(&rout[offset + 2], &iecp->raw_chg[offset + 2], 10)) { if (scsi_debugmode > 0) pout("scsiSetExceptionControlAndWarning: already enabled\n"); return 0; } } else { /* disabling Exception Control and (temperature) Warnings */ eCEnabled = (rout[offset + 2] & DEXCPT_ENABLE) ? 0 : 1; wEnabled = (rout[offset + 2] & EWASC_ENABLE) ? 1 : 0; if ((! eCEnabled) && (! wEnabled)) { if (scsi_debugmode > 0) pout("scsiSetExceptionControlAndWarning: already disabled\n"); return 0; /* nothing to do, leave other setting alone */ } if (wEnabled) rout[offset + 2] &= EWASC_DISABLE; if (eCEnabled) { if (iecp->gotChangeable && (iecp->raw_chg[offset + 2] & DEXCPT_ENABLE)) rout[offset + 2] |= DEXCPT_ENABLE; rout[offset + 2] &= TEST_DISABLE;/* clear TEST bit for spec */ } } if (10 == iecp->modese_len) err = scsiModeSelect10(device, sp, rout, resp_len); else if (6 == iecp->modese_len) err = scsiModeSelect(device, sp, rout, resp_len); return err; } int scsiGetTemp(scsi_device * device, UINT8 *currenttemp, UINT8 *triptemp) { UINT8 tBuf[252]; int err; memset(tBuf, 0, sizeof(tBuf)); if ((err = scsiLogSense(device, TEMPERATURE_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { *currenttemp = 0; *triptemp = 0; pout("Log Sense for temperature failed [%s]\n", scsiErrString(err)); return err; } *currenttemp = tBuf[9]; *triptemp = tBuf[15]; return 0; } /* Read informational exception log page or Request Sense response. * Fetching asc/ascq code potentially flagging an exception or warning. * Returns 0 if ok, else error number. A current temperature of 255 * (Celsius) implies that the temperature not available. */ int scsiCheckIE(scsi_device * device, int hasIELogPage, int hasTempLogPage, UINT8 *asc, UINT8 *ascq, UINT8 *currenttemp, UINT8 *triptemp) { UINT8 tBuf[252]; struct scsi_sense_disect sense_info; int err; int temperatureSet = 0; unsigned short pagesize; UINT8 currTemp, trTemp; *asc = 0; *ascq = 0; *currenttemp = 0; *triptemp = 0; memset(tBuf,0,sizeof(tBuf)); // need to clear stack space of junk memset(&sense_info, 0, sizeof(sense_info)); if (hasIELogPage) { if ((err = scsiLogSense(device, IE_LPAGE, 0, tBuf, sizeof(tBuf), 0))) { pout("Log Sense failed, IE page [%s]\n", scsiErrString(err)); return err; } // pull out page size from response, don't forget to add 4 pagesize = (unsigned short) ((tBuf[2] << 8) | tBuf[3]) + 4; if ((pagesize < 4) || tBuf[4] || tBuf[5]) { pout("Log Sense failed, IE page, bad parameter code or length\n"); return SIMPLE_ERR_BAD_PARAM; } if (tBuf[7] > 1) { sense_info.asc = tBuf[8]; sense_info.ascq = tBuf[9]; if (! hasTempLogPage) { if (tBuf[7] > 2) *currenttemp = tBuf[10]; if (tBuf[7] > 3) /* IBM extension in SMART (IE) lpage */ *triptemp = tBuf[11]; } } } if (0 == sense_info.asc) { /* ties in with MRIE field of 6 in IEC mode page (0x1c) */ if ((err = scsiRequestSense(device, &sense_info))) { pout("Request Sense failed, [%s]\n", scsiErrString(err)); return err; } } *asc = sense_info.asc; *ascq = sense_info.ascq; if ((! temperatureSet) && hasTempLogPage) { if (0 == scsiGetTemp(device, &currTemp, &trTemp)) { *currenttemp = currTemp; *triptemp = trTemp; } } return 0; } // The first character (W, C, I) tells the severity static const char * TapeAlertsMessageTable[]= { " ", /* 0x01 */ "W: The tape drive is having problems reading data. No data has been lost,\n" " but there has been a reduction in the performance of the tape.", /* 0x02 */ "W: The tape drive is having problems writing data. No data has been lost,\n" " but there has been a reduction in the capacity of the tape.", /* 0x03 */ "W: The operation has stopped because an error has occurred while reading\n" " or writing data that the drive cannot correct.", /* 0x04 */ "C: Your data is at risk:\n" " 1. Copy any data you require from this tape. \n" " 2. Do not use this tape again.\n" " 3. Restart the operation with a different tape.", /* 0x05 */ "C: The tape is damaged or the drive is faulty. Call the tape drive\n" " supplier helpline.", /* 0x06 */ "C: The tape is from a faulty batch or the tape drive is faulty:\n" " 1. Use a good tape to test the drive.\n" " 2. If problem persists, call the tape drive supplier helpline.", /* 0x07 */ "W: The tape cartridge has reached the end of its calculated useful life:\n" " 1. Copy data you need to another tape.\n" " 2. Discard the old tape.", /* 0x08 */ "W: The tape cartridge is not data-grade. Any data you back up to the tape\n" " is at risk. Replace the cartridge with a data-grade tape.", /* 0x09 */ "C: You are trying to write to a write-protected cartridge. Remove the\n" " write-protection or use another tape.", /* 0x0a */ "I: You cannot eject the cartridge because the tape drive is in use. Wait\n" " until the operation is complete before ejecting the cartridge.", /* 0x0b */ "I: The tape in the drive is a cleaning cartridge.", /* 0x0c */ "I: You have tried to load a cartridge of a type which is not supported\n" " by this drive.", /* 0x0d */ "C: The operation has failed because the tape in the drive has experienced\n" " a mechanical failure:\n" " 1. Discard the old tape.\n" " 2. Restart the operation with a different tape.", /* 0x0e */ "C: The operation has failed because the tape in the drive has experienced\n" " a mechanical failure:\n" " 1. Do not attempt to extract the tape cartridge\n" " 2. Call the tape drive supplier helpline.", /* 0x0f */ "W: The memory in the tape cartridge has failed, which reduces\n" " performance. Do not use the cartridge for further write operations.", /* 0x10 */ "C: The operation has failed because the tape cartridge was manually\n" " de-mounted while the tape drive was actively writing or reading.", /* 0x11 */ "W: You have loaded a cartridge of a type that is read-only in this drive.\n" " The cartridge will appear as write-protected.", /* 0x12 */ "W: The tape directory on the tape cartridge has been corrupted. File\n" " search performance will be degraded. The tape directory can be rebuilt\n" " by reading all the data on the cartridge.", /* 0x13 */ "I: The tape cartridge is nearing the end of its calculated life. It is\n" " recommended that you:\n" " 1. Use another tape cartridge for your next backup.\n" " 2. Store this tape in a safe place in case you need to restore " " data from it.", /* 0x14 */ "C: The tape drive needs cleaning:\n" " 1. If the operation has stopped, eject the tape and clean the drive.\n" " 2. If the operation has not stopped, wait for it to finish and then\n" " clean the drive.\n" " Check the tape drive users manual for device specific cleaning instructions.", /* 0x15 */ "W: The tape drive is due for routine cleaning:\n" " 1. Wait for the current operation to finish.\n" " 2. The use a cleaning cartridge.\n" " Check the tape drive users manual for device specific cleaning instructions.", /* 0x16 */ "C: The last cleaning cartridge used in the tape drive has worn out:\n" " 1. Discard the worn out cleaning cartridge.\n" " 2. Wait for the current operation to finish.\n" " 3. Then use a new cleaning cartridge.", /* 0x17 */ "C: The last cleaning cartridge used in the tape drive was an invalid\n" " type:\n" " 1. Do not use this cleaning cartridge in this drive.\n" " 2. Wait for the current operation to finish.\n" " 3. Then use a new cleaning cartridge.", /* 0x18 */ "W: The tape drive has requested a retention operation", /* 0x19 */ "W: A redundant interface port on the tape drive has failed", /* 0x1a */ "W: A tape drive cooling fan has failed", /* 0x1b */ "W: A redundant power supply has failed inside the tape drive enclosure.\n" " Check the enclosure users manual for instructions on replacing the\n" " failed power supply.", /* 0x1c */ "W: The tape drive power consumption is outside the specified range.", /* 0x1d */ "W: Preventive maintenance of the tape drive is required. Check the tape\n" " drive users manual for device specific preventive maintenance\n" " tasks or call the tape drive supplier helpline.", /* 0x1e */ "C: The tape drive has a hardware fault:\n" " 1. Eject the tape or magazine.\n" " 2. Reset the drive.\n" " 3. Restart the operation.", /* 0x1f */ "C: The tape drive has a hardware fault:\n" " 1. Turn the tape drive off and then on again.\n" " 2. Restart the operation.\n" " 3. If the problem persists, call the tape drive supplier helpline.", /* 0x20 */ "W: The tape drive has a problem with the application client interface:\n" " 1. Check the cables and cable connections.\n" " 2. Restart the operation.", /* 0x21 */ "C: The operation has failed:\n" " 1. Eject the tape or magazine.\n" " 2. Insert the tape or magazine again.\n" " 3. Restart the operation.", /* 0x22 */ "W: The firmware download has failed because you have tried to use the\n" " incorrect firmware for this tape drive. Obtain the correct\n" " firmware and try again.", /* 0x23 */ "W: Environmental conditions inside the tape drive are outside the\n" " specified humidity range.", /* 0x24 */ "W: Environmental conditions inside the tape drive are outside the\n" " specified temperature range.", /* 0x25 */ "W: The voltage supply to the tape drive is outside the specified range.", /* 0x26 */ "C: A hardware failure of the tape drive is predicted. Call the tape\n" " drive supplier helpline.", /* 0x27 */ "W: The tape drive may have a hardware fault. Run extended diagnostics to\n" " verify and diagnose the problem. Check the tape drive users manual for\n" " device specific instructions on running extended diagnostic tests.", /* 0x28 */ "C: The changer mechanism is having difficulty communicating with the tape\n" " drive:\n" " 1. Turn the autoloader off then on.\n" " 2. Restart the operation.\n" " 3. If problem persists, call the tape drive supplier helpline.", /* 0x29 */ "C: A tape has been left in the autoloader by a previous hardware fault:\n" " 1. Insert an empty magazine to clear the fault.\n" " 2. If the fault does not clear, turn the autoloader off and then\n" " on again.\n" " 3. If the problem persists, call the tape drive supplier helpline.", /* 0x2a */ "W: There is a problem with the autoloader mechanism.", /* 0x2b */ "C: The operation has failed because the autoloader door is open:\n" " 1. Clear any obstructions from the autoloader door.\n" " 2. Eject the magazine and then insert it again.\n" " 3. If the fault does not clear, turn the autoloader off and then\n" " on again.\n" " 4. If the problem persists, call the tape drive supplier helpline.", /* 0x2c */ "C: The autoloader has a hardware fault:\n" " 1. Turn the autoloader off and then on again.\n" " 2. Restart the operation.\n" " 3. If the problem persists, call the tape drive supplier helpline.\n" " Check the autoloader users manual for device specific instructions\n" " on turning the device power on and off.", /* 0x2d */ "C: The autoloader cannot operate without the magazine,\n" " 1. Insert the magazine into the autoloader.\n" " 2. Restart the operation.", /* 0x2e */ "W: A hardware failure of the changer mechanism is predicted. Call the\n" " tape drive supplier helpline.", /* 0x2f */ "I: Reserved.", /* 0x30 */ "I: Reserved.", /* 0x31 */ "I: Reserved.", /* 0x32 */ "W: Media statistics have been lost at some time in the past", /* 0x33 */ "W: The tape directory on the tape cartridge just unloaded has been\n" " corrupted. File search performance will be degraded. The tape\n" " directory can be rebuilt by reading all the data.", /* 0x34 */ "C: The tape just unloaded could not write its system area successfully:\n" " 1. Copy data to another tape cartridge.\n" " 2. Discard the old cartridge.", /* 0x35 */ "C: The tape system are could not be read successfully at load time:\n" " 1. Copy data to another tape cartridge.\n", /* 0x36 */ "C: The start or data could not be found on the tape:\n" " 1. Check you are using the correct format tape.\n" " 2. Discard the tape or return the tape to your supplier", /* 0x37 */ "C: The operation has failed because the media cannot be loaded\n" " and threaded.\n" " 1. Remove the cartridge, inspect it as specified in the product\n" " manual, and retry the operation.\n" " 2. If the problem persists, call the tape drive supplier help line.", /* 0x38 */ "C: The operation has failed because the medium cannot be unloaded:\n" " 1. Do not attempt to extract the tape cartridge.\n" " 2. Call the tape driver supplier help line.", /* 0x39 */ "C: The tape drive has a problem with the automation interface:\n" " 1. Check the power to the automation system.\n" " 2. Check the cables and cable connections.\n" " 3. Call the supplier help line if problem persists.", /* 0x3a */ "W: The tape drive has reset itself due to a detected firmware\n" " fault. If problem persists, call the supplier help line.", }; const char * scsiTapeAlertsTapeDevice(unsigned short code) { const int num = sizeof(TapeAlertsMessageTable) / sizeof(TapeAlertsMessageTable[0]); return (code < num) ? TapeAlertsMessageTable[code] : "Unknown Alert"; } // The first character (W, C, I) tells the severity static const char * ChangerTapeAlertsMessageTable[]= { " ", /* 0x01 */ "C: The library mechanism is having difficulty communicating with the\n" " drive:\n" " 1. Turn the library off then on.\n" " 2. Restart the operation.\n" " 3. If the problem persists, call the library supplier help line.", /* 0x02 */ "W: There is a problem with the library mechanism. If problem persists,\n" " call the library supplier help line.", /* 0x03 */ "C: The library has a hardware fault:\n" " 1. Reset the library.\n" " 2. Restart the operation.\n" " Check the library users manual for device specific instructions on resetting\n" " the device.", /* 0x04 */ "C: The library has a hardware fault:\n" " 1. Turn the library off then on again.\n" " 2. Restart the operation.\n" " 3. If the problem persists, call the library supplier help line.\n" " Check the library users manual for device specific instructions on turning the\n" " device power on and off.", /* 0x05 */ "W: The library mechanism may have a hardware fault.\n" " Run extended diagnostics to verify and diagnose the problem. Check the library\n" " users manual for device specific instructions on running extended diagnostic\n" " tests.", /* 0x06 */ "C: The library has a problem with the host interface:\n" " 1. Check the cables and connections.\n" " 2. Restart the operation.", /* 0x07 */ "W: A hardware failure of the library is predicted. Call the library\n" " supplier help line.", /* 0x08 */ "W: Preventive maintenance of the library is required.\n" " Check the library users manual for device specific preventative maintenance\n" " tasks, or call your library supplier help line.", /* 0x09 */ "C: General environmental conditions inside the library are outside the\n" " specified humidity range.", /* 0x0a */ "C: General environmental conditions inside the library are outside the\n" " specified temperature range.", /* 0x0b */ "C: The voltage supply to the library is outside the specified range.\n" " There is a potential problem with the power supply or failure of\n" " a redundant power supply.", /* 0x0c */ "C: A cartridge has been left inside the library by a previous hardware\n" " fault:\n" " 1. Insert an empty magazine to clear the fault.\n" " 2. If the fault does not clear, turn the library off and then on again.\n" " 3. If the problem persists, call the library supplier help line.", /* 0x0d */ "W: There is a potential problem with the drive ejecting cartridges or\n" " with the library mechanism picking a cartridge from a slot.\n" " 1. No action needs to be taken at this time.\n" " 2. If the problem persists, call the library supplier help line.", /* 0x0e */ "W: There is a potential problem with the library mechanism placing a\n" " cartridge into a slot.\n" " 1. No action needs to be taken at this time.\n" " 2. If the problem persists, call the library supplier help line.", /* 0x0f */ "W: There is a potential problem with the drive or the library mechanism\n" " loading cartridges, or an incompatible cartridge.", /* 0x10 */ "C: The library has failed because the door is open:\n" " 1. Clear any obstructions from the library door.\n" " 2. Close the library door.\n" " 3. If the problem persists, call the library supplier help line.", /* 0x11 */ "C: There is a mechanical problem with the library media import/export\n" " mailslot.", /* 0x12 */ "C: The library cannot operate without the magazine.\n" " 1. Insert the magazine into the library.\n" " 2. Restart the operation.", /* 0x13 */ "W: Library security has been compromised.", /* 0x14 */ "I: The library security mode has been changed.\n" " The library has either been put into secure mode, or the library has exited\n" " the secure mode.\n" " This is for information purposes only. No action is required.", /* 0x15 */ "I: The library has been manually turned offline and is unavailable for use.", /* 0x16 */ "I: A drive inside the library has been taken offline.\n" " This is for information purposes only. No action is required.", /* 0x17 */ "W: There is a potential problem with the bar code label or the scanner\n" " hardware in the library mechanism.\n" " 1. No action needs to be taken at this time.\n" " 2. If the problem persists, call the library supplier help line.", /* 0x18 */ "C: The library has detected an inconsistency in its inventory.\n" " 1. Redo the library inventory to correct inconsistency.\n" " 2. Restart the operation.\n" " Check the applications users manual or the hardware users manual for\n" " specific instructions on redoing the library inventory.", /* 0x19 */ "W: A library operation has been attempted that is invalid at this time.", /* 0x1a */ "W: A redundant interface port on the library has failed.", /* 0x1b */ "W: A library cooling fan has failed.", /* 0x1c */ "W: A redundant power supply has failed inside the library. Check the\n" " library users manual for instructions on replacing the failed power supply.", /* 0x1d */ "W: The library power consumption is outside the specified range.", /* 0x1e */ "C: A failure has occurred in the cartridge pass-through mechanism between\n" " two library modules.", /* 0x1f */ "C: A cartridge has been left in the pass-through mechanism from a\n" " previous hardware fault. Check the library users guide for instructions on\n" " clearing this fault.", /* 0x20 */ "I: The library was unable to read the bar code on a cartridge.", }; const char * scsiTapeAlertsChangerDevice(unsigned short code) { const int num = sizeof(ChangerTapeAlertsMessageTable) / sizeof(ChangerTapeAlertsMessageTable[0]); return (code < num) ? ChangerTapeAlertsMessageTable[code] : "Unknown Alert"; } /* this is a subset of the SCSI additional sense code strings indexed * by "ascq" for the case when asc==SCSI_ASC_IMPENDING_FAILURE (0x5d) */ static const char * strs_for_asc_5d[] = { /* 0x00 */ "FAILURE PREDICTION THRESHOLD EXCEEDED", "MEDIA FAILURE PREDICTION THRESHOLD EXCEEDED", "LOGICAL UNIT FAILURE PREDICTION THRESHOLD EXCEEDED", "SPARE AREA EXHAUSTION PREDICTION THRESHOLD EXCEEDED", "", "", "", "", "", "", "", "", "", "", "", "", /* 0x10 */ "HARDWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE", "HARDWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH", "HARDWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH", "HARDWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH", "HARDWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS", "HARDWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH", "HARDWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH", "HARDWARE IMPENDING FAILURE CHANNEL PARAMETRICS", "HARDWARE IMPENDING FAILURE CONTROLLER DETECTED", "HARDWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE", "HARDWARE IMPENDING FAILURE SEEK TIME PERFORMANCE", "HARDWARE IMPENDING FAILURE SPIN-UP RETRY COUNT", "HARDWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT", "", "", "", /* 0x20 */ "CONTROLLER IMPENDING FAILURE GENERAL HARD DRIVE FAILURE", "CONTROLLER IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH", "CONTROLLER IMPENDING FAILURE DATA ERROR RATE TOO HIGH", "CONTROLLER IMPENDING FAILURE SEEK ERROR RATE TOO HIGH", "CONTROLLER IMPENDING FAILURE TOO MANY BLOCK REASSIGNS", "CONTROLLER IMPENDING FAILURE ACCESS TIMES TOO HIGH", "CONTROLLER IMPENDING FAILURE START UNIT TIMES TOO HIGH", "CONTROLLER IMPENDING FAILURE CHANNEL PARAMETRICS", "CONTROLLER IMPENDING FAILURE CONTROLLER DETECTED", "CONTROLLER IMPENDING FAILURE THROUGHPUT PERFORMANCE", "CONTROLLER IMPENDING FAILURE SEEK TIME PERFORMANCE", "CONTROLLER IMPENDING FAILURE SPIN-UP RETRY COUNT", "CONTROLLER IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT", "", "", "", /* 0x30 */ "DATA CHANNEL IMPENDING FAILURE GENERAL HARD DRIVE FAILURE", "DATA CHANNEL IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH", "DATA CHANNEL IMPENDING FAILURE DATA ERROR RATE TOO HIGH", "DATA CHANNEL IMPENDING FAILURE SEEK ERROR RATE TOO HIGH", "DATA CHANNEL IMPENDING FAILURE TOO MANY BLOCK REASSIGNS", "DATA CHANNEL IMPENDING FAILURE ACCESS TIMES TOO HIGH", "DATA CHANNEL IMPENDING FAILURE START UNIT TIMES TOO HIGH", "DATA CHANNEL IMPENDING FAILURE CHANNEL PARAMETRICS", "DATA CHANNEL IMPENDING FAILURE CONTROLLER DETECTED", "DATA CHANNEL IMPENDING FAILURE THROUGHPUT PERFORMANCE", "DATA CHANNEL IMPENDING FAILURE SEEK TIME PERFORMANCE", "DATA CHANNEL IMPENDING FAILURE SPIN-UP RETRY COUNT", "DATA CHANNEL IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT", "", "", "", /* 0x40 */ "SERVO IMPENDING FAILURE GENERAL HARD DRIVE FAILURE", "SERVO IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH", "SERVO IMPENDING FAILURE DATA ERROR RATE TOO HIGH", "SERVO IMPENDING FAILURE SEEK ERROR RATE TOO HIGH", "SERVO IMPENDING FAILURE TOO MANY BLOCK REASSIGNS", "SERVO IMPENDING FAILURE ACCESS TIMES TOO HIGH", "SERVO IMPENDING FAILURE START UNIT TIMES TOO HIGH", "SERVO IMPENDING FAILURE CHANNEL PARAMETRICS", "SERVO IMPENDING FAILURE CONTROLLER DETECTED", "SERVO IMPENDING FAILURE THROUGHPUT PERFORMANCE", "SERVO IMPENDING FAILURE SEEK TIME PERFORMANCE", "SERVO IMPENDING FAILURE SPIN-UP RETRY COUNT", "SERVO IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT", "", "", "", /* 0x50 */ "SPINDLE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE", "SPINDLE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH", "SPINDLE IMPENDING FAILURE DATA ERROR RATE TOO HIGH", "SPINDLE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH", "SPINDLE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS", "SPINDLE IMPENDING FAILURE ACCESS TIMES TOO HIGH", "SPINDLE IMPENDING FAILURE START UNIT TIMES TOO HIGH", "SPINDLE IMPENDING FAILURE CHANNEL PARAMETRICS", "SPINDLE IMPENDING FAILURE CONTROLLER DETECTED", "SPINDLE IMPENDING FAILURE THROUGHPUT PERFORMANCE", "SPINDLE IMPENDING FAILURE SEEK TIME PERFORMANCE", "SPINDLE IMPENDING FAILURE SPIN-UP RETRY COUNT", "SPINDLE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT", "", "", "", /* 0x60 */ "FIRMWARE IMPENDING FAILURE GENERAL HARD DRIVE FAILURE", "FIRMWARE IMPENDING FAILURE DRIVE ERROR RATE TOO HIGH", "FIRMWARE IMPENDING FAILURE DATA ERROR RATE TOO HIGH", "FIRMWARE IMPENDING FAILURE SEEK ERROR RATE TOO HIGH", "FIRMWARE IMPENDING FAILURE TOO MANY BLOCK REASSIGNS", "FIRMWARE IMPENDING FAILURE ACCESS TIMES TOO HIGH", "FIRMWARE IMPENDING FAILURE START UNIT TIMES TOO HIGH", "FIRMWARE IMPENDING FAILURE CHANNEL PARAMETRICS", "FIRMWARE IMPENDING FAILURE CONTROLLER DETECTED", "FIRMWARE IMPENDING FAILURE THROUGHPUT PERFORMANCE", "FIRMWARE IMPENDING FAILURE SEEK TIME PERFORMANCE", "FIRMWARE IMPENDING FAILURE SPIN-UP RETRY COUNT", /* 0x6c */ "FIRMWARE IMPENDING FAILURE DRIVE CALIBRATION RETRY COUNT"}; /* this is a subset of the SCSI additional sense code strings indexed * * by "ascq" for the case when asc==SCSI_ASC_WARNING (0xb) * */ static const char * strs_for_asc_b[] = { /* 0x00 */ "WARNING", "WARNING - SPECIFIED TEMPERATURE EXCEEDED", "WARNING - ENCLOSURE DEGRADED"}; static char spare_buff[128]; const char * scsiGetIEString(UINT8 asc, UINT8 ascq) { const char * rp; if (SCSI_ASC_IMPENDING_FAILURE == asc) { if (ascq == 0xff) return "FAILURE PREDICTION THRESHOLD EXCEEDED (FALSE)"; else if (ascq < (sizeof(strs_for_asc_5d) / sizeof(strs_for_asc_5d[0]))) { rp = strs_for_asc_5d[ascq]; if (strlen(rp) > 0) return rp; } snprintf(spare_buff, sizeof(spare_buff), "FAILURE PREDICTION THRESHOLD EXCEEDED: ascq=0x%x", ascq); return spare_buff; } else if (SCSI_ASC_WARNING == asc) { if (ascq < (sizeof(strs_for_asc_b) / sizeof(strs_for_asc_b[0]))) { rp = strs_for_asc_b[ascq]; if (strlen(rp) > 0) return rp; } snprintf(spare_buff, sizeof(spare_buff), "WARNING: ascq=0x%x", ascq); return spare_buff; } return NULL; /* not a IE additional sense code */ } /* This is not documented in t10.org, page 0x80 is vendor specific */ /* Some IBM disks do an offline read-scan when they get this command. */ int scsiSmartIBMOfflineTest(scsi_device * device) { UINT8 tBuf[256]; int res; memset(tBuf, 0, sizeof(tBuf)); /* Build SMART Off-line Immediate Diag Header */ tBuf[0] = 0x80; /* Page Code */ tBuf[1] = 0x00; /* Reserved */ tBuf[2] = 0x00; /* Page Length MSB */ tBuf[3] = 0x04; /* Page Length LSB */ tBuf[4] = 0x03; /* SMART Revision */ tBuf[5] = 0x00; /* Reserved */ tBuf[6] = 0x00; /* Off-line Immediate Time MSB */ tBuf[7] = 0x00; /* Off-line Immediate Time LSB */ res = scsiSendDiagnostic(device, SCSI_DIAG_NO_SELF_TEST, tBuf, 8); if (res) pout("IBM offline test failed [%s]\n", scsiErrString(res)); return res; } int scsiSmartDefaultSelfTest(scsi_device * device) { int res; res = scsiSendDiagnostic(device, SCSI_DIAG_DEF_SELF_TEST, NULL, 0); if (res) pout("Default self test failed [%s]\n", scsiErrString(res)); return res; } int scsiSmartShortSelfTest(scsi_device * device) { int res; res = scsiSendDiagnostic(device, SCSI_DIAG_BG_SHORT_SELF_TEST, NULL, 0); if (res) pout("Short offline self test failed [%s]\n", scsiErrString(res)); return res; } int scsiSmartExtendSelfTest(scsi_device * device) { int res; res = scsiSendDiagnostic(device, SCSI_DIAG_BG_EXTENDED_SELF_TEST, NULL, 0); if (res) pout("Long (extended) offline self test failed [%s]\n", scsiErrString(res)); return res; } int scsiSmartShortCapSelfTest(scsi_device * device) { int res; res = scsiSendDiagnostic(device, SCSI_DIAG_FG_SHORT_SELF_TEST, NULL, 0); if (res) pout("Short foreground self test failed [%s]\n", scsiErrString(res)); return res; } int scsiSmartExtendCapSelfTest(scsi_device * device) { int res; res = scsiSendDiagnostic(device, SCSI_DIAG_FG_EXTENDED_SELF_TEST, NULL, 0); if (res) pout("Long (extended) foreground self test failed [%s]\n", scsiErrString(res)); return res; } int scsiSmartSelfTestAbort(scsi_device * device) { int res; res = scsiSendDiagnostic(device, SCSI_DIAG_ABORT_SELF_TEST, NULL, 0); if (res) pout("Abort self test failed [%s]\n", scsiErrString(res)); return res; } /* Returns 0 and the expected duration of an extended self test (in seconds) if successful; any other return value indicates a failure. */ int scsiFetchExtendedSelfTestTime(scsi_device * device, int * durationSec, int modese_len) { int err, offset, res; UINT8 buff[64]; memset(buff, 0, sizeof(buff)); if (modese_len <= 6) { if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)))) { if (SIMPLE_ERR_BAD_OPCODE == err) modese_len = 10; else return err; } else if (0 == modese_len) modese_len = 6; } if (10 == modese_len) { err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)); if (err) return err; } offset = scsiModePageOffset(buff, sizeof(buff), modese_len); if (offset < 0) return -EINVAL; if (buff[offset + 1] >= 0xa) { res = (buff[offset + 10] << 8) | buff[offset + 11]; *durationSec = res; return 0; } else return -EINVAL; } void scsiDecodeErrCounterPage(unsigned char * resp, struct scsiErrorCounter *ecp) { int k, j, num, pl, pc; unsigned char * ucp; unsigned char * xp; uint64_t * ullp; memset(ecp, 0, sizeof(*ecp)); num = (resp[2] << 8) | resp[3]; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pl = ucp[3] + 4; switch (pc) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: ecp->gotPC[pc] = 1; ullp = &ecp->counter[pc]; break; default: ecp->gotExtraPC = 1; ullp = &ecp->counter[7]; break; } k = pl - 4; xp = ucp + 4; if (k > (int)sizeof(*ullp)) { xp += (k - sizeof(*ullp)); k = sizeof(*ullp); } *ullp = 0; for (j = 0; j < k; ++j) { if (j > 0) *ullp <<= 8; *ullp |= xp[j]; } num -= pl; ucp += pl; } } void scsiDecodeNonMediumErrPage(unsigned char *resp, struct scsiNonMediumError *nmep) { int k, j, num, pl, pc, szof; unsigned char * ucp; unsigned char * xp; memset(nmep, 0, sizeof(*nmep)); num = (resp[2] << 8) | resp[3]; ucp = &resp[0] + 4; szof = sizeof(nmep->counterPC0); while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pl = ucp[3] + 4; switch (pc) { case 0: nmep->gotPC0 = 1; k = pl - 4; xp = ucp + 4; if (k > szof) { xp += (k - szof); k = szof; } nmep->counterPC0 = 0; for (j = 0; j < k; ++j) { if (j > 0) nmep->counterPC0 <<= 8; nmep->counterPC0 |= xp[j]; } break; case 0x8009: nmep->gotTFE_H = 1; k = pl - 4; xp = ucp + 4; if (k > szof) { xp += (k - szof); k = szof; } nmep->counterTFE_H = 0; for (j = 0; j < k; ++j) { if (j > 0) nmep->counterTFE_H <<= 8; nmep->counterTFE_H |= xp[j]; } break; case 0x8015: nmep->gotPE_H = 1; k = pl - 4; xp = ucp + 4; if (k > szof) { xp += (k - szof); k = szof; } nmep->counterPE_H = 0; for (j = 0; j < k; ++j) { if (j > 0) nmep->counterPE_H <<= 8; nmep->counterPE_H |= xp[j]; } break; default: nmep->gotExtraPC = 1; break; } num -= pl; ucp += pl; } } /* Counts number of failed self-tests. Also encodes the poweron_hour of the most recent failed self-test. Return value is negative if this function has a problem (typically -1), otherwise the bottom 8 bits are the number of failed self tests and the 16 bits above that are the poweron hour of the most recent failure. Note: aborted self tests (typically by the user) and self tests in progress are not considered failures. See Working Draft SCSI Primary Commands - 3 (SPC-3) section 7.2.10 T10/1416-D (rev 22a) */ int scsiCountFailedSelfTests(scsi_device * fd, int noisy) { int num, k, n, err, res, fails, fail_hour; UINT8 * ucp; unsigned char resp[LOG_RESP_SELF_TEST_LEN]; if ((err = scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp, LOG_RESP_SELF_TEST_LEN, 0))) { if (noisy) pout("scsiCountSelfTests Failed [%s]\n", scsiErrString(err)); return -1; } if ((resp[0] & 0x3f) != SELFTEST_RESULTS_LPAGE) { if (noisy) pout("Self-test Log Sense Failed, page mismatch\n"); return -1; } // compute page length num = (resp[2] << 8) + resp[3]; // Log sense page length 0x190 bytes if (num != 0x190) { if (noisy) pout("Self-test Log Sense length is 0x%x not 0x190 bytes\n", num); return -1; } fails = 0; fail_hour = 0; // loop through the twenty possible entries for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) { // timestamp in power-on hours (or zero if test in progress) n = (ucp[6] << 8) | ucp[7]; // The spec says "all 20 bytes will be zero if no test" but // DG has found otherwise. So this is a heuristic. if ((0 == n) && (0 == ucp[4])) break; res = ucp[4] & 0xf; if ((res > 2) && (res < 8)) { fails++; if (1 == fails) fail_hour = (ucp[6] << 8) + ucp[7]; } } return (fail_hour << 8) + fails; } /* Returns 0 if able to read self test log page; then outputs 1 into *inProgress if self test still in progress, else outputs 0. */ int scsiSelfTestInProgress(scsi_device * fd, int * inProgress) { int num; UINT8 * ucp; unsigned char resp[LOG_RESP_SELF_TEST_LEN]; if (scsiLogSense(fd, SELFTEST_RESULTS_LPAGE, 0, resp, LOG_RESP_SELF_TEST_LEN, 0)) return -1; if (resp[0] != SELFTEST_RESULTS_LPAGE) return -1; // compute page length num = (resp[2] << 8) + resp[3]; // Log sense page length 0x190 bytes if (num != 0x190) { return -1; } ucp = resp + 4; if (inProgress) *inProgress = (0xf == (ucp[4] & 0xf)) ? 1 : 0; return 0; } /* Returns a negative value if failed to fetch Contol mode page or it was malformed. Returns 0 if GLTSD bit is zero and returns 1 if the GLTSD bit is set. Examines default mode page when current==0 else examines current mode page. */ int scsiFetchControlGLTSD(scsi_device * device, int modese_len, int current) { int err, offset; UINT8 buff[64]; int pc = current ? MPAGE_CONTROL_CURRENT : MPAGE_CONTROL_DEFAULT; memset(buff, 0, sizeof(buff)); if (modese_len <= 6) { if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, pc, buff, sizeof(buff)))) { if (SIMPLE_ERR_BAD_OPCODE == err) modese_len = 10; else return -EINVAL; } else if (0 == modese_len) modese_len = 6; } if (10 == modese_len) { err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, pc, buff, sizeof(buff)); if (err) return -EINVAL; } offset = scsiModePageOffset(buff, sizeof(buff), modese_len); if ((offset >= 0) && (buff[offset + 1] >= 0xa)) return (buff[offset + 2] & 2) ? 1 : 0; return -EINVAL; } /* Returns a negative value on error, 0 if unknown and 1 if SSD, * otherwise the positive returned value is the speed in rpm. First checks * the Block Device Characteristics VPD page and if that fails it tries the * RIGID_DISK_DRIVE_GEOMETRY_PAGE mode page. */ int scsiGetRPM(scsi_device * device, int modese_len, int * form_factorp) { int err, offset, speed; UINT8 buff[64]; int pc = MPAGE_CONTROL_DEFAULT; memset(buff, 0, sizeof(buff)); if ((0 == scsiInquiryVpd(device, SCSI_VPD_BLOCK_DEVICE_CHARACTERISTICS, buff, sizeof(buff))) && (((buff[2] << 8) + buff[3]) > 2)) { speed = (buff[4] << 8) + buff[5]; if (form_factorp) *form_factorp = buff[7] & 0xf; return speed; } if (form_factorp) *form_factorp = 0; if (modese_len <= 6) { if ((err = scsiModeSense(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc, buff, sizeof(buff)))) { if (SIMPLE_ERR_BAD_OPCODE == err) modese_len = 10; else return -EINVAL; } else if (0 == modese_len) modese_len = 6; } if (10 == modese_len) { err = scsiModeSense10(device, RIGID_DISK_DRIVE_GEOMETRY_PAGE, 0, pc, buff, sizeof(buff)); if (err) return -EINVAL; } offset = scsiModePageOffset(buff, sizeof(buff), modese_len); return (buff[offset + 20] << 8) | buff[offset + 21]; } /* Returns a non-zero value in case of error, wcep/rcdp == -1 - get value, 0 - clear bit, 1 - set bit */ int scsiGetSetCache(scsi_device * device, int modese_len, short int * wcep, short int * rcdp) { int err, offset, resp_len, sp; UINT8 buff[64], ch_buff[64]; short set_wce = *wcep; short set_rcd = *rcdp; memset(buff, 0, sizeof(buff)); if (modese_len <= 6) { if ((err = scsiModeSense(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)))) { if (SIMPLE_ERR_BAD_OPCODE == err) modese_len = 10; else { device->set_err(EINVAL, "SCSI MODE SENSE failed"); return -EINVAL; } } else if (0 == modese_len) modese_len = 6; } if (10 == modese_len) { err = scsiModeSense10(device, CACHING_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)); if (err) { device->set_err(EINVAL, "SCSI MODE SENSE failed"); return -EINVAL; } } offset = scsiModePageOffset(buff, sizeof(buff), modese_len); if ((offset < 0) || (buff[offset + 1] < 0xa)) { device->set_err(EINVAL, "Bad response"); return SIMPLE_ERR_BAD_RESP; } *wcep = ((buff[offset + 2] & 0x04) != 0); *rcdp = ((buff[offset + 2] & 0x01) != 0); if((*wcep == set_wce || set_wce == -1) && ((*rcdp == set_rcd) || set_rcd == -1)) return 0; // no changes needed or nothing to set if (modese_len == 6) err = scsiModeSense(device, CACHING_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, ch_buff, sizeof(ch_buff)); else err = scsiModeSense10(device, CACHING_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, ch_buff, sizeof(ch_buff)); if (err) { device->set_err(EINVAL, "WCE/RCD bits not changable"); return err; } // set WCE bit if(set_wce >= 0 && *wcep != set_wce) { if (0 == (ch_buff[offset + 2] & 0x04)) { device->set_err(EINVAL, "WCE bit not changable"); return 1; } if(set_wce) buff[offset + 2] |= 0x04; // set bit else buff[offset + 2] &= 0xfb; // clear bit } // set RCD bit if(set_rcd >= 0 && *rcdp != set_rcd) { if (0 == (ch_buff[offset + 2] & 0x01)) { device->set_err(EINVAL, "RCD bit not changable"); return 1; } if(set_rcd) buff[offset + 2] |= 0x01; // set bit else buff[offset + 2] &= 0xfe; // clear bit } if (10 == modese_len) { resp_len = (buff[0] << 8) + buff[1] + 2; buff[3] &= 0xef; /* for disks mask out DPOFUA bit */ } else { resp_len = buff[0] + 1; buff[2] &= 0xef; /* for disks mask out DPOFUA bit */ } sp = 0; /* Do not change saved values */ if (10 == modese_len) err = scsiModeSelect10(device, sp, buff, resp_len); else if (6 == modese_len) err = scsiModeSelect(device, sp, buff, resp_len); if(err) device->set_err(EINVAL, "MODE SELECT command failed"); return err; } /* Attempts to set or clear GLTSD bit in Control mode page. If enabled is 0 attempts to clear GLTSD otherwise it attempts to set it. Returns 0 if successful, negative if low level error, > 0 if higher level error (e.g. SIMPLE_ERR_BAD_PARAM if GLTSD bit is not changeable). */ int scsiSetControlGLTSD(scsi_device * device, int enabled, int modese_len) { int err, offset, resp_len, sp; UINT8 buff[64]; UINT8 ch_buff[64]; memset(buff, 0, sizeof(buff)); if (modese_len <= 6) { if ((err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)))) { if (SIMPLE_ERR_BAD_OPCODE == err) modese_len = 10; else return err; } else if (0 == modese_len) modese_len = 6; } if (10 == modese_len) { err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)); if (err) return err; } offset = scsiModePageOffset(buff, sizeof(buff), modese_len); if ((offset < 0) || (buff[offset + 1] < 0xa)) return SIMPLE_ERR_BAD_RESP; if (enabled) enabled = 2; if (enabled == (buff[offset + 2] & 2)) return 0; /* GLTSD already in wanted state so nothing to do */ if (modese_len == 6) err = scsiModeSense(device, CONTROL_MODE_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, ch_buff, sizeof(ch_buff)); else err = scsiModeSense10(device, CONTROL_MODE_PAGE, 0, MPAGE_CONTROL_CHANGEABLE, ch_buff, sizeof(ch_buff)); if (err) return err; if (0 == (ch_buff[offset + 2] & 2)) return SIMPLE_ERR_BAD_PARAM; /* GLTSD bit not chageable */ if (10 == modese_len) { resp_len = (buff[0] << 8) + buff[1] + 2; buff[3] &= 0xef; /* for disks mask out DPOFUA bit */ } else { resp_len = buff[0] + 1; buff[2] &= 0xef; /* for disks mask out DPOFUA bit */ } sp = (buff[offset] & 0x80) ? 1 : 0; /* PS bit becomes 'SELECT's SP bit */ if (enabled) buff[offset + 2] |= 0x2; /* set GLTSD bit */ else buff[offset + 2] &= 0xfd; /* clear GLTSD bit */ if (10 == modese_len) err = scsiModeSelect10(device, sp, buff, resp_len); else if (6 == modese_len) err = scsiModeSelect(device, sp, buff, resp_len); return err; } /* Returns a negative value if failed to fetch Protocol specific port mode page or it was malformed. Returns transport protocol identifier when value >= 0 . */ int scsiFetchTransportProtocol(scsi_device * device, int modese_len) { int err, offset; UINT8 buff[64]; memset(buff, 0, sizeof(buff)); if (modese_len <= 6) { if ((err = scsiModeSense(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)))) { if (SIMPLE_ERR_BAD_OPCODE == err) modese_len = 10; else return -EINVAL; } else if (0 == modese_len) modese_len = 6; } if (10 == modese_len) { err = scsiModeSense10(device, PROTOCOL_SPECIFIC_PORT_PAGE, 0, MPAGE_CONTROL_CURRENT, buff, sizeof(buff)); if (err) return -EINVAL; } offset = scsiModePageOffset(buff, sizeof(buff), modese_len); if ((offset >= 0) && (buff[offset + 1] > 1)) { if ((0 == (buff[offset] & 0x40)) && /* SPF==0 */ (PROTOCOL_SPECIFIC_PORT_PAGE == (buff[offset] & 0x3f))) return (buff[offset + 2] & 0xf); } return -EINVAL; } const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len, int desc_type) { int add_sen_len, add_len, desc_len, k; const unsigned char * descp; if ((sense_len < 8) || (0 == (add_sen_len = sensep[7]))) return NULL; if ((sensep[0] < 0x72) || (sensep[0] > 0x73)) return NULL; add_sen_len = (add_sen_len < (sense_len - 8)) ? add_sen_len : (sense_len - 8); descp = &sensep[8]; for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { descp += desc_len; add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; desc_len = add_len + 2; if (descp[0] == desc_type) return descp; if (add_len < 0) /* short descriptor ?? */ break; } return NULL; } // Convenience function for formatting strings from SCSI identify void scsi_format_id_string(char * out, const unsigned char * in, int n) { char tmp[65]; n = n > 64 ? 64 : n; strncpy(tmp, (const char *)in, n); tmp[n] = '\0'; // Find the first non-space character (maybe none). int first = -1; int i; for (i = 0; tmp[i]; i++) if (!isspace((int)tmp[i])) { first = i; break; } if (first == -1) { // There are no non-space characters. out[0] = '\0'; return; } // Find the last non-space character. for (i = strlen(tmp)-1; i >= first && isspace((int)tmp[i]); i--); int last = i; strncpy(out, tmp+first, last-first+1); out[last-first+1] = '\0'; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/knowndrives.h��������������������������������������������������������0000644�0000000�0000000�00000005123�12021467115�017603� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * knowndrives.h * * Home page of code is: http://smartmontools.sourceforge.net * Address of support mailing list: smartmontools-support@lists.sourceforge.net * * Copyright (C) 2003-11 Philip Williams, Bruce Allen * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #ifndef KNOWNDRIVES_H_ #define KNOWNDRIVES_H_ #define KNOWNDRIVES_H_CVSID "$Id: knowndrives.h 3597 2012-09-04 21:10:37Z chrfranke $\n" // Structure to store drive database entries, see drivedb.h for a description. struct drive_settings { const char * modelfamily; const char * modelregexp; const char * firmwareregexp; const char * warningmsg; const char * presets; }; // info returned by lookup_usb_device() struct usb_dev_info { std::string usb_device; // Device name, empty if unknown std::string usb_bridge; // USB bridge name, empty if unknown std::string usb_type; // Type string ('-d' option). }; // Search drivedb for USB device with vendor:product ID. int lookup_usb_device(int vendor_id, int product_id, int bcd_device, usb_dev_info & info, usb_dev_info & info2); // Shows the presets (if any) that are available for the given drive. void show_presets(const ata_identify_device * drive); // Shows all presets for drives in knowndrives[]. // Returns #syntax errors. int showallpresets(); // Shows all matching presets for a drive in knowndrives[]. // Returns # matching entries. int showmatchingpresets(const char *model, const char *firmware); // Searches drive database and sets preset vendor attribute // options in defs and firmwarebugs. // Values that have already been set will not be changed. // Returns pointer to database entry or nullptr if none found. const drive_settings * lookup_drive_apply_presets( const ata_identify_device * drive, ata_vendor_attr_defs & defs, firmwarebug_defs & firmwarebugs); // Get path for additional database file const char * get_drivedb_path_add(); #ifdef SMARTMONTOOLS_DRIVEDBDIR // Get path for default database file const char * get_drivedb_path_default(); #endif // Read drive database from file. bool read_drive_database(const char * path); // Read drive databases from standard places. bool read_default_drive_databases(); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/atacmdnames.h��������������������������������������������������������0000644�0000000�0000000�00000002215�12062413436�017510� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * atacmdnames.h * * This module is based on the T13/1532D Volume 1 Revision 3 (ATA/ATAPI-7) * specification, which is available from http://www.t13.org/#FTP_site * * Home page of code is: http://smartmontools.sourceforge.net * Address of support mailing list: smartmontools-support@lists.sourceforge.net * * Copyright (C) 2003-8 Philip Williams * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef ATACMDNAMES_H_ #define ATACMDNAMES_H_ #define ATACMDNAMES_H_CVSID "$Id: atacmdnames.h 3728 2012-12-13 17:57:50Z chrfranke $\n" /* Returns the name of the command (and possibly sub-command) with the given command code and feature register values. */ const char *look_up_ata_command(unsigned char c_code, unsigned char f_reg); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_freebsd.h���������������������������������������������������������0000644�0000000�0000000�00000041076�12062407372�017360� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_freebsd.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 Eduard Martinescu <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ /*- * Copyright (c) 2000 Michael Smith * Copyright (c) 2003 Paul Saab * Copyright (c) 2003 Vinod Kashyap * Copyright (c) 2000 BSDi * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* * Copyright (c) 2004-05 Applied Micro Circuits Corporation. * Copyright (c) 2004-05 Vinod Kashyap * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef OS_FREEBSD_H_ #define OS_FREEBSD_H_ #define OS_FREEBSD_H_CVSID "$Id: os_freebsd.h 3727 2012-12-13 17:23:06Z samm2 $" #define MAX_NUM_DEV 26 #ifdef HAVE_SYS_TWEREG_H #include <sys/twereg.h> #else /** * The following cut out of twereg.h * */ #if __FreeBSD_version < 500040 #define __packed __attribute__((__packed__)) #endif #define TWE_MAX_SGL_LENGTH 62 #define TWE_MAX_ATA_SGL_LENGTH 60 #define TWE_OP_ATA_PASSTHROUGH 0x11 /* scatter/gather list entry */ typedef struct { u_int32_t address; u_int32_t length; } __packed TWE_SG_Entry; typedef struct { u_int8_t opcode:5; /* TWE_OP_INITCONNECTION */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t res2:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; u_int16_t message_credits; u_int32_t response_queue_pointer; } __packed TWE_Command_INITCONNECTION; typedef struct { u_int8_t opcode:5; /* TWE_OP_READ/TWE_OP_WRITE */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t unit:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; u_int16_t block_count; u_int32_t lba; TWE_SG_Entry sgl[TWE_MAX_SGL_LENGTH]; } __packed TWE_Command_IO; typedef struct { u_int8_t opcode:5; /* TWE_OP_HOTSWAP */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t unit:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; u_int8_t action; #define TWE_OP_HOTSWAP_REMOVE 0x00 /* remove assumed-degraded unit */ #define TWE_OP_HOTSWAP_ADD_CBOD 0x01 /* add CBOD to empty port */ #define TWE_OP_HOTSWAP_ADD_SPARE 0x02 /* add spare to empty port */ u_int8_t aport; } __packed TWE_Command_HOTSWAP; typedef struct { u_int8_t opcode:5; /* TWE_OP_SETATAFEATURE */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t unit:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; u_int8_t feature; #define TWE_OP_SETATAFEATURE_WCE 0x02 #define TWE_OP_SETATAFEATURE_DIS_WCE 0x82 u_int8_t feature_mode; u_int16_t all_units; u_int16_t persistence; } __packed TWE_Command_SETATAFEATURE; typedef struct { u_int8_t opcode:5; /* TWE_OP_CHECKSTATUS */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t unit:4; u_int8_t res2:4; u_int8_t status; u_int8_t flags; u_int16_t target_status; /* set low byte to target request's ID */ } __packed TWE_Command_CHECKSTATUS; typedef struct { u_int8_t opcode:5; /* TWE_OP_GETPARAM, TWE_OP_SETPARAM */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t unit:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; u_int16_t param_count; TWE_SG_Entry sgl[TWE_MAX_SGL_LENGTH]; } __packed TWE_Command_PARAM; typedef struct { u_int8_t opcode:5; /* TWE_OP_REBUILDUNIT */ u_int8_t res1:3; u_int8_t size; u_int8_t request_id; u_int8_t src_unit:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; u_int8_t action:7; #define TWE_OP_REBUILDUNIT_NOP 0 #define TWE_OP_REBUILDUNIT_STOP 2 /* stop all rebuilds */ #define TWE_OP_REBUILDUNIT_START 4 /* start rebuild with lowest unit */ #define TWE_OP_REBUILDUNIT_STARTUNIT 5 /* rebuild src_unit (not supported) */ u_int8_t cs:1; /* request state change on src_unit */ u_int8_t logical_subunit; /* for RAID10 rebuild of logical subunit */ } __packed TWE_Command_REBUILDUNIT; typedef struct { u_int8_t opcode:5; u_int8_t sgl_offset:3; u_int8_t size; u_int8_t request_id; u_int8_t unit; u_int8_t status; u_int8_t flags; u_int16_t param; u_int16_t features; u_int16_t sector_count; u_int16_t sector_num; u_int16_t cylinder_lo; u_int16_t cylinder_hi; u_int8_t drive_head; u_int8_t command; TWE_SG_Entry sgl[TWE_MAX_ATA_SGL_LENGTH]; } __packed TWE_Command_ATA; typedef struct { u_int8_t opcode:5; u_int8_t sgl_offset:3; u_int8_t size; u_int8_t request_id; u_int8_t unit:4; u_int8_t host_id:4; u_int8_t status; u_int8_t flags; #define TWE_FLAGS_SUCCESS 0x00 #define TWE_FLAGS_INFORMATIONAL 0x01 #define TWE_FLAGS_WARNING 0x02 #define TWE_FLAGS_FATAL 0x03 #define TWE_FLAGS_PERCENTAGE (1<<8) /* bits 0-6 indicate completion percentage */ u_int16_t count; /* block count, parameter count, message credits */ } __packed TWE_Command_Generic; /* command packet - must be TWE_ALIGNMENT aligned */ typedef union { TWE_Command_INITCONNECTION initconnection; TWE_Command_IO io; TWE_Command_PARAM param; TWE_Command_CHECKSTATUS checkstatus; TWE_Command_REBUILDUNIT rebuildunit; TWE_Command_SETATAFEATURE setatafeature; TWE_Command_ATA ata; TWE_Command_Generic generic; u_int8_t pad[512]; } TWE_Command; /* response queue entry */ typedef union { struct { u_int32_t undefined_1:4; u_int32_t response_id:8; u_int32_t undefined_2:20; } u; u_int32_t value; } TWE_Response_Queue; #endif #ifdef HAVE_SYS_TWEIO_H #include <sys/tweio.h> #else /* * Following cut out of tweio.h * */ /* * User-space command * * Note that the command's scatter/gather list will be computed by the * driver, and cannot be filled in by the consumer. */ struct twe_usercommand { TWE_Command tu_command; /* command ready for the controller */ void *tu_data; /* pointer to data in userspace */ size_t tu_size; /* userspace data length */ }; #define TWEIO_COMMAND _IOWR('T', 100, struct twe_usercommand) #endif #ifdef HAVE_SYS_TW_OSL_IOCTL_H #include <sys/tw_osl_ioctl.h> #else /* * Following cut out of tw_osl_types.h * */ typedef void TW_VOID; typedef char TW_INT8; typedef unsigned char TW_UINT8; typedef short TW_INT16; typedef unsigned short TW_UINT16; typedef int TW_INT32; typedef unsigned int TW_UINT32; typedef long long TW_INT64; typedef unsigned long long TW_UINT64; /* * Following cut out of tw_cl_share.h * */ #pragma pack(1) struct tw_cl_event_packet { TW_UINT32 sequence_id; TW_UINT32 time_stamp_sec; TW_UINT16 aen_code; TW_UINT8 severity; TW_UINT8 retrieved; TW_UINT8 repeat_count; TW_UINT8 parameter_len; TW_UINT8 parameter_data[98]; TW_UINT32 event_src; TW_UINT8 severity_str[20]; }; #pragma pack() /* * Following cut out of tw_cl_fwif.h * */ #define TWA_FW_CMD_ATA_PASSTHROUGH 0x11 #define TWA_SENSE_DATA_LENGTH 18 #pragma pack(1) /* 7000 structures. */ struct tw_cl_command_init_connect { TW_UINT8 res1__opcode; /* 3:5 */ TW_UINT8 size; TW_UINT8 request_id; TW_UINT8 res2; TW_UINT8 status; TW_UINT8 flags; TW_UINT16 message_credits; TW_UINT32 features; TW_UINT16 fw_srl; TW_UINT16 fw_arch_id; TW_UINT16 fw_branch; TW_UINT16 fw_build; TW_UINT32 result; }; /* Structure for downloading firmware onto the controller. */ struct tw_cl_command_download_firmware { TW_UINT8 sgl_off__opcode;/* 3:5 */ TW_UINT8 size; TW_UINT8 request_id; TW_UINT8 unit; TW_UINT8 status; TW_UINT8 flags; TW_UINT16 param; TW_UINT8 sgl[1]; }; /* Structure for hard resetting the controller. */ struct tw_cl_command_reset_firmware { TW_UINT8 res1__opcode; /* 3:5 */ TW_UINT8 size; TW_UINT8 request_id; TW_UINT8 unit; TW_UINT8 status; TW_UINT8 flags; TW_UINT8 res2; TW_UINT8 param; }; /* Structure for sending get/set param commands. */ struct tw_cl_command_param { TW_UINT8 sgl_off__opcode;/* 3:5 */ TW_UINT8 size; TW_UINT8 request_id; TW_UINT8 host_id__unit; /* 4:4 */ TW_UINT8 status; TW_UINT8 flags; TW_UINT16 param_count; TW_UINT8 sgl[1]; }; /* Generic command packet. */ struct tw_cl_command_generic { TW_UINT8 sgl_off__opcode;/* 3:5 */ TW_UINT8 size; TW_UINT8 request_id; TW_UINT8 host_id__unit; /* 4:4 */ TW_UINT8 status; TW_UINT8 flags; TW_UINT16 count; /* block cnt, parameter cnt, message credits */ }; /* Command packet header. */ struct tw_cl_command_header { TW_UINT8 sense_data[TWA_SENSE_DATA_LENGTH]; struct { TW_INT8 reserved[4]; TW_UINT16 error; TW_UINT8 padding; TW_UINT8 res__severity; /* 5:3 */ } status_block; TW_UINT8 err_specific_desc[98]; struct { TW_UINT8 size_header; TW_UINT16 reserved; TW_UINT8 size_sense; } header_desc; }; /* 7000 Command packet. */ union tw_cl_command_7k { struct tw_cl_command_init_connect init_connect; struct tw_cl_command_download_firmware download_fw; struct tw_cl_command_reset_firmware reset_fw; struct tw_cl_command_param param; struct tw_cl_command_generic generic; TW_UINT8 padding[1024 - sizeof(struct tw_cl_command_header)]; }; /* 9000 Command Packet. */ struct tw_cl_command_9k { TW_UINT8 res__opcode; /* 3:5 */ TW_UINT8 unit; TW_UINT16 lun_l4__req_id; /* 4:12 */ TW_UINT8 status; TW_UINT8 sgl_offset; /* offset (in bytes) to sg_list, from the end of sgl_entries */ TW_UINT16 lun_h4__sgl_entries; TW_UINT8 cdb[16]; TW_UINT8 sg_list[872];/* total struct size = 1024-sizeof(cmd_hdr) */ }; /* Full command packet. */ struct tw_cl_command_packet { struct tw_cl_command_header cmd_hdr; union { union tw_cl_command_7k cmd_pkt_7k; struct tw_cl_command_9k cmd_pkt_9k; } command; }; #pragma pack() /* * Following cut out of tw_cl_ioctl.h * */ #pragma pack(1) /* Structure used to handle GET/RELEASE LOCK ioctls. */ struct tw_cl_lock_packet { TW_UINT32 timeout_msec; TW_UINT32 time_remaining_msec; TW_UINT32 force_flag; }; /* Structure used to handle GET COMPATIBILITY INFO ioctl. */ struct tw_cl_compatibility_packet { TW_UINT8 driver_version[32];/* driver version */ TW_UINT16 working_srl; /* driver & firmware negotiated srl */ TW_UINT16 working_branch; /* branch # of the firmware that the driver is compatible with */ TW_UINT16 working_build; /* build # of the firmware that the driver is compatible with */ }; /* Driver understandable part of the ioctl packet built by the API. */ struct tw_cl_driver_packet { TW_UINT32 control_code; TW_UINT32 status; TW_UINT32 unique_id; TW_UINT32 sequence_id; TW_UINT32 os_status; TW_UINT32 buffer_length; }; #pragma pack() /* * Following cut out of tw_osl_ioctl.h * */ #pragma pack(1) /* * We need the structure below to ensure that the first byte of * data_buf is not overwritten by the kernel, after we return * from the ioctl call. Note that cmd_pkt has been reduced * to an array of 1024 bytes even though it's actually 2048 bytes * in size. This is because, we don't expect requests from user * land requiring 2048 (273 sg elements) byte cmd pkts. */ typedef struct tw_osli_ioctl_no_data_buf { struct tw_cl_driver_packet driver_pkt; TW_VOID *pdata; /* points to data_buf */ TW_INT8 padding[488 - sizeof(TW_VOID *)]; struct tw_cl_command_packet cmd_pkt; } TW_OSLI_IOCTL_NO_DATA_BUF; #pragma pack() #define TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH \ _IOWR('T', 202, TW_OSLI_IOCTL_NO_DATA_BUF) #pragma pack(1) typedef struct tw_osli_ioctl_with_payload { struct tw_cl_driver_packet driver_pkt; TW_INT8 padding[488]; struct tw_cl_command_packet cmd_pkt; union { struct tw_cl_event_packet event_pkt; struct tw_cl_lock_packet lock_pkt; struct tw_cl_compatibility_packet compat_pkt; TW_INT8 data_buf[1]; } payload; } TW_OSLI_IOCTL_WITH_PAYLOAD; #pragma pack() #endif #define HPT_CTL_CODE(x) (x+0xFF00) #define HPT_IOCTL_GET_CHANNEL_INFO HPT_CTL_CODE(3) #define HPT_IOCTL_GET_CHANNEL_INFO_V2 HPT_CTL_CODE(53) #define HPT_IOCTL_IDE_PASS_THROUGH HPT_CTL_CODE(24) #define HPT_READ 1 #define HPT_WRITE 2 #define HPT_IOCTL_MAGIC 0xA1B2C3D4 #define MAXDEV_PER_CHANNEL 2 #define PMPORT_PER_CHANNEL 15 /* max devices connected to this channel via pmport */ #pragma pack(1) typedef struct _HPT_CHANNEL_INFO { unsigned int reserve1; unsigned int reserve2; unsigned int devices[MAXDEV_PER_CHANNEL]; } HPT_CHANNEL_INFO, *PHPT_CHANNEL_INFO; typedef struct _HPT_CHANNEL_INFO_V2 { unsigned int reserve1; unsigned int reserve2; unsigned int devices[PMPORT_PER_CHANNEL]; } HPT_CHANNEL_INFO_V2, *PHPT_CHANNEL_INFO_V2; typedef struct _HPT_IOCTL_PARAM { unsigned int magic; /* used to check if it's a valid ioctl packet */ unsigned int ctrl_code; /* operation control code */ void* in; /* input data buffer */ unsigned int in_size; /* size of input data buffer */ void* out; /* output data buffer */ unsigned int out_size; /* size of output data buffer */ void* returned_size; /* count of chars returned */ } HPT_IOCTL_PARAM, *PHPT_IOCTL_PARAM; #define HPT_DO_IOCONTROL _IOW('H', 0, HPT_IOCTL_PARAM) typedef struct _HPT_PASS_THROUGH_HEADER { unsigned int id; /* disk ID */ unsigned char feature; unsigned char sectorcount; unsigned char lbalow; unsigned char lbamid; unsigned char lbahigh; unsigned char driverhead; unsigned char command; unsigned char sectors; /* data size in sectors, if the command has data transfer */ unsigned char protocol; /* HPT_(READ,WRITE) or zero for non-DATA */ unsigned char reserve[3]; } HPT_PASS_THROUGH_HEADER, *PHPT_PASS_THROUGH_HEADER; #pragma pack() #ifndef __unused #define __unused __attribute__ ((__unused__)) #endif #endif /* OS_FREEBSD_H_ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/scsiprint.h����������������������������������������������������������0000644�0000000�0000000�00000005202�12110055706�017244� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * scsiprint.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * Additional SCSI work: * Copyright (C) 2003-13 Douglas Gilbert <dgilbert@interlog.com> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef SCSI_PRINT_H_ #define SCSI_PRINT_H_ #define SCSIPRINT_H_CVSID "$Id: scsiprint.h 3776 2013-02-17 04:25:42Z dpgilbert $\n" // Options for scsiPrintMain struct scsi_print_options { bool drive_info; bool smart_check_status; bool smart_vendor_attrib; bool smart_error_log; bool smart_selftest_log; bool smart_background_log; bool smart_ss_media_log; bool smart_disable, smart_enable; bool smart_auto_save_disable, smart_auto_save_enable; bool smart_default_selftest; bool smart_short_selftest, smart_short_cap_selftest; bool smart_extend_selftest, smart_extend_cap_selftest; bool smart_selftest_abort; bool smart_selftest_force; // Ignore already running test bool sasphy, sasphy_reset; bool get_wce, get_rcd; short int set_wce, set_rcd; // disable(-1), enable(1) cache scsi_print_options() : drive_info(false), smart_check_status(false), smart_vendor_attrib(false), smart_error_log(false), smart_selftest_log(false), smart_background_log(false), smart_ss_media_log(false), smart_disable(false), smart_enable(false), smart_auto_save_disable(false), smart_auto_save_enable(false), smart_default_selftest(false), smart_short_selftest(false), smart_short_cap_selftest(false), smart_extend_selftest(false), smart_extend_cap_selftest(false), smart_selftest_abort(false), smart_selftest_force(false), sasphy(false), sasphy_reset(false), get_wce(false), get_rcd(false), set_wce(0), set_rcd(0) { } }; int scsiPrintMain(scsi_device * device, const scsi_print_options & options); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/regex/���������������������������������������������������������������0000755�0000000�0000000�00000000000�12212065523�016171� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/regex/regcomp.c������������������������������������������������������0000644�0000000�0000000�00000304750�12062407372�020007� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Extended regular expression matching and search library. Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern, int length, reg_syntax_t syntax); static void re_compile_fastmap_iter (regex_t *bufp, const re_dfastate_t *init_state, char *fastmap); static reg_errcode_t init_dfa (re_dfa_t *dfa, int pat_len); static reg_errcode_t init_word_char (re_dfa_t *dfa); #ifdef RE_ENABLE_I18N static void free_charset (re_charset_t *cset); #endif /* RE_ENABLE_I18N */ static void free_workarea_compile (regex_t *preg); static reg_errcode_t create_initial_state (re_dfa_t *dfa); static reg_errcode_t analyze (re_dfa_t *dfa); static reg_errcode_t analyze_tree (re_dfa_t *dfa, bin_tree_t *node); static void calc_first (re_dfa_t *dfa, bin_tree_t *node); static void calc_next (re_dfa_t *dfa, bin_tree_t *node); static void calc_epsdest (re_dfa_t *dfa, bin_tree_t *node); static reg_errcode_t duplicate_node_closure (re_dfa_t *dfa, int top_org_node, int top_clone_node, int root_node, unsigned int constraint); static reg_errcode_t duplicate_node (int *new_idx, re_dfa_t *dfa, int org_idx, unsigned int constraint); static int search_duplicated_node (re_dfa_t *dfa, int org_node, unsigned int constraint); static reg_errcode_t calc_eclosure (re_dfa_t *dfa); static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, int node, int root); static void calc_inveclosure (re_dfa_t *dfa); static int fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax); static re_token_t fetch_token (re_string_t *input, reg_syntax_t syntax); static int peek_token (re_token_t *token, re_string_t *input, reg_syntax_t syntax); static int peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax); static bin_tree_t *parse (re_string_t *regexp, regex_t *preg, reg_syntax_t syntax, reg_errcode_t *err); static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg, re_token_t *token, reg_syntax_t syntax, int nest, reg_errcode_t *err); static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err); static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token, reg_syntax_t syntax, reg_errcode_t *err); static reg_errcode_t parse_bracket_element (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token, int token_len, re_dfa_t *dfa, reg_syntax_t syntax); static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem, re_string_t *regexp, re_token_t *token); #ifndef _LIBC # ifdef RE_ENABLE_I18N static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, re_charset_t *mbcset, int *range_alloc, bracket_elem_t *start_elem, bracket_elem_t *end_elem); static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, re_charset_t *mbcset, int *coll_sym_alloc, const unsigned char *name); # else /* not RE_ENABLE_I18N */ static reg_errcode_t build_range_exp (re_bitset_ptr_t sbcset, bracket_elem_t *start_elem, bracket_elem_t *end_elem); static reg_errcode_t build_collating_symbol (re_bitset_ptr_t sbcset, const unsigned char *name); # endif /* not RE_ENABLE_I18N */ #endif /* not _LIBC */ #ifdef RE_ENABLE_I18N static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, re_charset_t *mbcset, int *equiv_class_alloc, const unsigned char *name); static reg_errcode_t build_charclass (re_bitset_ptr_t sbcset, re_charset_t *mbcset, int *char_class_alloc, const unsigned char *class_name, reg_syntax_t syntax); #else /* not RE_ENABLE_I18N */ static reg_errcode_t build_equiv_class (re_bitset_ptr_t sbcset, const unsigned char *name); static reg_errcode_t build_charclass (re_bitset_ptr_t sbcset, const unsigned char *class_name, reg_syntax_t syntax); #endif /* not RE_ENABLE_I18N */ static bin_tree_t *build_word_op (re_dfa_t *dfa, int not, reg_errcode_t *err); static void free_bin_tree (bin_tree_t *tree); static bin_tree_t *create_tree (bin_tree_t *left, bin_tree_t *right, re_token_type_t type, int index); static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa); /* This table gives an error message for each of the error codes listed in regex.h. Obviously the order here has to be same as there. POSIX doesn't require that we do anything for REG_NOERROR, but why not be nice? */ const char __re_error_msgid[] attribute_hidden = { #define REG_NOERROR_IDX 0 gettext_noop ("Success") /* REG_NOERROR */ "\0" #define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success") gettext_noop ("No match") /* REG_NOMATCH */ "\0" #define REG_BADPAT_IDX (REG_NOMATCH_IDX + sizeof "No match") gettext_noop ("Invalid regular expression") /* REG_BADPAT */ "\0" #define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression") gettext_noop ("Invalid collation character") /* REG_ECOLLATE */ "\0" #define REG_ECTYPE_IDX (REG_ECOLLATE_IDX + sizeof "Invalid collation character") gettext_noop ("Invalid character class name") /* REG_ECTYPE */ "\0" #define REG_EESCAPE_IDX (REG_ECTYPE_IDX + sizeof "Invalid character class name") gettext_noop ("Trailing backslash") /* REG_EESCAPE */ "\0" #define REG_ESUBREG_IDX (REG_EESCAPE_IDX + sizeof "Trailing backslash") gettext_noop ("Invalid back reference") /* REG_ESUBREG */ "\0" #define REG_EBRACK_IDX (REG_ESUBREG_IDX + sizeof "Invalid back reference") gettext_noop ("Unmatched [ or [^") /* REG_EBRACK */ "\0" #define REG_EPAREN_IDX (REG_EBRACK_IDX + sizeof "Unmatched [ or [^") gettext_noop ("Unmatched ( or \\(") /* REG_EPAREN */ "\0" #define REG_EBRACE_IDX (REG_EPAREN_IDX + sizeof "Unmatched ( or \\(") gettext_noop ("Unmatched \\{") /* REG_EBRACE */ "\0" #define REG_BADBR_IDX (REG_EBRACE_IDX + sizeof "Unmatched \\{") gettext_noop ("Invalid content of \\{\\}") /* REG_BADBR */ "\0" #define REG_ERANGE_IDX (REG_BADBR_IDX + sizeof "Invalid content of \\{\\}") gettext_noop ("Invalid range end") /* REG_ERANGE */ "\0" #define REG_ESPACE_IDX (REG_ERANGE_IDX + sizeof "Invalid range end") gettext_noop ("Memory exhausted") /* REG_ESPACE */ "\0" #define REG_BADRPT_IDX (REG_ESPACE_IDX + sizeof "Memory exhausted") gettext_noop ("Invalid preceding regular expression") /* REG_BADRPT */ "\0" #define REG_EEND_IDX (REG_BADRPT_IDX + sizeof "Invalid preceding regular expression") gettext_noop ("Premature end of regular expression") /* REG_EEND */ "\0" #define REG_ESIZE_IDX (REG_EEND_IDX + sizeof "Premature end of regular expression") gettext_noop ("Regular expression too big") /* REG_ESIZE */ "\0" #define REG_ERPAREN_IDX (REG_ESIZE_IDX + sizeof "Regular expression too big") gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ }; const size_t __re_error_msgid_idx[] attribute_hidden = { REG_NOERROR_IDX, REG_NOMATCH_IDX, REG_BADPAT_IDX, REG_ECOLLATE_IDX, REG_ECTYPE_IDX, REG_EESCAPE_IDX, REG_ESUBREG_IDX, REG_EBRACK_IDX, REG_EPAREN_IDX, REG_EBRACE_IDX, REG_BADBR_IDX, REG_ERANGE_IDX, REG_ESPACE_IDX, REG_BADRPT_IDX, REG_EEND_IDX, REG_ESIZE_IDX, REG_ERPAREN_IDX }; /* Entry points for GNU code. */ /* re_compile_pattern is the GNU regular expression compiler: it compiles PATTERN (of length LENGTH) and puts the result in BUFP. Returns 0 if the pattern was valid, otherwise an error string. Assumes the `allocated' (and perhaps `buffer') and `translate' fields are set in BUFP on entry. */ const char * re_compile_pattern (pattern, length, bufp) const char *pattern; size_t length; struct re_pattern_buffer *bufp; { reg_errcode_t ret; /* And GNU code determines whether or not to get register information by passing null for the REGS argument to re_match, etc., not by setting no_sub. */ bufp->no_sub = 0; /* Match anchors at newline. */ bufp->newline_anchor = 1; ret = re_compile_internal (bufp, pattern, length, re_syntax_options); if (!ret) return NULL; return gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); } #ifdef _LIBC weak_alias (__re_compile_pattern, re_compile_pattern) #endif /* Set by `re_set_syntax' to the current regexp syntax to recognize. Can also be assigned to arbitrarily: each pattern buffer stores its own syntax, so it can be changed between regex compilations. */ /* This has no initializer because initialized variables in Emacs become read-only after dumping. */ reg_syntax_t re_syntax_options; /* Specify the precise syntax of regexps for compilation. This provides for compatibility for various utilities which historically have different, incompatible syntaxes. The argument SYNTAX is a bit mask comprised of the various bits defined in regex.h. We return the old syntax. */ reg_syntax_t re_set_syntax (syntax) reg_syntax_t syntax; { reg_syntax_t ret = re_syntax_options; re_syntax_options = syntax; return ret; } #ifdef _LIBC weak_alias (__re_set_syntax, re_set_syntax) #endif int re_compile_fastmap (bufp) struct re_pattern_buffer *bufp; { re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; char *fastmap = bufp->fastmap; memset (fastmap, '\0', sizeof (char) * SBC_MAX); re_compile_fastmap_iter (bufp, dfa->init_state, fastmap); if (dfa->init_state != dfa->init_state_word) re_compile_fastmap_iter (bufp, dfa->init_state_word, fastmap); if (dfa->init_state != dfa->init_state_nl) re_compile_fastmap_iter (bufp, dfa->init_state_nl, fastmap); if (dfa->init_state != dfa->init_state_begbuf) re_compile_fastmap_iter (bufp, dfa->init_state_begbuf, fastmap); bufp->fastmap_accurate = 1; return 0; } #ifdef _LIBC weak_alias (__re_compile_fastmap, re_compile_fastmap) #endif static inline void re_set_fastmap (char *fastmap, int icase, int ch) { fastmap[ch] = 1; if (icase) fastmap[tolower (ch)] = 1; } /* Helper function for re_compile_fastmap. Compile fastmap for the initial_state INIT_STATE. */ static void re_compile_fastmap_iter (bufp, init_state, fastmap) regex_t *bufp; const re_dfastate_t *init_state; char *fastmap; { re_dfa_t *dfa = (re_dfa_t *) bufp->buffer; int node_cnt; int icase = (MB_CUR_MAX == 1 && (bufp->syntax & RE_ICASE)); for (node_cnt = 0; node_cnt < init_state->nodes.nelem; ++node_cnt) { int node = init_state->nodes.elems[node_cnt]; re_token_type_t type = dfa->nodes[node].type; if (type == CHARACTER) re_set_fastmap (fastmap, icase, dfa->nodes[node].opr.c); else if (type == SIMPLE_BRACKET) { int i, j, ch; for (i = 0, ch = 0; i < BITSET_UINTS; ++i) for (j = 0; j < UINT_BITS; ++j, ++ch) if (dfa->nodes[node].opr.sbcset[i] & (1 << j)) re_set_fastmap (fastmap, icase, ch); } #ifdef RE_ENABLE_I18N else if (type == COMPLEX_BRACKET) { int i; re_charset_t *cset = dfa->nodes[node].opr.mbcset; if (cset->non_match || cset->ncoll_syms || cset->nequiv_classes || cset->nranges || cset->nchar_classes) { # ifdef _LIBC if (_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES) != 0) { /* In this case we want to catch the bytes which are the first byte of any collation elements. e.g. In da_DK, we want to catch 'a' since "aa" is a valid collation element, and don't catch 'b' since 'b' is the only collation element which starts from 'b'. */ int j, ch; const int32_t *table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); for (i = 0, ch = 0; i < BITSET_UINTS; ++i) for (j = 0; j < UINT_BITS; ++j, ++ch) if (table[ch] < 0) re_set_fastmap (fastmap, icase, ch); } # else if (MB_CUR_MAX > 1) for (i = 0; i < SBC_MAX; ++i) if (__btowc (i) == WEOF) re_set_fastmap (fastmap, icase, i); # endif /* not _LIBC */ } for (i = 0; i < cset->nmbchars; ++i) { char buf[256]; mbstate_t state; memset (&state, '\0', sizeof (state)); __wcrtomb (buf, cset->mbchars[i], &state); re_set_fastmap (fastmap, icase, *(unsigned char *) buf); } } #endif /* RE_ENABLE_I18N */ else if (type == END_OF_RE || type == OP_PERIOD) { memset (fastmap, '\1', sizeof (char) * SBC_MAX); if (type == END_OF_RE) bufp->can_be_null = 1; return; } } } /* Entry point for POSIX code. */ /* regcomp takes a regular expression as a string and compiles it. PREG is a regex_t *. We do not expect any fields to be initialized, since POSIX says we shouldn't. Thus, we set `buffer' to the compiled pattern; `used' to the length of the compiled pattern; `syntax' to RE_SYNTAX_POSIX_EXTENDED if the REG_EXTENDED bit in CFLAGS is set; otherwise, to RE_SYNTAX_POSIX_BASIC; `newline_anchor' to REG_NEWLINE being set in CFLAGS; `fastmap' to an allocated space for the fastmap; `fastmap_accurate' to zero; `re_nsub' to the number of subexpressions in PATTERN. PATTERN is the address of the pattern string. CFLAGS is a series of bits which affect compilation. If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we use POSIX basic syntax. If REG_NEWLINE is set, then . and [^...] don't match newline. Also, regexec will try a match beginning after every newline. If REG_ICASE is set, then we considers upper- and lowercase versions of letters to be equivalent when matching. If REG_NOSUB is set, then when PREG is passed to regexec, that routine will report only success or failure, and nothing about the registers. It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for the return codes and their meanings.) */ int regcomp (preg, pattern, cflags) regex_t *__restrict preg; const char *__restrict pattern; int cflags; { reg_errcode_t ret; reg_syntax_t syntax = ((cflags & REG_EXTENDED) ? RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC); preg->buffer = NULL; preg->allocated = 0; preg->used = 0; /* Try to allocate space for the fastmap. */ preg->fastmap = re_malloc (char, SBC_MAX); if (BE (preg->fastmap == NULL, 0)) return REG_ESPACE; syntax |= (cflags & REG_ICASE) ? RE_ICASE : 0; /* If REG_NEWLINE is set, newlines are treated differently. */ if (cflags & REG_NEWLINE) { /* REG_NEWLINE implies neither . nor [^...] match newline. */ syntax &= ~RE_DOT_NEWLINE; syntax |= RE_HAT_LISTS_NOT_NEWLINE; /* It also changes the matching behavior. */ preg->newline_anchor = 1; } else preg->newline_anchor = 0; preg->no_sub = !!(cflags & REG_NOSUB); preg->translate = NULL; ret = re_compile_internal (preg, pattern, strlen (pattern), syntax); /* POSIX doesn't distinguish between an unmatched open-group and an unmatched close-group: both are REG_EPAREN. */ if (ret == REG_ERPAREN) ret = REG_EPAREN; /* We have already checked preg->fastmap != NULL. */ if (BE (ret == REG_NOERROR, 1)) /* Compute the fastmap now, since regexec cannot modify the pattern buffer. This function nevers fails in this implementation. */ (void) re_compile_fastmap (preg); else { /* Some error occurred while compiling the expression. */ re_free (preg->fastmap); preg->fastmap = NULL; } return (int) ret; } #ifdef _LIBC weak_alias (__regcomp, regcomp) #endif /* Returns a message corresponding to an error code, ERRCODE, returned from either regcomp or regexec. We don't use PREG here. */ size_t regerror (errcode, preg, errbuf, errbuf_size) int errcode; const regex_t *preg; char *errbuf; size_t errbuf_size; { const char *msg; size_t msg_size; if (BE (errcode < 0 || errcode >= (int) (sizeof (__re_error_msgid_idx) / sizeof (__re_error_msgid_idx[0])), 0)) /* Only error codes returned by the rest of the code should be passed to this routine. If we are given anything else, or if other regex code generates an invalid error code, then the program has a bug. Dump core so we can fix it. */ abort (); msg = gettext (__re_error_msgid + __re_error_msgid_idx[errcode]); msg_size = strlen (msg) + 1; /* Includes the null. */ if (BE (errbuf_size != 0, 1)) { if (BE (msg_size > errbuf_size, 0)) { #if defined HAVE_MEMPCPY || defined _LIBC *((char *) __mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; #else memcpy (errbuf, msg, errbuf_size - 1); errbuf[errbuf_size - 1] = 0; #endif } else memcpy (errbuf, msg, msg_size); } return msg_size; } #ifdef _LIBC weak_alias (__regerror, regerror) #endif static void free_dfa_content (re_dfa_t *dfa) { int i, j; re_free (dfa->subexps); for (i = 0; i < dfa->nodes_len; ++i) { re_token_t *node = dfa->nodes + i; #ifdef RE_ENABLE_I18N if (node->type == COMPLEX_BRACKET && node->duplicated == 0) free_charset (node->opr.mbcset); else #endif /* RE_ENABLE_I18N */ if (node->type == SIMPLE_BRACKET && node->duplicated == 0) re_free (node->opr.sbcset); } re_free (dfa->nexts); for (i = 0; i < dfa->nodes_len; ++i) { if (dfa->eclosures != NULL) re_node_set_free (dfa->eclosures + i); if (dfa->inveclosures != NULL) re_node_set_free (dfa->inveclosures + i); if (dfa->edests != NULL) re_node_set_free (dfa->edests + i); } re_free (dfa->edests); re_free (dfa->eclosures); re_free (dfa->inveclosures); re_free (dfa->nodes); for (i = 0; i <= dfa->state_hash_mask; ++i) { struct re_state_table_entry *entry = dfa->state_table + i; for (j = 0; j < entry->num; ++j) { re_dfastate_t *state = entry->array[j]; free_state (state); } re_free (entry->array); } re_free (dfa->state_table); if (dfa->word_char != NULL) re_free (dfa->word_char); #ifdef DEBUG re_free (dfa->re_str); #endif re_free (dfa); } /* Free dynamically allocated space used by PREG. */ void regfree (preg) regex_t *preg; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; if (BE (dfa != NULL, 1)) free_dfa_content (dfa); re_free (preg->fastmap); } #ifdef _LIBC weak_alias (__regfree, regfree) #endif /* Entry points compatible with 4.2 BSD regex library. We don't define them unless specifically requested. */ #if defined _REGEX_RE_COMP || defined _LIBC /* BSD has one and only one pattern buffer. */ static struct re_pattern_buffer re_comp_buf; char * # ifdef _LIBC /* Make these definitions weak in libc, so POSIX programs can redefine these names if they don't use our functions, and still use regcomp/regexec above without link errors. */ weak_function # endif re_comp (s) const char *s; { reg_errcode_t ret; char *fastmap; if (!s) { if (!re_comp_buf.buffer) return gettext ("No previous regular expression"); return 0; } if (re_comp_buf.buffer) { fastmap = re_comp_buf.fastmap; re_comp_buf.fastmap = NULL; __regfree (&re_comp_buf); memset (&re_comp_buf, '\0', sizeof (re_comp_buf)); re_comp_buf.fastmap = fastmap; } if (re_comp_buf.fastmap == NULL) { re_comp_buf.fastmap = (char *) malloc (SBC_MAX); if (re_comp_buf.fastmap == NULL) return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) REG_ESPACE]); } /* Since `re_exec' always passes NULL for the `regs' argument, we don't need to initialize the pattern buffer fields which affect it. */ /* Match anchors at newlines. */ re_comp_buf.newline_anchor = 1; ret = re_compile_internal (&re_comp_buf, s, strlen (s), re_syntax_options); if (!ret) return NULL; /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ return (char *) gettext (__re_error_msgid + __re_error_msgid_idx[(int) ret]); } #ifdef _LIBC libc_freeres_fn (free_mem) { __regfree (&re_comp_buf); } #endif #endif /* _REGEX_RE_COMP */ /* Internal entry point. Compile the regular expression PATTERN, whose length is LENGTH. SYNTAX indicate regular expression's syntax. */ static reg_errcode_t re_compile_internal (preg, pattern, length, syntax) regex_t *preg; const char * pattern; int length; reg_syntax_t syntax; { reg_errcode_t err = REG_NOERROR; re_dfa_t *dfa; re_string_t regexp; /* Initialize the pattern buffer. */ preg->fastmap_accurate = 0; preg->syntax = syntax; preg->not_bol = preg->not_eol = 0; preg->used = 0; preg->re_nsub = 0; preg->can_be_null = 0; preg->regs_allocated = REGS_UNALLOCATED; /* Initialize the dfa. */ dfa = (re_dfa_t *) preg->buffer; if (preg->allocated < sizeof (re_dfa_t)) { /* If zero allocated, but buffer is non-null, try to realloc enough space. This loses if buffer's address is bogus, but that is the user's responsibility. If ->buffer is NULL this is a simple allocation. */ dfa = re_realloc (preg->buffer, re_dfa_t, 1); if (dfa == NULL) return REG_ESPACE; preg->allocated = sizeof (re_dfa_t); } preg->buffer = (unsigned char *) dfa; preg->used = sizeof (re_dfa_t); err = init_dfa (dfa, length); if (BE (err != REG_NOERROR, 0)) { re_free (dfa); preg->buffer = NULL; preg->allocated = 0; return err; } #ifdef DEBUG dfa->re_str = re_malloc (char, length + 1); strncpy (dfa->re_str, pattern, length + 1); #endif err = re_string_construct (®exp, pattern, length, preg->translate, syntax & RE_ICASE); if (BE (err != REG_NOERROR, 0)) { re_free (dfa); preg->buffer = NULL; preg->allocated = 0; return err; } /* Parse the regular expression, and build a structure tree. */ preg->re_nsub = 0; dfa->str_tree = parse (®exp, preg, syntax, &err); if (BE (dfa->str_tree == NULL, 0)) goto re_compile_internal_free_return; /* Analyze the tree and collect information which is necessary to create the dfa. */ err = analyze (dfa); if (BE (err != REG_NOERROR, 0)) goto re_compile_internal_free_return; /* Then create the initial state of the dfa. */ err = create_initial_state (dfa); /* Release work areas. */ free_workarea_compile (preg); re_string_destruct (®exp); if (BE (err != REG_NOERROR, 0)) { re_compile_internal_free_return: free_dfa_content (dfa); preg->buffer = NULL; preg->allocated = 0; } return err; } /* Initialize DFA. We use the length of the regular expression PAT_LEN as the initial length of some arrays. */ static reg_errcode_t init_dfa (dfa, pat_len) re_dfa_t *dfa; int pat_len; { int table_size; memset (dfa, '\0', sizeof (re_dfa_t)); dfa->nodes_alloc = pat_len + 1; dfa->nodes = re_malloc (re_token_t, dfa->nodes_alloc); dfa->states_alloc = pat_len + 1; /* table_size = 2 ^ ceil(log pat_len) */ for (table_size = 1; table_size > 0; table_size <<= 1) if (table_size > pat_len) break; dfa->state_table = calloc (sizeof (struct re_state_table_entry), table_size); dfa->state_hash_mask = table_size - 1; dfa->subexps_alloc = 1; dfa->subexps = re_malloc (re_subexp_t, dfa->subexps_alloc); dfa->word_char = NULL; if (BE (dfa->nodes == NULL || dfa->state_table == NULL || dfa->subexps == NULL, 0)) { /* We don't bother to free anything which was allocated. Very soon the process will go down anyway. */ dfa->subexps = NULL; dfa->state_table = NULL; dfa->nodes = NULL; return REG_ESPACE; } return REG_NOERROR; } /* Initialize WORD_CHAR table, which indicate which character is "word". In this case "word" means that it is the word construction character used by some operators like "\<", "\>", etc. */ static reg_errcode_t init_word_char (dfa) re_dfa_t *dfa; { int i, j, ch; dfa->word_char = (re_bitset_ptr_t) calloc (sizeof (bitset), 1); if (BE (dfa->word_char == NULL, 0)) return REG_ESPACE; for (i = 0, ch = 0; i < BITSET_UINTS; ++i) for (j = 0; j < UINT_BITS; ++j, ++ch) if (isalnum (ch) || ch == '_') dfa->word_char[i] |= 1 << j; return REG_NOERROR; } /* Free the work area which are only used while compiling. */ static void free_workarea_compile (preg) regex_t *preg; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; free_bin_tree (dfa->str_tree); dfa->str_tree = NULL; re_free (dfa->org_indices); dfa->org_indices = NULL; } /* Create initial states for all contexts. */ static reg_errcode_t create_initial_state (dfa) re_dfa_t *dfa; { int first, i; reg_errcode_t err; re_node_set init_nodes; /* Initial states have the epsilon closure of the node which is the first node of the regular expression. */ first = dfa->str_tree->first; dfa->init_node = first; err = re_node_set_init_copy (&init_nodes, dfa->eclosures + first); if (BE (err != REG_NOERROR, 0)) return err; /* The back-references which are in initial states can epsilon transit, since in this case all of the subexpressions can be null. Then we add epsilon closures of the nodes which are the next nodes of the back-references. */ if (dfa->nbackref > 0) for (i = 0; i < init_nodes.nelem; ++i) { int node_idx = init_nodes.elems[i]; re_token_type_t type = dfa->nodes[node_idx].type; int clexp_idx; if (type != OP_BACK_REF) continue; for (clexp_idx = 0; clexp_idx < init_nodes.nelem; ++clexp_idx) { re_token_t *clexp_node; clexp_node = dfa->nodes + init_nodes.elems[clexp_idx]; if (clexp_node->type == OP_CLOSE_SUBEXP && clexp_node->opr.idx + 1 == dfa->nodes[node_idx].opr.idx) break; } if (clexp_idx == init_nodes.nelem) continue; if (type == OP_BACK_REF) { int dest_idx = dfa->edests[node_idx].elems[0]; if (!re_node_set_contains (&init_nodes, dest_idx)) { re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx); i = 0; } } } /* It must be the first time to invoke acquire_state. */ dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0); /* We don't check ERR here, since the initial state must not be NULL. */ if (BE (dfa->init_state == NULL, 0)) return err; if (dfa->init_state->has_constraint) { dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes, CONTEXT_WORD); dfa->init_state_nl = re_acquire_state_context (&err, dfa, &init_nodes, CONTEXT_NEWLINE); dfa->init_state_begbuf = re_acquire_state_context (&err, dfa, &init_nodes, CONTEXT_NEWLINE | CONTEXT_BEGBUF); if (BE (dfa->init_state_word == NULL || dfa->init_state_nl == NULL || dfa->init_state_begbuf == NULL, 0)) return err; } else dfa->init_state_word = dfa->init_state_nl = dfa->init_state_begbuf = dfa->init_state; re_node_set_free (&init_nodes); return REG_NOERROR; } /* Analyze the structure tree, and calculate "first", "next", "edest", "eclosure", and "inveclosure". */ static reg_errcode_t analyze (dfa) re_dfa_t *dfa; { int i; reg_errcode_t ret; /* Allocate arrays. */ dfa->nexts = re_malloc (int, dfa->nodes_alloc); dfa->org_indices = re_malloc (int, dfa->nodes_alloc); dfa->edests = re_malloc (re_node_set, dfa->nodes_alloc); dfa->eclosures = re_malloc (re_node_set, dfa->nodes_alloc); dfa->inveclosures = re_malloc (re_node_set, dfa->nodes_alloc); if (BE (dfa->nexts == NULL || dfa->org_indices == NULL || dfa->edests == NULL || dfa->eclosures == NULL || dfa->inveclosures == NULL, 0)) return REG_ESPACE; /* Initialize them. */ for (i = 0; i < dfa->nodes_len; ++i) { dfa->nexts[i] = -1; re_node_set_init_empty (dfa->edests + i); re_node_set_init_empty (dfa->eclosures + i); re_node_set_init_empty (dfa->inveclosures + i); } ret = analyze_tree (dfa, dfa->str_tree); if (BE (ret == REG_NOERROR, 1)) { ret = calc_eclosure (dfa); if (ret == REG_NOERROR) calc_inveclosure (dfa); } return ret; } /* Helper functions for analyze. This function calculate "first", "next", and "edest" for the subtree whose root is NODE. */ static reg_errcode_t analyze_tree (dfa, node) re_dfa_t *dfa; bin_tree_t *node; { reg_errcode_t ret; if (node->first == -1) calc_first (dfa, node); if (node->next == -1) calc_next (dfa, node); if (node->eclosure.nelem == 0) calc_epsdest (dfa, node); /* Calculate "first" etc. for the left child. */ if (node->left != NULL) { ret = analyze_tree (dfa, node->left); if (BE (ret != REG_NOERROR, 0)) return ret; } /* Calculate "first" etc. for the right child. */ if (node->right != NULL) { ret = analyze_tree (dfa, node->right); if (BE (ret != REG_NOERROR, 0)) return ret; } return REG_NOERROR; } /* Calculate "first" for the node NODE. */ static void calc_first (dfa, node) re_dfa_t *dfa; bin_tree_t *node; { int idx, type; idx = node->node_idx; type = (node->type == 0) ? dfa->nodes[idx].type : node->type; switch (type) { #ifdef DEBUG case OP_OPEN_BRACKET: case OP_CLOSE_BRACKET: case OP_OPEN_DUP_NUM: case OP_CLOSE_DUP_NUM: case OP_NON_MATCH_LIST: case OP_OPEN_COLL_ELEM: case OP_CLOSE_COLL_ELEM: case OP_OPEN_EQUIV_CLASS: case OP_CLOSE_EQUIV_CLASS: case OP_OPEN_CHAR_CLASS: case OP_CLOSE_CHAR_CLASS: /* These must not be appeared here. */ assert (0); #endif case END_OF_RE: case CHARACTER: case OP_PERIOD: case OP_DUP_ASTERISK: case OP_DUP_QUESTION: #ifdef RE_ENABLE_I18N case COMPLEX_BRACKET: #endif /* RE_ENABLE_I18N */ case SIMPLE_BRACKET: case OP_BACK_REF: case ANCHOR: case OP_OPEN_SUBEXP: case OP_CLOSE_SUBEXP: node->first = idx; break; case OP_DUP_PLUS: #ifdef DEBUG assert (node->left != NULL); #endif if (node->left->first == -1) calc_first (dfa, node->left); node->first = node->left->first; break; case OP_ALT: node->first = idx; break; /* else fall through */ default: #ifdef DEBUG assert (node->left != NULL); #endif if (node->left->first == -1) calc_first (dfa, node->left); node->first = node->left->first; break; } } /* Calculate "next" for the node NODE. */ static void calc_next (dfa, node) re_dfa_t *dfa; bin_tree_t *node; { int idx, type; bin_tree_t *parent = node->parent; if (parent == NULL) { node->next = -1; idx = node->node_idx; if (node->type == 0) dfa->nexts[idx] = node->next; return; } idx = parent->node_idx; type = (parent->type == 0) ? dfa->nodes[idx].type : parent->type; switch (type) { case OP_DUP_ASTERISK: case OP_DUP_PLUS: node->next = idx; break; case CONCAT: if (parent->left == node) { if (parent->right->first == -1) calc_first (dfa, parent->right); node->next = parent->right->first; break; } /* else fall through */ default: if (parent->next == -1) calc_next (dfa, parent); node->next = parent->next; break; } idx = node->node_idx; if (node->type == 0) dfa->nexts[idx] = node->next; } /* Calculate "edest" for the node NODE. */ static void calc_epsdest (dfa, node) re_dfa_t *dfa; bin_tree_t *node; { int idx; idx = node->node_idx; if (node->type == 0) { if (dfa->nodes[idx].type == OP_DUP_ASTERISK || dfa->nodes[idx].type == OP_DUP_PLUS || dfa->nodes[idx].type == OP_DUP_QUESTION) { if (node->left->first == -1) calc_first (dfa, node->left); if (node->next == -1) calc_next (dfa, node); re_node_set_init_2 (dfa->edests + idx, node->left->first, node->next); } else if (dfa->nodes[idx].type == OP_ALT) { int left, right; if (node->left != NULL) { if (node->left->first == -1) calc_first (dfa, node->left); left = node->left->first; } else { if (node->next == -1) calc_next (dfa, node); left = node->next; } if (node->right != NULL) { if (node->right->first == -1) calc_first (dfa, node->right); right = node->right->first; } else { if (node->next == -1) calc_next (dfa, node); right = node->next; } re_node_set_init_2 (dfa->edests + idx, left, right); } else if (dfa->nodes[idx].type == ANCHOR || dfa->nodes[idx].type == OP_OPEN_SUBEXP || dfa->nodes[idx].type == OP_CLOSE_SUBEXP || dfa->nodes[idx].type == OP_BACK_REF) re_node_set_init_1 (dfa->edests + idx, node->next); } } /* Duplicate the epsilon closure of the node ROOT_NODE. Note that duplicated nodes have constraint INIT_CONSTRAINT in addition to their own constraint. */ static reg_errcode_t duplicate_node_closure (dfa, top_org_node, top_clone_node, root_node, init_constraint) re_dfa_t *dfa; int top_org_node, top_clone_node, root_node; unsigned int init_constraint; { reg_errcode_t err; int org_node, clone_node, ret; unsigned int constraint = init_constraint; for (org_node = top_org_node, clone_node = top_clone_node;;) { int org_dest, clone_dest; if (dfa->nodes[org_node].type == OP_BACK_REF) { /* If the back reference epsilon-transit, its destination must also have the constraint. Then duplicate the epsilon closure of the destination of the back reference, and store it in edests of the back reference. */ org_dest = dfa->nexts[org_node]; re_node_set_empty (dfa->edests + clone_node); err = duplicate_node (&clone_dest, dfa, org_dest, constraint); if (BE (err != REG_NOERROR, 0)) return err; dfa->nexts[clone_node] = dfa->nexts[org_node]; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } else if (dfa->edests[org_node].nelem == 0) { /* In case of the node can't epsilon-transit, don't duplicate the destination and store the original destination as the destination of the node. */ dfa->nexts[clone_node] = dfa->nexts[org_node]; break; } else if (dfa->edests[org_node].nelem == 1) { /* In case of the node can epsilon-transit, and it has only one destination. */ org_dest = dfa->edests[org_node].elems[0]; re_node_set_empty (dfa->edests + clone_node); if (dfa->nodes[org_node].type == ANCHOR) { /* In case of the node has another constraint, append it. */ if (org_node == root_node && clone_node != org_node) { /* ...but if the node is root_node itself, it means the epsilon closure have a loop, then tie it to the destination of the root_node. */ ret = re_node_set_insert (dfa->edests + clone_node, org_dest); if (BE (ret < 0, 0)) return REG_ESPACE; break; } constraint |= dfa->nodes[org_node].opr.ctx_type; } err = duplicate_node (&clone_dest, dfa, org_dest, constraint); if (BE (err != REG_NOERROR, 0)) return err; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } else /* dfa->edests[org_node].nelem == 2 */ { /* In case of the node can epsilon-transit, and it has two destinations. E.g. '|', '*', '+', '?'. */ org_dest = dfa->edests[org_node].elems[0]; re_node_set_empty (dfa->edests + clone_node); /* Search for a duplicated node which satisfies the constraint. */ clone_dest = search_duplicated_node (dfa, org_dest, constraint); if (clone_dest == -1) { /* There are no such a duplicated node, create a new one. */ err = duplicate_node (&clone_dest, dfa, org_dest, constraint); if (BE (err != REG_NOERROR, 0)) return err; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; err = duplicate_node_closure (dfa, org_dest, clone_dest, root_node, constraint); if (BE (err != REG_NOERROR, 0)) return err; } else { /* There are a duplicated node which satisfy the constraint, use it to avoid infinite loop. */ ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } org_dest = dfa->edests[org_node].elems[1]; err = duplicate_node (&clone_dest, dfa, org_dest, constraint); if (BE (err != REG_NOERROR, 0)) return err; ret = re_node_set_insert (dfa->edests + clone_node, clone_dest); if (BE (ret < 0, 0)) return REG_ESPACE; } org_node = org_dest; clone_node = clone_dest; } return REG_NOERROR; } /* Search for a node which is duplicated from the node ORG_NODE, and satisfies the constraint CONSTRAINT. */ static int search_duplicated_node (dfa, org_node, constraint) re_dfa_t *dfa; int org_node; unsigned int constraint; { int idx; for (idx = dfa->nodes_len - 1; dfa->nodes[idx].duplicated && idx > 0; --idx) { if (org_node == dfa->org_indices[idx] && constraint == dfa->nodes[idx].constraint) return idx; /* Found. */ } return -1; /* Not found. */ } /* Duplicate the node whose index is ORG_IDX and set the constraint CONSTRAINT. The new index will be stored in NEW_IDX and return REG_NOERROR if succeeded, otherwise return the error code. */ static reg_errcode_t duplicate_node (new_idx, dfa, org_idx, constraint) re_dfa_t *dfa; int *new_idx, org_idx; unsigned int constraint; { re_token_t dup; int dup_idx; dup = dfa->nodes[org_idx]; dup_idx = re_dfa_add_node (dfa, dup, 1); if (BE (dup_idx == -1, 0)) return REG_ESPACE; dfa->nodes[dup_idx].constraint = constraint; if (dfa->nodes[org_idx].type == ANCHOR) dfa->nodes[dup_idx].constraint |= dfa->nodes[org_idx].opr.ctx_type; dfa->nodes[dup_idx].duplicated = 1; re_node_set_init_empty (dfa->edests + dup_idx); re_node_set_init_empty (dfa->eclosures + dup_idx); re_node_set_init_empty (dfa->inveclosures + dup_idx); /* Store the index of the original node. */ dfa->org_indices[dup_idx] = org_idx; *new_idx = dup_idx; return REG_NOERROR; } static void calc_inveclosure (dfa) re_dfa_t *dfa; { int src, idx, dest; for (src = 0; src < dfa->nodes_len; ++src) { for (idx = 0; idx < dfa->eclosures[src].nelem; ++idx) { dest = dfa->eclosures[src].elems[idx]; re_node_set_insert (dfa->inveclosures + dest, src); } } } /* Calculate "eclosure" for all the node in DFA. */ static reg_errcode_t calc_eclosure (dfa) re_dfa_t *dfa; { int node_idx, incomplete; #ifdef DEBUG assert (dfa->nodes_len > 0); #endif incomplete = 0; /* For each nodes, calculate epsilon closure. */ for (node_idx = 0; ; ++node_idx) { reg_errcode_t err; re_node_set eclosure_elem; if (node_idx == dfa->nodes_len) { if (!incomplete) break; incomplete = 0; node_idx = 0; } #ifdef DEBUG assert (dfa->eclosures[node_idx].nelem != -1); #endif /* If we have already calculated, skip it. */ if (dfa->eclosures[node_idx].nelem != 0) continue; /* Calculate epsilon closure of `node_idx'. */ err = calc_eclosure_iter (&eclosure_elem, dfa, node_idx, 1); if (BE (err != REG_NOERROR, 0)) return err; if (dfa->eclosures[node_idx].nelem == 0) { incomplete = 1; re_node_set_free (&eclosure_elem); } } return REG_NOERROR; } /* Calculate epsilon closure of NODE. */ static reg_errcode_t calc_eclosure_iter (new_set, dfa, node, root) re_node_set *new_set; re_dfa_t *dfa; int node, root; { reg_errcode_t err; unsigned int constraint; int i, incomplete; re_node_set eclosure; incomplete = 0; err = re_node_set_alloc (&eclosure, dfa->edests[node].nelem + 1); if (BE (err != REG_NOERROR, 0)) return err; /* This indicates that we are calculating this node now. We reference this value to avoid infinite loop. */ dfa->eclosures[node].nelem = -1; constraint = ((dfa->nodes[node].type == ANCHOR) ? dfa->nodes[node].opr.ctx_type : 0); /* If the current node has constraints, duplicate all nodes. Since they must inherit the constraints. */ if (constraint && !dfa->nodes[dfa->edests[node].elems[0]].duplicated) { int org_node, cur_node; org_node = cur_node = node; err = duplicate_node_closure (dfa, node, node, node, constraint); if (BE (err != REG_NOERROR, 0)) return err; } /* Expand each epsilon destination nodes. */ if (IS_EPSILON_NODE(dfa->nodes[node].type)) for (i = 0; i < dfa->edests[node].nelem; ++i) { re_node_set eclosure_elem; int edest = dfa->edests[node].elems[i]; /* If calculating the epsilon closure of `edest' is in progress, return intermediate result. */ if (dfa->eclosures[edest].nelem == -1) { incomplete = 1; continue; } /* If we haven't calculated the epsilon closure of `edest' yet, calculate now. Otherwise use calculated epsilon closure. */ if (dfa->eclosures[edest].nelem == 0) { err = calc_eclosure_iter (&eclosure_elem, dfa, edest, 0); if (BE (err != REG_NOERROR, 0)) return err; } else eclosure_elem = dfa->eclosures[edest]; /* Merge the epsilon closure of `edest'. */ re_node_set_merge (&eclosure, &eclosure_elem); /* If the epsilon closure of `edest' is incomplete, the epsilon closure of this node is also incomplete. */ if (dfa->eclosures[edest].nelem == 0) { incomplete = 1; re_node_set_free (&eclosure_elem); } } /* Epsilon closures include itself. */ re_node_set_insert (&eclosure, node); if (incomplete && !root) dfa->eclosures[node].nelem = 0; else dfa->eclosures[node] = eclosure; *new_set = eclosure; return REG_NOERROR; } /* Functions for token which are used in the parser. */ /* Fetch a token from INPUT. We must not use this function inside bracket expressions. */ static re_token_t fetch_token (input, syntax) re_string_t *input; reg_syntax_t syntax; { re_token_t token; int consumed_byte; consumed_byte = peek_token (&token, input, syntax); re_string_skip_bytes (input, consumed_byte); return token; } /* Peek a token from INPUT, and return the length of the token. We must not use this function inside bracket expressions. */ static int peek_token (token, input, syntax) re_token_t *token; re_string_t *input; reg_syntax_t syntax; { unsigned char c; if (re_string_eoi (input)) { token->type = END_OF_RE; return 0; } c = re_string_peek_byte (input, 0); token->opr.c = c; #ifdef RE_ENABLE_I18N token->mb_partial = 0; if (MB_CUR_MAX > 1 && !re_string_first_byte (input, re_string_cur_idx (input))) { token->type = CHARACTER; token->mb_partial = 1; return 1; } #endif if (c == '\\') { unsigned char c2; if (re_string_cur_idx (input) + 1 >= re_string_length (input)) { token->type = BACK_SLASH; return 1; } c2 = re_string_peek_byte_case (input, 1); token->opr.c = c2; token->type = CHARACTER; switch (c2) { case '|': if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_NO_BK_VBAR)) token->type = OP_ALT; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!(syntax & RE_NO_BK_REFS)) { token->type = OP_BACK_REF; token->opr.idx = c2 - '0'; } break; case '<': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.idx = WORD_FIRST; } break; case '>': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.idx = WORD_LAST; } break; case 'b': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.idx = WORD_DELIM; } break; case 'B': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.idx = INSIDE_WORD; } break; case 'w': if (!(syntax & RE_NO_GNU_OPS)) token->type = OP_WORD; break; case 'W': if (!(syntax & RE_NO_GNU_OPS)) token->type = OP_NOTWORD; break; case '`': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.idx = BUF_FIRST; } break; case '\'': if (!(syntax & RE_NO_GNU_OPS)) { token->type = ANCHOR; token->opr.idx = BUF_LAST; } break; case '(': if (!(syntax & RE_NO_BK_PARENS)) token->type = OP_OPEN_SUBEXP; break; case ')': if (!(syntax & RE_NO_BK_PARENS)) token->type = OP_CLOSE_SUBEXP; break; case '+': if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_PLUS; break; case '?': if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_QUESTION; break; case '{': if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) token->type = OP_OPEN_DUP_NUM; break; case '}': if ((syntax & RE_INTERVALS) && (!(syntax & RE_NO_BK_BRACES))) token->type = OP_CLOSE_DUP_NUM; break; default: break; } return 2; } token->type = CHARACTER; switch (c) { case '\n': if (syntax & RE_NEWLINE_ALT) token->type = OP_ALT; break; case '|': if (!(syntax & RE_LIMITED_OPS) && (syntax & RE_NO_BK_VBAR)) token->type = OP_ALT; break; case '*': token->type = OP_DUP_ASTERISK; break; case '+': if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_PLUS; break; case '?': if (!(syntax & RE_LIMITED_OPS) && !(syntax & RE_BK_PLUS_QM)) token->type = OP_DUP_QUESTION; break; case '{': if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) token->type = OP_OPEN_DUP_NUM; break; case '}': if ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES)) token->type = OP_CLOSE_DUP_NUM; break; case '(': if (syntax & RE_NO_BK_PARENS) token->type = OP_OPEN_SUBEXP; break; case ')': if (syntax & RE_NO_BK_PARENS) token->type = OP_CLOSE_SUBEXP; break; case '[': token->type = OP_OPEN_BRACKET; break; case '.': token->type = OP_PERIOD; break; case '^': if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && re_string_cur_idx (input) != 0) { char prev = re_string_peek_byte (input, -1); if (prev != '|' && prev != '(' && (!(syntax & RE_NEWLINE_ALT) || prev != '\n')) break; } token->type = ANCHOR; token->opr.idx = LINE_FIRST; break; case '$': if (!(syntax & RE_CONTEXT_INDEP_ANCHORS) && re_string_cur_idx (input) + 1 != re_string_length (input)) { re_token_t next; re_string_skip_bytes (input, 1); peek_token (&next, input, syntax); re_string_skip_bytes (input, -1); if (next.type != OP_ALT && next.type != OP_CLOSE_SUBEXP) break; } token->type = ANCHOR; token->opr.idx = LINE_LAST; break; default: break; } return 1; } /* Peek a token from INPUT, and return the length of the token. We must not use this function out of bracket expressions. */ static int peek_token_bracket (token, input, syntax) re_token_t *token; re_string_t *input; reg_syntax_t syntax; { unsigned char c; if (re_string_eoi (input)) { token->type = END_OF_RE; return 0; } c = re_string_peek_byte (input, 0); token->opr.c = c; #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1 && !re_string_first_byte (input, re_string_cur_idx (input))) { token->type = CHARACTER; return 1; } #endif /* RE_ENABLE_I18N */ if (c == '\\' && (syntax & RE_BACKSLASH_ESCAPE_IN_LISTS)) { /* In this case, '\' escape a character. */ unsigned char c2; re_string_skip_bytes (input, 1); c2 = re_string_peek_byte (input, 0); token->opr.c = c2; token->type = CHARACTER; return 1; } if (c == '[') /* '[' is a special char in a bracket exps. */ { unsigned char c2; int token_len; c2 = re_string_peek_byte (input, 1); token->opr.c = c2; token_len = 2; switch (c2) { case '.': token->type = OP_OPEN_COLL_ELEM; break; case '=': token->type = OP_OPEN_EQUIV_CLASS; break; case ':': if (syntax & RE_CHAR_CLASSES) { token->type = OP_OPEN_CHAR_CLASS; break; } /* else fall through. */ default: token->type = CHARACTER; token->opr.c = c; token_len = 1; break; } return token_len; } switch (c) { case '-': token->type = OP_CHARSET_RANGE; break; case ']': token->type = OP_CLOSE_BRACKET; break; case '^': token->type = OP_NON_MATCH_LIST; break; default: token->type = CHARACTER; } return 1; } /* Functions for parser. */ /* Entry point of the parser. Parse the regular expression REGEXP and return the structure tree. If an error is occured, ERR is set by error code, and return NULL. This function build the following tree, from regular expression <reg_exp>: CAT / \ / \ <reg_exp> EOR CAT means concatenation. EOR means end of regular expression. */ static bin_tree_t * parse (regexp, preg, syntax, err) re_string_t *regexp; regex_t *preg; reg_syntax_t syntax; reg_errcode_t *err; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *eor, *root; re_token_t current_token; int new_idx; current_token = fetch_token (regexp, syntax); tree = parse_reg_exp (regexp, preg, ¤t_token, syntax, 0, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; new_idx = re_dfa_add_node (dfa, current_token, 0); eor = create_tree (NULL, NULL, 0, new_idx); if (tree != NULL) root = create_tree (tree, eor, CONCAT, 0); else root = eor; if (BE (new_idx == -1 || eor == NULL || root == NULL, 0)) { *err = REG_ESPACE; return NULL; } return root; } /* This function build the following tree, from regular expression <branch1>|<branch2>: ALT / \ / \ <branch1> <branch2> ALT means alternative, which represents the operator `|'. */ static bin_tree_t * parse_reg_exp (regexp, preg, token, syntax, nest, err) re_string_t *regexp; regex_t *preg; re_token_t *token; reg_syntax_t syntax; int nest; reg_errcode_t *err; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *branch = NULL; int new_idx; tree = parse_branch (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; while (token->type == OP_ALT) { re_token_t alt_token = *token; new_idx = re_dfa_add_node (dfa, alt_token, 0); *token = fetch_token (regexp, syntax); if (token->type != OP_ALT && token->type != END_OF_RE && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { branch = parse_branch (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && branch == NULL, 0)) { free_bin_tree (tree); return NULL; } } else branch = NULL; tree = create_tree (tree, branch, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } dfa->has_plural_match = 1; } return tree; } /* This function build the following tree, from regular expression <exp1><exp2>: CAT / \ / \ <exp1> <exp2> CAT means concatenation. */ static bin_tree_t * parse_branch (regexp, preg, token, syntax, nest, err) re_string_t *regexp; regex_t *preg; re_token_t *token; reg_syntax_t syntax; int nest; reg_errcode_t *err; { bin_tree_t *tree, *exp; tree = parse_expression (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; while (token->type != OP_ALT && token->type != END_OF_RE && (nest == 0 || token->type != OP_CLOSE_SUBEXP)) { exp = parse_expression (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && exp == NULL, 0)) { free_bin_tree (tree); return NULL; } if (tree != NULL && exp != NULL) { tree = create_tree (tree, exp, CONCAT, 0); if (tree == NULL) { *err = REG_ESPACE; return NULL; } } else if (tree == NULL) tree = exp; /* Otherwise exp == NULL, we don't need to create new tree. */ } return tree; } /* This function build the following tree, from regular expression a*: * | a */ static bin_tree_t * parse_expression (regexp, preg, token, syntax, nest, err) re_string_t *regexp; regex_t *preg; re_token_t *token; reg_syntax_t syntax; int nest; reg_errcode_t *err; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree; int new_idx; switch (token->type) { case CHARACTER: new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) { while (!re_string_eoi (regexp) && !re_string_first_byte (regexp, re_string_cur_idx (regexp))) { bin_tree_t *mbc_remain; *token = fetch_token (regexp, syntax); new_idx = re_dfa_add_node (dfa, *token, 0); mbc_remain = create_tree (NULL, NULL, 0, new_idx); tree = create_tree (tree, mbc_remain, CONCAT, 0); if (BE (new_idx == -1 || mbc_remain == NULL || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } } #endif break; case OP_OPEN_SUBEXP: tree = parse_sub_exp (regexp, preg, token, syntax, nest + 1, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_OPEN_BRACKET: tree = parse_bracket_exp (regexp, dfa, token, syntax, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_BACK_REF: if (BE (preg->re_nsub < token->opr.idx || dfa->subexps[token->opr.idx - 1].end == -1, 0)) { *err = REG_ESUBREG; return NULL; } dfa->used_bkref_map |= 1 << (token->opr.idx - 1); new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } ++dfa->nbackref; dfa->has_mb_node = 1; break; case OP_DUP_ASTERISK: case OP_DUP_PLUS: case OP_DUP_QUESTION: case OP_OPEN_DUP_NUM: if (syntax & RE_CONTEXT_INVALID_OPS) { *err = REG_BADRPT; return NULL; } else if (syntax & RE_CONTEXT_INDEP_OPS) { *token = fetch_token (regexp, syntax); return parse_expression (regexp, preg, token, syntax, nest, err); } /* else fall through */ case OP_CLOSE_SUBEXP: if ((token->type == OP_CLOSE_SUBEXP) && !(syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)) { *err = REG_ERPAREN; return NULL; } /* else fall through */ case OP_CLOSE_DUP_NUM: /* We treat it as a normal character. */ /* Then we can these characters as normal characters. */ token->type = CHARACTER; new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } break; case ANCHOR: if (dfa->word_char == NULL) { *err = init_word_char (dfa); if (BE (*err != REG_NOERROR, 0)) return NULL; } if (token->opr.ctx_type == WORD_DELIM) { bin_tree_t *tree_first, *tree_last; int idx_first, idx_last; token->opr.ctx_type = WORD_FIRST; idx_first = re_dfa_add_node (dfa, *token, 0); tree_first = create_tree (NULL, NULL, 0, idx_first); token->opr.ctx_type = WORD_LAST; idx_last = re_dfa_add_node (dfa, *token, 0); tree_last = create_tree (NULL, NULL, 0, idx_last); token->type = OP_ALT; new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (tree_first, tree_last, 0, new_idx); if (BE (idx_first == -1 || idx_last == -1 || new_idx == -1 || tree_first == NULL || tree_last == NULL || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } else { new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } /* We must return here, since ANCHORs can't be followed by repetition operators. eg. RE"^*" is invalid or "<ANCHOR(^)><CHAR(*)>", it must not be "<ANCHOR(^)><REPEAT(*)>". */ *token = fetch_token (regexp, syntax); return tree; case OP_PERIOD: new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } if (MB_CUR_MAX > 1) dfa->has_mb_node = 1; break; case OP_WORD: tree = build_word_op (dfa, 0, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_NOTWORD: tree = build_word_op (dfa, 1, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; break; case OP_ALT: case END_OF_RE: return NULL; case BACK_SLASH: *err = REG_EESCAPE; return NULL; default: /* Must not happen? */ #ifdef DEBUG assert (0); #endif return NULL; } *token = fetch_token (regexp, syntax); while (token->type == OP_DUP_ASTERISK || token->type == OP_DUP_PLUS || token->type == OP_DUP_QUESTION || token->type == OP_OPEN_DUP_NUM) { tree = parse_dup_op (tree, regexp, dfa, token, syntax, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; dfa->has_plural_match = 1; } return tree; } /* This function build the following tree, from regular expression (<reg_exp>): SUBEXP | <reg_exp> */ static bin_tree_t * parse_sub_exp (regexp, preg, token, syntax, nest, err) re_string_t *regexp; regex_t *preg; re_token_t *token; reg_syntax_t syntax; int nest; reg_errcode_t *err; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; bin_tree_t *tree, *left_par, *right_par; size_t cur_nsub; int new_idx; cur_nsub = preg->re_nsub++; if (dfa->subexps_alloc < preg->re_nsub) { re_subexp_t *new_array; dfa->subexps_alloc *= 2; new_array = re_realloc (dfa->subexps, re_subexp_t, dfa->subexps_alloc); if (BE (new_array == NULL, 0)) { dfa->subexps_alloc /= 2; *err = REG_ESPACE; return NULL; } dfa->subexps = new_array; } dfa->subexps[cur_nsub].start = dfa->nodes_len; dfa->subexps[cur_nsub].end = -1; new_idx = re_dfa_add_node (dfa, *token, 0); left_par = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || left_par == NULL, 0)) { *err = REG_ESPACE; return NULL; } dfa->nodes[new_idx].opr.idx = cur_nsub; *token = fetch_token (regexp, syntax); /* The subexpression may be a null string. */ if (token->type == OP_CLOSE_SUBEXP) tree = NULL; else { tree = parse_reg_exp (regexp, preg, token, syntax, nest, err); if (BE (*err != REG_NOERROR && tree == NULL, 0)) return NULL; } if (BE (token->type != OP_CLOSE_SUBEXP, 0)) { free_bin_tree (tree); *err = REG_BADPAT; return NULL; } new_idx = re_dfa_add_node (dfa, *token, 0); dfa->subexps[cur_nsub].end = dfa->nodes_len; right_par = create_tree (NULL, NULL, 0, new_idx); tree = ((tree == NULL) ? right_par : create_tree (tree, right_par, CONCAT, 0)); tree = create_tree (left_par, tree, CONCAT, 0); if (BE (new_idx == -1 || right_par == NULL || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } dfa->nodes[new_idx].opr.idx = cur_nsub; return tree; } /* This function parse repetition operators like "*", "+", "{1,3}" etc. */ static bin_tree_t * parse_dup_op (dup_elem, regexp, dfa, token, syntax, err) bin_tree_t *dup_elem; re_string_t *regexp; re_dfa_t *dfa; re_token_t *token; reg_syntax_t syntax; reg_errcode_t *err; { re_token_t dup_token; bin_tree_t *tree = dup_elem, *work_tree; int new_idx, start_idx = re_string_cur_idx (regexp); re_token_t start_token = *token; if (token->type == OP_OPEN_DUP_NUM) { int i; int end = 0; int start = fetch_number (regexp, token, syntax); bin_tree_t *elem; if (start == -1) { if (token->type == CHARACTER && token->opr.c == ',') start = 0; /* We treat "{,m}" as "{0,m}". */ else { *err = REG_BADBR; /* <re>{} is invalid. */ return NULL; } } if (BE (start != -2, 1)) { /* We treat "{n}" as "{n,n}". */ end = ((token->type == OP_CLOSE_DUP_NUM) ? start : ((token->type == CHARACTER && token->opr.c == ',') ? fetch_number (regexp, token, syntax) : -2)); } if (BE (start == -2 || end == -2, 0)) { /* Invalid sequence. */ if (token->type == OP_CLOSE_DUP_NUM) goto parse_dup_op_invalid_interval; else goto parse_dup_op_ebrace; } if (BE (start == 0 && end == 0, 0)) { /* We treat "<re>{0}" and "<re>{0,0}" as null string. */ *token = fetch_token (regexp, syntax); free_bin_tree (dup_elem); return NULL; } /* Extract "<re>{n,m}" to "<re><re>...<re><re>{0,<m-n>}". */ elem = tree; for (i = 0; i < start; ++i) if (i != 0) { work_tree = duplicate_tree (elem, dfa); tree = create_tree (tree, work_tree, CONCAT, 0); if (BE (work_tree == NULL || tree == NULL, 0)) goto parse_dup_op_espace; } if (end == -1) { /* We treat "<re>{0,}" as "<re>*". */ dup_token.type = OP_DUP_ASTERISK; if (start > 0) { elem = duplicate_tree (elem, dfa); new_idx = re_dfa_add_node (dfa, dup_token, 0); work_tree = create_tree (elem, NULL, 0, new_idx); tree = create_tree (tree, work_tree, CONCAT, 0); if (BE (elem == NULL || new_idx == -1 || work_tree == NULL || tree == NULL, 0)) goto parse_dup_op_espace; } else { new_idx = re_dfa_add_node (dfa, dup_token, 0); tree = create_tree (elem, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) goto parse_dup_op_espace; } } else if (end - start > 0) { /* Then extract "<re>{0,m}" to "<re>?<re>?...<re>?". */ dup_token.type = OP_DUP_QUESTION; if (start > 0) { elem = duplicate_tree (elem, dfa); new_idx = re_dfa_add_node (dfa, dup_token, 0); elem = create_tree (elem, NULL, 0, new_idx); tree = create_tree (tree, elem, CONCAT, 0); if (BE (elem == NULL || new_idx == -1 || tree == NULL, 0)) goto parse_dup_op_espace; } else { new_idx = re_dfa_add_node (dfa, dup_token, 0); tree = elem = create_tree (elem, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) goto parse_dup_op_espace; } for (i = 1; i < end - start; ++i) { work_tree = duplicate_tree (elem, dfa); tree = create_tree (tree, work_tree, CONCAT, 0); if (BE (work_tree == NULL || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } } } else { new_idx = re_dfa_add_node (dfa, *token, 0); tree = create_tree (tree, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) { *err = REG_ESPACE; return NULL; } } *token = fetch_token (regexp, syntax); return tree; parse_dup_op_espace: free_bin_tree (tree); *err = REG_ESPACE; return NULL; parse_dup_op_ebrace: if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) { *err = REG_EBRACE; return NULL; } goto parse_dup_op_rollback; parse_dup_op_invalid_interval: if (BE (!(syntax & RE_INVALID_INTERVAL_ORD), 0)) { *err = REG_BADBR; return NULL; } parse_dup_op_rollback: re_string_set_index (regexp, start_idx); *token = start_token; token->type = CHARACTER; return dup_elem; } /* Size of the names for collating symbol/equivalence_class/character_class. I'm not sure, but maybe enough. */ #define BRACKET_NAME_BUF_SIZE 32 #ifndef _LIBC /* Local function for parse_bracket_exp only used in case of NOT _LIBC. Build the range expression which starts from START_ELEM, and ends at END_ELEM. The result are written to MBCSET and SBCSET. RANGE_ALLOC is the allocated size of mbcset->range_starts, and mbcset->range_ends, is a pointer argument sinse we may update it. */ static reg_errcode_t # ifdef RE_ENABLE_I18N build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) re_charset_t *mbcset; int *range_alloc; # else /* not RE_ENABLE_I18N */ build_range_exp (sbcset, start_elem, end_elem) # endif /* not RE_ENABLE_I18N */ re_bitset_ptr_t sbcset; bracket_elem_t *start_elem, *end_elem; { unsigned int start_ch, end_ch; /* Equivalence Classes and Character Classes can't be a range start/end. */ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, 0)) return REG_ERANGE; /* We can handle no multi character collating elements without libc support. */ if (BE ((start_elem->type == COLL_SYM && strlen ((char *) start_elem->opr.name) > 1) || (end_elem->type == COLL_SYM && strlen ((char *) end_elem->opr.name) > 1), 0)) return REG_ECOLLATE; # ifdef RE_ENABLE_I18N { wchar_t wc, start_wc, end_wc; wchar_t cmp_buf[6] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; start_ch = ((start_elem->type == SB_CHAR) ? start_elem->opr.ch : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] : 0)); end_ch = ((end_elem->type == SB_CHAR) ? end_elem->opr.ch : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] : 0)); start_wc = ((start_elem->type == SB_CHAR || start_elem->type == COLL_SYM) ? __btowc (start_ch) : start_elem->opr.wch); end_wc = ((end_elem->type == SB_CHAR || end_elem->type == COLL_SYM) ? __btowc (end_ch) : end_elem->opr.wch); cmp_buf[0] = start_wc; cmp_buf[4] = end_wc; if (wcscoll (cmp_buf, cmp_buf + 4) > 0) return REG_ERANGE; /* Check the space of the arrays. */ if (*range_alloc == mbcset->nranges) { /* There are not enough space, need realloc. */ wchar_t *new_array_start, *new_array_end; int new_nranges; /* +1 in case of mbcset->nranges is 0. */ new_nranges = 2 * mbcset->nranges + 1; /* Use realloc since mbcset->range_starts and mbcset->range_ends are NULL if *range_alloc == 0. */ new_array_start = re_realloc (mbcset->range_starts, wchar_t, new_nranges); new_array_end = re_realloc (mbcset->range_ends, wchar_t, new_nranges); if (BE (new_array_start == NULL || new_array_end == NULL, 0)) return REG_ESPACE; mbcset->range_starts = new_array_start; mbcset->range_ends = new_array_end; *range_alloc = new_nranges; } mbcset->range_starts[mbcset->nranges] = start_wc; mbcset->range_ends[mbcset->nranges++] = end_wc; /* Build the table for single byte characters. */ for (wc = 0; wc <= SBC_MAX; ++wc) { cmp_buf[2] = wc; if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) bitset_set (sbcset, wc); } } # else /* not RE_ENABLE_I18N */ { unsigned int ch; start_ch = ((start_elem->type == SB_CHAR ) ? start_elem->opr.ch : ((start_elem->type == COLL_SYM) ? start_elem->opr.name[0] : 0)); end_ch = ((end_elem->type == SB_CHAR ) ? end_elem->opr.ch : ((end_elem->type == COLL_SYM) ? end_elem->opr.name[0] : 0)); if (start_ch > end_ch) return REG_ERANGE; /* Build the table for single byte characters. */ for (ch = 0; ch <= SBC_MAX; ++ch) if (start_ch <= ch && ch <= end_ch) bitset_set (sbcset, ch); } # endif /* not RE_ENABLE_I18N */ return REG_NOERROR; } #endif /* not _LIBC */ #ifndef _LIBC /* Helper function for parse_bracket_exp only used in case of NOT _LIBC.. Build the collating element which is represented by NAME. The result are written to MBCSET and SBCSET. COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a pointer argument since we may update it. */ static reg_errcode_t # ifdef RE_ENABLE_I18N build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) re_charset_t *mbcset; int *coll_sym_alloc; # else /* not RE_ENABLE_I18N */ build_collating_symbol (sbcset, name) # endif /* not RE_ENABLE_I18N */ re_bitset_ptr_t sbcset; const unsigned char *name; { size_t name_len = strlen ((const char *) name); if (BE (name_len != 1, 0)) return REG_ECOLLATE; else { bitset_set (sbcset, name[0]); return REG_NOERROR; } } #endif /* not _LIBC */ /* This function parse bracket expression like "[abc]", "[a-c]", "[[.a-a.]]" etc. */ static bin_tree_t * parse_bracket_exp (regexp, dfa, token, syntax, err) re_string_t *regexp; re_dfa_t *dfa; re_token_t *token; reg_syntax_t syntax; reg_errcode_t *err; { #ifdef _LIBC const unsigned char *collseqmb; const char *collseqwc; uint32_t nrules; int32_t table_size; const int32_t *symb_table; const unsigned char *extra; /* Local function for parse_bracket_exp used in _LIBC environement. Seek the collating symbol entry correspondings to NAME. Return the index of the symbol in the SYMB_TABLE. */ static inline int32_t seek_collating_symbol_entry (name, name_len) const unsigned char *name; size_t name_len; { int32_t hash = elem_hash ((const char *) name, name_len); int32_t elem = hash % table_size; int32_t second = hash % (table_size - 2); while (symb_table[2 * elem] != 0) { /* First compare the hashing value. */ if (symb_table[2 * elem] == hash /* Compare the length of the name. */ && name_len == extra[symb_table[2 * elem + 1]] /* Compare the name. */ && memcmp (name, &extra[symb_table[2 * elem + 1] + 1], name_len) == 0) { /* Yep, this is the entry. */ break; } /* Next entry. */ elem += second; } return elem; } /* Local function for parse_bracket_exp used in _LIBC environement. Look up the collation sequence value of BR_ELEM. Return the value if succeeded, UINT_MAX otherwise. */ static inline unsigned int lookup_collation_sequence_value (br_elem) bracket_elem_t *br_elem; { if (br_elem->type == SB_CHAR) { /* if (MB_CUR_MAX == 1) */ if (nrules == 0) return collseqmb[br_elem->opr.ch]; else { wint_t wc = __btowc (br_elem->opr.ch); return collseq_table_lookup (collseqwc, wc); } } else if (br_elem->type == MB_CHAR) { return collseq_table_lookup (collseqwc, br_elem->opr.wch); } else if (br_elem->type == COLL_SYM) { size_t sym_name_len = strlen ((char *) br_elem->opr.name); if (nrules != 0) { int32_t elem, idx; elem = seek_collating_symbol_entry (br_elem->opr.name, sym_name_len); if (symb_table[2 * elem] != 0) { /* We found the entry. */ idx = symb_table[2 * elem + 1]; /* Skip the name of collating element name. */ idx += 1 + extra[idx]; /* Skip the byte sequence of the collating element. */ idx += 1 + extra[idx]; /* Adjust for the alignment. */ idx = (idx + 3) & ~3; /* Skip the multibyte collation sequence value. */ idx += sizeof (unsigned int); /* Skip the wide char sequence of the collating element. */ idx += sizeof (unsigned int) * (1 + *(unsigned int *) (extra + idx)); /* Return the collation sequence value. */ return *(unsigned int *) (extra + idx); } else if (symb_table[2 * elem] == 0 && sym_name_len == 1) { /* No valid character. Match it as a single byte character. */ return collseqmb[br_elem->opr.name[0]]; } } else if (sym_name_len == 1) return collseqmb[br_elem->opr.name[0]]; } return UINT_MAX; } /* Local function for parse_bracket_exp used in _LIBC environement. Build the range expression which starts from START_ELEM, and ends at END_ELEM. The result are written to MBCSET and SBCSET. RANGE_ALLOC is the allocated size of mbcset->range_starts, and mbcset->range_ends, is a pointer argument sinse we may update it. */ static inline reg_errcode_t # ifdef RE_ENABLE_I18N build_range_exp (sbcset, mbcset, range_alloc, start_elem, end_elem) re_charset_t *mbcset; int *range_alloc; # else /* not RE_ENABLE_I18N */ build_range_exp (sbcset, start_elem, end_elem) # endif /* not RE_ENABLE_I18N */ re_bitset_ptr_t sbcset; bracket_elem_t *start_elem, *end_elem; { unsigned int ch; uint32_t start_collseq; uint32_t end_collseq; # ifdef RE_ENABLE_I18N /* Check the space of the arrays. */ if (*range_alloc == mbcset->nranges) { /* There are not enough space, need realloc. */ uint32_t *new_array_start; uint32_t *new_array_end; int new_nranges; /* +1 in case of mbcset->nranges is 0. */ new_nranges = 2 * mbcset->nranges + 1; /* Use realloc since mbcset->range_starts and mbcset->range_ends are NULL if *range_alloc == 0. */ new_array_start = re_realloc (mbcset->range_starts, uint32_t, new_nranges); new_array_end = re_realloc (mbcset->range_ends, uint32_t, new_nranges); if (BE (new_array_start == NULL || new_array_end == NULL, 0)) return REG_ESPACE; mbcset->range_starts = new_array_start; mbcset->range_ends = new_array_end; *range_alloc = new_nranges; } # endif /* RE_ENABLE_I18N */ /* Equivalence Classes and Character Classes can't be a range start/end. */ if (BE (start_elem->type == EQUIV_CLASS || start_elem->type == CHAR_CLASS || end_elem->type == EQUIV_CLASS || end_elem->type == CHAR_CLASS, 0)) return REG_ERANGE; start_collseq = lookup_collation_sequence_value (start_elem); end_collseq = lookup_collation_sequence_value (end_elem); /* Check start/end collation sequence values. */ if (BE (start_collseq == UINT_MAX || end_collseq == UINT_MAX, 0)) return REG_ECOLLATE; if (BE ((syntax & RE_NO_EMPTY_RANGES) && start_collseq > end_collseq, 0)) return REG_ERANGE; # ifdef RE_ENABLE_I18N /* Got valid collation sequence values, add them as a new entry. */ mbcset->range_starts[mbcset->nranges] = start_collseq; mbcset->range_ends[mbcset->nranges++] = end_collseq; # endif /* RE_ENABLE_I18N */ /* Build the table for single byte characters. */ for (ch = 0; ch <= SBC_MAX; ch++) { uint32_t ch_collseq; /* if (MB_CUR_MAX == 1) */ if (nrules == 0) ch_collseq = collseqmb[ch]; else ch_collseq = collseq_table_lookup (collseqwc, __btowc (ch)); if (start_collseq <= ch_collseq && ch_collseq <= end_collseq) bitset_set (sbcset, ch); } return REG_NOERROR; } /* Local function for parse_bracket_exp used in _LIBC environement. Build the collating element which is represented by NAME. The result are written to MBCSET and SBCSET. COLL_SYM_ALLOC is the allocated size of mbcset->coll_sym, is a pointer argument sinse we may update it. */ static inline reg_errcode_t # ifdef RE_ENABLE_I18N build_collating_symbol (sbcset, mbcset, coll_sym_alloc, name) re_charset_t *mbcset; int *coll_sym_alloc; # else /* not RE_ENABLE_I18N */ build_collating_symbol (sbcset, name) # endif /* not RE_ENABLE_I18N */ re_bitset_ptr_t sbcset; const unsigned char *name; { int32_t elem, idx; size_t name_len = strlen ((const char *) name); if (nrules != 0) { elem = seek_collating_symbol_entry (name, name_len); if (symb_table[2 * elem] != 0) { /* We found the entry. */ idx = symb_table[2 * elem + 1]; /* Skip the name of collating element name. */ idx += 1 + extra[idx]; } else if (symb_table[2 * elem] == 0 && name_len == 1) { /* No valid character, treat it as a normal character. */ bitset_set (sbcset, name[0]); return REG_NOERROR; } else return REG_ECOLLATE; # ifdef RE_ENABLE_I18N /* Got valid collation sequence, add it as a new entry. */ /* Check the space of the arrays. */ if (*coll_sym_alloc == mbcset->ncoll_syms) { /* Not enough, realloc it. */ /* +1 in case of mbcset->ncoll_syms is 0. */ *coll_sym_alloc = 2 * mbcset->ncoll_syms + 1; /* Use realloc since mbcset->coll_syms is NULL if *alloc == 0. */ mbcset->coll_syms = re_realloc (mbcset->coll_syms, int32_t, *coll_sym_alloc); if (BE (mbcset->coll_syms == NULL, 0)) return REG_ESPACE; } mbcset->coll_syms[mbcset->ncoll_syms++] = idx; # endif /* RE_ENABLE_I18N */ return REG_NOERROR; } else { if (BE (name_len != 1, 0)) return REG_ECOLLATE; else { bitset_set (sbcset, name[0]); return REG_NOERROR; } } } #endif re_token_t br_token; re_bitset_ptr_t sbcset; #ifdef RE_ENABLE_I18N re_charset_t *mbcset; int coll_sym_alloc = 0, range_alloc = 0, mbchar_alloc = 0; int equiv_class_alloc = 0, char_class_alloc = 0; #else /* not RE_ENABLE_I18N */ int non_match = 0; #endif /* not RE_ENABLE_I18N */ bin_tree_t *work_tree; int token_len, new_idx; #ifdef _LIBC collseqmb = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules) { /* if (MB_CUR_MAX > 1) */ collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); table_size = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_SYMB_HASH_SIZEMB); symb_table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_TABLEMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); } #endif sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); #ifdef RE_ENABLE_I18N mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); #endif /* RE_ENABLE_I18N */ #ifdef RE_ENABLE_I18N if (BE (sbcset == NULL || mbcset == NULL, 0)) #else if (BE (sbcset == NULL, 0)) #endif /* RE_ENABLE_I18N */ { *err = REG_ESPACE; return NULL; } token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } if (token->type == OP_NON_MATCH_LIST) { #ifdef RE_ENABLE_I18N int i; mbcset->non_match = 1; #else /* not RE_ENABLE_I18N */ non_match = 1; #endif /* not RE_ENABLE_I18N */ if (syntax & RE_HAT_LISTS_NOT_NEWLINE) bitset_set (sbcset, '\0'); re_string_skip_bytes (regexp, token_len); /* Skip a token. */ token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) for (i = 0; i < SBC_MAX; ++i) if (__btowc (i) == WEOF) bitset_set (sbcset, i); #endif /* RE_ENABLE_I18N */ } /* We treat the first ']' as a normal character. */ if (token->type == OP_CLOSE_BRACKET) token->type = CHARACTER; while (1) { bracket_elem_t start_elem, end_elem; unsigned char start_name_buf[BRACKET_NAME_BUF_SIZE]; unsigned char end_name_buf[BRACKET_NAME_BUF_SIZE]; reg_errcode_t ret; int token_len2 = 0, is_range_exp = 0; re_token_t token2; start_elem.opr.name = start_name_buf; ret = parse_bracket_element (&start_elem, regexp, token, token_len, dfa, syntax); if (BE (ret != REG_NOERROR, 0)) { *err = ret; goto parse_bracket_exp_free_return; } token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } if (token->type == OP_CHARSET_RANGE) { re_string_skip_bytes (regexp, token_len); /* Skip '-'. */ token_len2 = peek_token_bracket (&token2, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } if (token2.type == OP_CLOSE_BRACKET) { /* We treat the last '-' as a normal character. */ re_string_skip_bytes (regexp, -token_len); token->type = CHARACTER; } else is_range_exp = 1; } if (is_range_exp == 1) { end_elem.opr.name = end_name_buf; ret = parse_bracket_element (&end_elem, regexp, &token2, token_len2, dfa, syntax); if (BE (ret != REG_NOERROR, 0)) { *err = ret; goto parse_bracket_exp_free_return; } token_len = peek_token_bracket (token, regexp, syntax); if (BE (token->type == END_OF_RE, 0)) { *err = REG_BADPAT; goto parse_bracket_exp_free_return; } *err = build_range_exp (sbcset, #ifdef RE_ENABLE_I18N mbcset, &range_alloc, #endif /* RE_ENABLE_I18N */ &start_elem, &end_elem); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; } else { switch (start_elem.type) { case SB_CHAR: bitset_set (sbcset, start_elem.opr.ch); break; #ifdef RE_ENABLE_I18N case MB_CHAR: /* Check whether the array has enough space. */ if (mbchar_alloc == mbcset->nmbchars) { /* Not enough, realloc it. */ /* +1 in case of mbcset->nmbchars is 0. */ mbchar_alloc = 2 * mbcset->nmbchars + 1; /* Use realloc since array is NULL if *alloc == 0. */ mbcset->mbchars = re_realloc (mbcset->mbchars, wchar_t, mbchar_alloc); if (BE (mbcset->mbchars == NULL, 0)) goto parse_bracket_exp_espace; } mbcset->mbchars[mbcset->nmbchars++] = start_elem.opr.wch; break; #endif /* RE_ENABLE_I18N */ case EQUIV_CLASS: *err = build_equiv_class (sbcset, #ifdef RE_ENABLE_I18N mbcset, &equiv_class_alloc, #endif /* RE_ENABLE_I18N */ start_elem.opr.name); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; break; case COLL_SYM: *err = build_collating_symbol (sbcset, #ifdef RE_ENABLE_I18N mbcset, &coll_sym_alloc, #endif /* RE_ENABLE_I18N */ start_elem.opr.name); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; break; case CHAR_CLASS: *err = build_charclass (sbcset, #ifdef RE_ENABLE_I18N mbcset, &char_class_alloc, #endif /* RE_ENABLE_I18N */ start_elem.opr.name, syntax); if (BE (*err != REG_NOERROR, 0)) goto parse_bracket_exp_free_return; break; default: assert (0); break; } } if (token->type == OP_CLOSE_BRACKET) break; } re_string_skip_bytes (regexp, token_len); /* Skip a token. */ /* If it is non-matching list. */ #ifdef RE_ENABLE_I18N if (mbcset->non_match) #else /* not RE_ENABLE_I18N */ if (non_match) #endif /* not RE_ENABLE_I18N */ bitset_not (sbcset); /* Build a tree for simple bracket. */ br_token.type = SIMPLE_BRACKET; br_token.opr.sbcset = sbcset; new_idx = re_dfa_add_node (dfa, br_token, 0); work_tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || work_tree == NULL, 0)) goto parse_bracket_exp_espace; #ifdef RE_ENABLE_I18N if (mbcset->nmbchars || mbcset->ncoll_syms || mbcset->nequiv_classes || mbcset->nranges || (MB_CUR_MAX > 1 && (mbcset->nchar_classes || mbcset->non_match))) { re_token_t alt_token; bin_tree_t *mbc_tree; /* Build a tree for complex bracket. */ br_token.type = COMPLEX_BRACKET; br_token.opr.mbcset = mbcset; dfa->has_mb_node = 1; new_idx = re_dfa_add_node (dfa, br_token, 0); mbc_tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || mbc_tree == NULL, 0)) goto parse_bracket_exp_espace; /* Then join them by ALT node. */ dfa->has_plural_match = 1; alt_token.type = OP_ALT; new_idx = re_dfa_add_node (dfa, alt_token, 0); work_tree = create_tree (work_tree, mbc_tree, 0, new_idx); if (BE (new_idx != -1 && mbc_tree != NULL, 1)) return work_tree; } else { free_charset (mbcset); return work_tree; } #else /* not RE_ENABLE_I18N */ return work_tree; #endif /* not RE_ENABLE_I18N */ parse_bracket_exp_espace: *err = REG_ESPACE; parse_bracket_exp_free_return: re_free (sbcset); #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* RE_ENABLE_I18N */ return NULL; } /* Parse an element in the bracket expression. */ static reg_errcode_t parse_bracket_element (elem, regexp, token, token_len, dfa, syntax) bracket_elem_t *elem; re_string_t *regexp; re_token_t *token; int token_len; re_dfa_t *dfa; reg_syntax_t syntax; { #ifdef RE_ENABLE_I18N int cur_char_size; cur_char_size = re_string_char_size_at (regexp, re_string_cur_idx (regexp)); if (cur_char_size > 1) { elem->type = MB_CHAR; elem->opr.wch = re_string_wchar_at (regexp, re_string_cur_idx (regexp)); re_string_skip_bytes (regexp, cur_char_size); return REG_NOERROR; } #endif /* RE_ENABLE_I18N */ re_string_skip_bytes (regexp, token_len); /* Skip a token. */ if (token->type == OP_OPEN_COLL_ELEM || token->type == OP_OPEN_CHAR_CLASS || token->type == OP_OPEN_EQUIV_CLASS) return parse_bracket_symbol (elem, regexp, token); elem->type = SB_CHAR; elem->opr.ch = token->opr.c; return REG_NOERROR; } /* Parse a bracket symbol in the bracket expression. Bracket symbols are such as [:<character_class>:], [.<collating_element>.], and [=<equivalent_class>=]. */ static reg_errcode_t parse_bracket_symbol (elem, regexp, token) bracket_elem_t *elem; re_string_t *regexp; re_token_t *token; { unsigned char ch, delim = token->opr.c; int i = 0; for (;; ++i) { if (re_string_eoi(regexp) || i >= BRACKET_NAME_BUF_SIZE) return REG_EBRACK; if (token->type == OP_OPEN_CHAR_CLASS) ch = re_string_fetch_byte_case (regexp); else ch = re_string_fetch_byte (regexp); if (ch == delim && re_string_peek_byte (regexp, 0) == ']') break; elem->opr.name[i] = ch; } re_string_skip_bytes (regexp, 1); elem->opr.name[i] = '\0'; switch (token->type) { case OP_OPEN_COLL_ELEM: elem->type = COLL_SYM; break; case OP_OPEN_EQUIV_CLASS: elem->type = EQUIV_CLASS; break; case OP_OPEN_CHAR_CLASS: elem->type = CHAR_CLASS; break; default: break; } return REG_NOERROR; } /* Helper function for parse_bracket_exp. Build the equivalence class which is represented by NAME. The result are written to MBCSET and SBCSET. EQUIV_CLASS_ALLOC is the allocated size of mbcset->equiv_classes, is a pointer argument sinse we may update it. */ static reg_errcode_t #ifdef RE_ENABLE_I18N build_equiv_class (sbcset, mbcset, equiv_class_alloc, name) re_charset_t *mbcset; int *equiv_class_alloc; #else /* not RE_ENABLE_I18N */ build_equiv_class (sbcset, name) #endif /* not RE_ENABLE_I18N */ re_bitset_ptr_t sbcset; const unsigned char *name; { #if defined _LIBC && defined RE_ENABLE_I18N uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) { const int32_t *table, *indirect; const unsigned char *weights, *extra, *cp; unsigned char char_buf[2]; int32_t idx1, idx2; unsigned int ch; size_t len; /* This #include defines a local function! */ # include <locale/weight.h> /* Calculate the index for equivalence class. */ cp = name; table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); idx1 = findidx (&cp); if (BE (idx1 == 0 || cp < name + strlen ((const char *) name), 0)) /* This isn't a valid character. */ return REG_ECOLLATE; /* Build single byte matcing table for this equivalence class. */ char_buf[1] = (unsigned char) '\0'; len = weights[idx1]; for (ch = 0; ch < SBC_MAX; ++ch) { char_buf[0] = ch; cp = char_buf; idx2 = findidx (&cp); /* idx2 = table[ch]; */ if (idx2 == 0) /* This isn't a valid character. */ continue; if (len == weights[idx2]) { int cnt = 0; while (cnt <= len && weights[idx1 + 1 + cnt] == weights[idx2 + 1 + cnt]) ++cnt; if (cnt > len) bitset_set (sbcset, ch); } } /* Check whether the array has enough space. */ if (*equiv_class_alloc == mbcset->nequiv_classes) { /* Not enough, realloc it. */ /* +1 in case of mbcset->nequiv_classes is 0. */ *equiv_class_alloc = 2 * mbcset->nequiv_classes + 1; /* Use realloc since the array is NULL if *alloc == 0. */ mbcset->equiv_classes = re_realloc (mbcset->equiv_classes, int32_t, *equiv_class_alloc); if (BE (mbcset->equiv_classes == NULL, 0)) return REG_ESPACE; } mbcset->equiv_classes[mbcset->nequiv_classes++] = idx1; } else #endif /* _LIBC && RE_ENABLE_I18N */ { if (BE (strlen ((const char *) name) != 1, 0)) return REG_ECOLLATE; bitset_set (sbcset, *name); } return REG_NOERROR; } /* Helper function for parse_bracket_exp. Build the character class which is represented by NAME. The result are written to MBCSET and SBCSET. CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes, is a pointer argument sinse we may update it. */ static reg_errcode_t #ifdef RE_ENABLE_I18N build_charclass (sbcset, mbcset, char_class_alloc, class_name, syntax) re_charset_t *mbcset; int *char_class_alloc; #else /* not RE_ENABLE_I18N */ build_charclass (sbcset, class_name, syntax) #endif /* not RE_ENABLE_I18N */ re_bitset_ptr_t sbcset; const unsigned char *class_name; reg_syntax_t syntax; { int i; const char *name = (const char *) class_name; /* In case of REG_ICASE "upper" and "lower" match the both of upper and lower cases. */ if ((syntax & RE_ICASE) && (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0)) name = "alpha"; #ifdef RE_ENABLE_I18N /* Check the space of the arrays. */ if (*char_class_alloc == mbcset->nchar_classes) { /* Not enough, realloc it. */ /* +1 in case of mbcset->nchar_classes is 0. */ *char_class_alloc = 2 * mbcset->nchar_classes + 1; /* Use realloc since array is NULL if *alloc == 0. */ mbcset->char_classes = re_realloc (mbcset->char_classes, wctype_t, *char_class_alloc); if (BE (mbcset->char_classes == NULL, 0)) return REG_ESPACE; } mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name); #endif /* RE_ENABLE_I18N */ #define BUILD_CHARCLASS_LOOP(ctype_func)\ for (i = 0; i < SBC_MAX; ++i) \ { \ if (ctype_func (i)) \ bitset_set (sbcset, i); \ } if (strcmp (name, "alnum") == 0) BUILD_CHARCLASS_LOOP (isalnum) else if (strcmp (name, "cntrl") == 0) BUILD_CHARCLASS_LOOP (iscntrl) else if (strcmp (name, "lower") == 0) BUILD_CHARCLASS_LOOP (islower) else if (strcmp (name, "space") == 0) BUILD_CHARCLASS_LOOP (isspace) else if (strcmp (name, "alpha") == 0) BUILD_CHARCLASS_LOOP (isalpha) else if (strcmp (name, "digit") == 0) BUILD_CHARCLASS_LOOP (isdigit) else if (strcmp (name, "print") == 0) BUILD_CHARCLASS_LOOP (isprint) else if (strcmp (name, "upper") == 0) BUILD_CHARCLASS_LOOP (isupper) else if (strcmp (name, "blank") == 0) BUILD_CHARCLASS_LOOP (isblank) else if (strcmp (name, "graph") == 0) BUILD_CHARCLASS_LOOP (isgraph) else if (strcmp (name, "punct") == 0) BUILD_CHARCLASS_LOOP (ispunct) else if (strcmp (name, "xdigit") == 0) BUILD_CHARCLASS_LOOP (isxdigit) else return REG_ECTYPE; return REG_NOERROR; } static bin_tree_t * build_word_op (dfa, not, err) re_dfa_t *dfa; int not; reg_errcode_t *err; { re_bitset_ptr_t sbcset; #ifdef RE_ENABLE_I18N re_charset_t *mbcset; int alloc = 0; #else /* not RE_ENABLE_I18N */ int non_match = 0; #endif /* not RE_ENABLE_I18N */ reg_errcode_t ret; re_token_t br_token; bin_tree_t *tree; int new_idx; sbcset = (re_bitset_ptr_t) calloc (sizeof (unsigned int), BITSET_UINTS); #ifdef RE_ENABLE_I18N mbcset = (re_charset_t *) calloc (sizeof (re_charset_t), 1); #endif /* RE_ENABLE_I18N */ #ifdef RE_ENABLE_I18N if (BE (sbcset == NULL || mbcset == NULL, 0)) #else /* not RE_ENABLE_I18N */ if (BE (sbcset == NULL, 0)) #endif /* not RE_ENABLE_I18N */ { *err = REG_ESPACE; return NULL; } if (not) { #ifdef RE_ENABLE_I18N int i; /* if (syntax & RE_HAT_LISTS_NOT_NEWLINE) bitset_set(cset->sbcset, '\0'); */ mbcset->non_match = 1; if (MB_CUR_MAX > 1) for (i = 0; i < SBC_MAX; ++i) if (__btowc (i) == WEOF) bitset_set (sbcset, i); #else /* not RE_ENABLE_I18N */ non_match = 1; #endif /* not RE_ENABLE_I18N */ } /* We don't care the syntax in this case. */ ret = build_charclass (sbcset, #ifdef RE_ENABLE_I18N mbcset, &alloc, #endif /* RE_ENABLE_I18N */ (const unsigned char *) "alpha", 0); if (BE (ret != REG_NOERROR, 0)) { re_free (sbcset); #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* RE_ENABLE_I18N */ *err = ret; return NULL; } /* \w match '_' also. */ bitset_set (sbcset, '_'); /* If it is non-matching list. */ #ifdef RE_ENABLE_I18N if (mbcset->non_match) #else /* not RE_ENABLE_I18N */ if (non_match) #endif /* not RE_ENABLE_I18N */ bitset_not (sbcset); /* Build a tree for simple bracket. */ br_token.type = SIMPLE_BRACKET; br_token.opr.sbcset = sbcset; new_idx = re_dfa_add_node (dfa, br_token, 0); tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || tree == NULL, 0)) goto build_word_op_espace; #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) { re_token_t alt_token; bin_tree_t *mbc_tree; /* Build a tree for complex bracket. */ br_token.type = COMPLEX_BRACKET; br_token.opr.mbcset = mbcset; dfa->has_mb_node = 1; new_idx = re_dfa_add_node (dfa, br_token, 0); mbc_tree = create_tree (NULL, NULL, 0, new_idx); if (BE (new_idx == -1 || mbc_tree == NULL, 0)) goto build_word_op_espace; /* Then join them by ALT node. */ alt_token.type = OP_ALT; new_idx = re_dfa_add_node (dfa, alt_token, 0); tree = create_tree (tree, mbc_tree, 0, new_idx); if (BE (new_idx != -1 && mbc_tree != NULL, 1)) return tree; } else { free_charset (mbcset); return tree; } #else /* not RE_ENABLE_I18N */ return tree; #endif /* not RE_ENABLE_I18N */ build_word_op_espace: re_free (sbcset); #ifdef RE_ENABLE_I18N free_charset (mbcset); #endif /* RE_ENABLE_I18N */ *err = REG_ESPACE; return NULL; } /* This is intended for the expressions like "a{1,3}". Fetch a number from `input', and return the number. Return -1, if the number field is empty like "{,1}". Return -2, If an error is occured. */ static int fetch_number (input, token, syntax) re_string_t *input; re_token_t *token; reg_syntax_t syntax; { int num = -1; unsigned char c; while (1) { *token = fetch_token (input, syntax); c = token->opr.c; if (BE (token->type == END_OF_RE, 0)) return -2; if (token->type == OP_CLOSE_DUP_NUM || c == ',') break; num = ((token->type != CHARACTER || c < '0' || '9' < c || num == -2) ? -2 : ((num == -1) ? c - '0' : num * 10 + c - '0')); num = (num > RE_DUP_MAX) ? -2 : num; } return num; } #ifdef RE_ENABLE_I18N static void free_charset (re_charset_t *cset) { re_free (cset->mbchars); # ifdef _LIBC re_free (cset->coll_syms); re_free (cset->equiv_classes); re_free (cset->range_starts); re_free (cset->range_ends); # endif re_free (cset->char_classes); re_free (cset); } #endif /* RE_ENABLE_I18N */ /* Functions for binary tree operation. */ /* Create a node of tree. Note: This function automatically free left and right if malloc fails. */ static bin_tree_t * create_tree (left, right, type, index) bin_tree_t *left; bin_tree_t *right; re_token_type_t type; int index; { bin_tree_t *tree; tree = re_malloc (bin_tree_t, 1); if (BE (tree == NULL, 0)) { free_bin_tree (left); free_bin_tree (right); return NULL; } tree->parent = NULL; tree->left = left; tree->right = right; tree->type = type; tree->node_idx = index; tree->first = -1; tree->next = -1; re_node_set_init_empty (&tree->eclosure); if (left != NULL) left->parent = tree; if (right != NULL) right->parent = tree; return tree; } /* Free the sub tree pointed by TREE. */ static void free_bin_tree (tree) bin_tree_t *tree; { if (tree == NULL) return; /*re_node_set_free (&tree->eclosure);*/ free_bin_tree (tree->left); free_bin_tree (tree->right); re_free (tree); } /* Duplicate the node SRC, and return new node. */ static bin_tree_t * duplicate_tree (src, dfa) const bin_tree_t *src; re_dfa_t *dfa; { bin_tree_t *left = NULL, *right = NULL, *new_tree; int new_node_idx; /* Since node indies must be according to Post-order of the tree, we must duplicate the left at first. */ if (src->left != NULL) { left = duplicate_tree (src->left, dfa); if (left == NULL) return NULL; } /* Secondaly, duplicate the right. */ if (src->right != NULL) { right = duplicate_tree (src->right, dfa); if (right == NULL) { free_bin_tree (left); return NULL; } } /* At last, duplicate itself. */ if (src->type == NON_TYPE) { new_node_idx = re_dfa_add_node (dfa, dfa->nodes[src->node_idx], 0); dfa->nodes[new_node_idx].duplicated = 1; if (BE (new_node_idx == -1, 0)) { free_bin_tree (left); free_bin_tree (right); return NULL; } } else new_node_idx = src->type; new_tree = create_tree (left, right, src->type, new_node_idx); if (BE (new_tree == NULL, 0)) { free_bin_tree (left); free_bin_tree (right); } return new_tree; } ������������������������smartmontools-6.2+svn3841.orig/regex/regexec.c������������������������������������������������������0000644�0000000�0000000�00000351040�12062407372�017767� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Extended regular expression matching and search library. Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ static reg_errcode_t match_ctx_init (re_match_context_t *cache, int eflags, re_string_t *input, int n); static void match_ctx_clean (re_match_context_t *mctx); static void match_ctx_free (re_match_context_t *cache); static void match_ctx_free_subtops (re_match_context_t *mctx); static reg_errcode_t match_ctx_add_entry (re_match_context_t *cache, int node, int str_idx, int from, int to); static int search_cur_bkref_entry (re_match_context_t *mctx, int str_idx); static void match_ctx_clear_flag (re_match_context_t *mctx); static reg_errcode_t match_ctx_add_subtop (re_match_context_t *mctx, int node, int str_idx); static re_sub_match_last_t * match_ctx_add_sublast (re_sub_match_top_t *subtop, int node, int str_idx); static void sift_ctx_init (re_sift_context_t *sctx, re_dfastate_t **sifted_sts, re_dfastate_t **limited_sts, int last_node, int last_str_idx, int check_subexp); static reg_errcode_t re_search_internal (const regex_t *preg, const char *string, int length, int start, int range, int stop, size_t nmatch, regmatch_t pmatch[], int eflags); static int re_search_2_stub (struct re_pattern_buffer *bufp, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop, int ret_len); static int re_search_stub (struct re_pattern_buffer *bufp, const char *string, int length, int start, int range, int stop, struct re_registers *regs, int ret_len); static unsigned re_copy_regs (struct re_registers *regs, regmatch_t *pmatch, int nregs, int regs_allocated); static inline re_dfastate_t *acquire_init_state_context (reg_errcode_t *err, const regex_t *preg, const re_match_context_t *mctx, int idx); static reg_errcode_t prune_impossible_nodes (const regex_t *preg, re_match_context_t *mctx); static int check_matching (const regex_t *preg, re_match_context_t *mctx, int fl_search, int fl_longest_match); static int check_halt_node_context (const re_dfa_t *dfa, int node, unsigned int context); static int check_halt_state_context (const regex_t *preg, const re_dfastate_t *state, const re_match_context_t *mctx, int idx); static void update_regs (re_dfa_t *dfa, regmatch_t *pmatch, int cur_node, int cur_idx, int nmatch); static int proceed_next_node (const regex_t *preg, int nregs, regmatch_t *regs, const re_match_context_t *mctx, int *pidx, int node, re_node_set *eps_via_nodes, struct re_fail_stack_t *fs); static reg_errcode_t push_fail_stack (struct re_fail_stack_t *fs, int str_idx, int *dests, int nregs, regmatch_t *regs, re_node_set *eps_via_nodes); static int pop_fail_stack (struct re_fail_stack_t *fs, int *pidx, int nregs, regmatch_t *regs, re_node_set *eps_via_nodes); static reg_errcode_t set_regs (const regex_t *preg, const re_match_context_t *mctx, size_t nmatch, regmatch_t *pmatch, int fl_backtrack); static reg_errcode_t free_fail_stack_return (struct re_fail_stack_t *fs); #ifdef RE_ENABLE_I18N static int sift_states_iter_mb (const regex_t *preg, const re_match_context_t *mctx, re_sift_context_t *sctx, int node_idx, int str_idx, int max_str_idx); #endif /* RE_ENABLE_I18N */ static reg_errcode_t sift_states_backward (const regex_t *preg, re_match_context_t *mctx, re_sift_context_t *sctx); static reg_errcode_t update_cur_sifted_state (const regex_t *preg, re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, re_node_set *dest_nodes); static reg_errcode_t add_epsilon_src_nodes (re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates); static reg_errcode_t sub_epsilon_src_nodes (re_dfa_t *dfa, int node, re_node_set *dest_nodes, const re_node_set *and_nodes); static int check_dst_limits (re_dfa_t *dfa, re_node_set *limits, re_match_context_t *mctx, int dst_node, int dst_idx, int src_node, int src_idx); static int check_dst_limits_calc_pos (re_dfa_t *dfa, re_match_context_t *mctx, int limit, re_node_set *eclosures, int subexp_idx, int node, int str_idx); static reg_errcode_t check_subexp_limits (re_dfa_t *dfa, re_node_set *dest_nodes, const re_node_set *candidates, re_node_set *limits, struct re_backref_cache_entry *bkref_ents, int str_idx); static reg_errcode_t sift_states_bkref (const regex_t *preg, re_match_context_t *mctx, re_sift_context_t *sctx, int str_idx, re_node_set *dest_nodes); static reg_errcode_t clean_state_log_if_need (re_match_context_t *mctx, int next_state_log_idx); static reg_errcode_t merge_state_array (re_dfa_t *dfa, re_dfastate_t **dst, re_dfastate_t **src, int num); static re_dfastate_t *transit_state (reg_errcode_t *err, const regex_t *preg, re_match_context_t *mctx, re_dfastate_t *state, int fl_search); static reg_errcode_t check_subexp_matching_top (re_dfa_t *dfa, re_match_context_t *mctx, re_node_set *cur_nodes, int str_idx); static re_dfastate_t *transit_state_sb (reg_errcode_t *err, const regex_t *preg, re_dfastate_t *pstate, int fl_search, re_match_context_t *mctx); #ifdef RE_ENABLE_I18N static reg_errcode_t transit_state_mb (const regex_t *preg, re_dfastate_t *pstate, re_match_context_t *mctx); #endif /* RE_ENABLE_I18N */ static reg_errcode_t transit_state_bkref (const regex_t *preg, re_node_set *nodes, re_match_context_t *mctx); static reg_errcode_t get_subexp (const regex_t *preg, re_match_context_t *mctx, int bkref_node, int bkref_str_idx); static reg_errcode_t get_subexp_sub (const regex_t *preg, re_match_context_t *mctx, re_sub_match_top_t *sub_top, re_sub_match_last_t *sub_last, int bkref_node, int bkref_str); static int find_subexp_node (re_dfa_t *dfa, re_node_set *nodes, int subexp_idx, int fl_open); static reg_errcode_t check_arrival (const regex_t *preg, re_match_context_t *mctx, state_array_t *path, int top_node, int top_str, int last_node, int last_str, int fl_open); static reg_errcode_t check_arrival_add_next_nodes (const regex_t *preg, re_dfa_t *dfa, re_match_context_t *mctx, int str_idx, re_node_set *cur_nodes, re_node_set *next_nodes); static reg_errcode_t check_arrival_expand_ecl (re_dfa_t *dfa, re_node_set *cur_nodes, int ex_subexp, int fl_open); static reg_errcode_t check_arrival_expand_ecl_sub (re_dfa_t *dfa, re_node_set *dst_nodes, int target, int ex_subexp, int fl_open); static reg_errcode_t expand_bkref_cache (const regex_t *preg, re_match_context_t *mctx, re_node_set *cur_nodes, int cur_str, int last_str, int subexp_num, int fl_open); static re_dfastate_t **build_trtable (const regex_t *dfa, const re_dfastate_t *state, int fl_search); #ifdef RE_ENABLE_I18N static int check_node_accept_bytes (const regex_t *preg, int node_idx, const re_string_t *input, int idx); # ifdef _LIBC static unsigned int find_collation_sequence_value (const unsigned char *mbs, size_t name_len); # endif /* _LIBC */ #endif /* RE_ENABLE_I18N */ static int group_nodes_into_DFAstates (const regex_t *dfa, const re_dfastate_t *state, re_node_set *states_node, bitset *states_ch); static int check_node_accept (const regex_t *preg, const re_token_t *node, const re_match_context_t *mctx, int idx); static reg_errcode_t extend_buffers (re_match_context_t *mctx); /* Entry point for POSIX code. */ /* regexec searches for a given pattern, specified by PREG, in the string STRING. If NMATCH is zero or REG_NOSUB was set in the cflags argument to `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at least NMATCH elements, and we set them to the offsets of the corresponding matched substrings. EFLAGS specifies `execution flags' which affect matching: if REG_NOTBOL is set, then ^ does not match at the beginning of the string; if REG_NOTEOL is set, then $ does not match at the end. We return 0 if we find a match and REG_NOMATCH if not. */ int regexec (preg, string, nmatch, pmatch, eflags) const regex_t *__restrict preg; const char *__restrict string; size_t nmatch; regmatch_t pmatch[]; int eflags; { reg_errcode_t err; int length = strlen (string); if (preg->no_sub) err = re_search_internal (preg, string, length, 0, length, length, 0, NULL, eflags); else err = re_search_internal (preg, string, length, 0, length, length, nmatch, pmatch, eflags); return err != REG_NOERROR; } #ifdef _LIBC weak_alias (__regexec, regexec) #endif /* Entry points for GNU code. */ /* re_match, re_search, re_match_2, re_search_2 The former two functions operate on STRING with length LENGTH, while the later two operate on concatenation of STRING1 and STRING2 with lengths LENGTH1 and LENGTH2, respectively. re_match() matches the compiled pattern in BUFP against the string, starting at index START. re_search() first tries matching at index START, then it tries to match starting from index START + 1, and so on. The last start position tried is START + RANGE. (Thus RANGE = 0 forces re_search to operate the same way as re_match().) The parameter STOP of re_{match,search}_2 specifies that no match exceeding the first STOP characters of the concatenation of the strings should be concerned. If REGS is not NULL, and BUFP->no_sub is not set, the offsets of the match and all groups is stroed in REGS. (For the "_2" variants, the offsets are computed relative to the concatenation, not relative to the individual strings.) On success, re_match* functions return the length of the match, re_search* return the position of the start of the match. Return value -1 means no match was found and -2 indicates an internal error. */ int re_match (bufp, string, length, start, regs) struct re_pattern_buffer *bufp; const char *string; int length, start; struct re_registers *regs; { return re_search_stub (bufp, string, length, start, 0, length, regs, 1); } #ifdef _LIBC weak_alias (__re_match, re_match) #endif int re_search (bufp, string, length, start, range, regs) struct re_pattern_buffer *bufp; const char *string; int length, start, range; struct re_registers *regs; { return re_search_stub (bufp, string, length, start, range, length, regs, 0); } #ifdef _LIBC weak_alias (__re_search, re_search) #endif int re_match_2 (bufp, string1, length1, string2, length2, start, regs, stop) struct re_pattern_buffer *bufp; const char *string1, *string2; int length1, length2, start, stop; struct re_registers *regs; { return re_search_2_stub (bufp, string1, length1, string2, length2, start, 0, regs, stop, 1); } #ifdef _LIBC weak_alias (__re_match_2, re_match_2) #endif int re_search_2 (bufp, string1, length1, string2, length2, start, range, regs, stop) struct re_pattern_buffer *bufp; const char *string1, *string2; int length1, length2, start, range, stop; struct re_registers *regs; { return re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, stop, 0); } #ifdef _LIBC weak_alias (__re_search_2, re_search_2) #endif static int re_search_2_stub (bufp, string1, length1, string2, length2, start, range, regs, stop, ret_len) struct re_pattern_buffer *bufp; const char *string1, *string2; int length1, length2, start, range, stop, ret_len; struct re_registers *regs; { const char *str; int rval; int len = length1 + length2; int free_str = 0; if (BE (length1 < 0 || length2 < 0 || stop < 0, 0)) return -2; /* Concatenate the strings. */ if (length2 > 0) if (length1 > 0) { char *s = re_malloc (char, len); if (BE (s == NULL, 0)) return -2; memcpy (s, string1, length1); memcpy (s + length1, string2, length2); str = s; free_str = 1; } else str = string2; else str = string1; rval = re_search_stub (bufp, str, len, start, range, stop, regs, ret_len); if (free_str) re_free ((char *) str); return rval; } /* The parameters have the same meaning as those of re_search. Additional parameters: If RET_LEN is nonzero the length of the match is returned (re_match style); otherwise the position of the match is returned. */ static int re_search_stub (bufp, string, length, start, range, stop, regs, ret_len) struct re_pattern_buffer *bufp; const char *string; int length, start, range, stop, ret_len; struct re_registers *regs; { reg_errcode_t result; regmatch_t *pmatch; int nregs, rval; int eflags = 0; /* Check for out-of-range. */ if (BE (start < 0 || start > length, 0)) return -1; if (BE (start + range > length, 0)) range = length - start; else if (BE (start + range < 0, 0)) range = -start; eflags |= (bufp->not_bol) ? REG_NOTBOL : 0; eflags |= (bufp->not_eol) ? REG_NOTEOL : 0; /* Compile fastmap if we haven't yet. */ if (range > 0 && bufp->fastmap != NULL && !bufp->fastmap_accurate) re_compile_fastmap (bufp); if (BE (bufp->no_sub, 0)) regs = NULL; /* We need at least 1 register. */ if (regs == NULL) nregs = 1; else if (BE (bufp->regs_allocated == REGS_FIXED && regs->num_regs < bufp->re_nsub + 1, 0)) { nregs = regs->num_regs; if (BE (nregs < 1, 0)) { /* Nothing can be copied to regs. */ regs = NULL; nregs = 1; } } else nregs = bufp->re_nsub + 1; pmatch = re_malloc (regmatch_t, nregs); if (BE (pmatch == NULL, 0)) return -2; result = re_search_internal (bufp, string, length, start, range, stop, nregs, pmatch, eflags); rval = 0; /* I hope we needn't fill ther regs with -1's when no match was found. */ if (result != REG_NOERROR) rval = -1; else if (regs != NULL) { /* If caller wants register contents data back, copy them. */ bufp->regs_allocated = re_copy_regs (regs, pmatch, nregs, bufp->regs_allocated); if (BE (bufp->regs_allocated == REGS_UNALLOCATED, 0)) rval = -2; } if (BE (rval == 0, 1)) { if (ret_len) { assert (pmatch[0].rm_so == start); rval = pmatch[0].rm_eo - start; } else rval = pmatch[0].rm_so; } re_free (pmatch); return rval; } static unsigned re_copy_regs (regs, pmatch, nregs, regs_allocated) struct re_registers *regs; regmatch_t *pmatch; int nregs, regs_allocated; { int rval = REGS_REALLOCATE; int i; int need_regs = nregs + 1; /* We need one extra element beyond `num_regs' for the `-1' marker GNU code uses. */ /* Have the register data arrays been allocated? */ if (regs_allocated == REGS_UNALLOCATED) { /* No. So allocate them with malloc. */ regs->start = re_malloc (regoff_t, need_regs); if (BE (regs->start == NULL, 0)) return REGS_UNALLOCATED; regs->end = re_malloc (regoff_t, need_regs); if (BE (regs->end == NULL, 0)) { re_free (regs->start); return REGS_UNALLOCATED; } regs->num_regs = need_regs; } else if (regs_allocated == REGS_REALLOCATE) { /* Yes. If we need more elements than were already allocated, reallocate them. If we need fewer, just leave it alone. */ if (need_regs > regs->num_regs) { regs->start = re_realloc (regs->start, regoff_t, need_regs); if (BE (regs->start == NULL, 0)) { if (regs->end != NULL) re_free (regs->end); return REGS_UNALLOCATED; } regs->end = re_realloc (regs->end, regoff_t, need_regs); if (BE (regs->end == NULL, 0)) { re_free (regs->start); return REGS_UNALLOCATED; } regs->num_regs = need_regs; } } else { assert (regs_allocated == REGS_FIXED); /* This function may not be called with REGS_FIXED and nregs too big. */ assert (regs->num_regs >= nregs); rval = REGS_FIXED; } /* Copy the regs. */ for (i = 0; i < nregs; ++i) { regs->start[i] = pmatch[i].rm_so; regs->end[i] = pmatch[i].rm_eo; } for ( ; i < regs->num_regs; ++i) regs->start[i] = regs->end[i] = -1; return rval; } /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated using the malloc library routine, and must each be at least NUM_REGS * sizeof (regoff_t) bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ void re_set_registers (bufp, regs, num_regs, starts, ends) struct re_pattern_buffer *bufp; struct re_registers *regs; unsigned num_regs; regoff_t *starts, *ends; { if (num_regs) { bufp->regs_allocated = REGS_REALLOCATE; regs->num_regs = num_regs; regs->start = starts; regs->end = ends; } else { bufp->regs_allocated = REGS_UNALLOCATED; regs->num_regs = 0; regs->start = regs->end = (regoff_t *) 0; } } #ifdef _LIBC weak_alias (__re_set_registers, re_set_registers) #endif /* Entry points compatible with 4.2 BSD regex library. We don't define them unless specifically requested. */ #if defined _REGEX_RE_COMP || defined _LIBC int # ifdef _LIBC weak_function # endif re_exec (s) const char *s; { return 0 == regexec (&re_comp_buf, s, 0, NULL, 0); } #endif /* _REGEX_RE_COMP */ static re_node_set empty_set; /* Internal entry point. */ /* Searches for a compiled pattern PREG in the string STRING, whose length is LENGTH. NMATCH, PMATCH, and EFLAGS have the same mingings with regexec. START, and RANGE have the same meanings with re_search. Return REG_NOERROR if we find a match, and REG_NOMATCH if not, otherwise return the error code. Note: We assume front end functions already check ranges. (START + RANGE >= 0 && START + RANGE <= LENGTH) */ static reg_errcode_t re_search_internal (preg, string, length, start, range, stop, nmatch, pmatch, eflags) const regex_t *preg; const char *string; int length, start, range, stop, eflags; size_t nmatch; regmatch_t pmatch[]; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *)preg->buffer; re_string_t input; int left_lim, right_lim, incr; int fl_longest_match, match_first, match_last = -1; int fast_translate, sb; re_match_context_t mctx; char *fastmap = ((preg->fastmap != NULL && preg->fastmap_accurate && range && !preg->can_be_null) ? preg->fastmap : NULL); /* Check if the DFA haven't been compiled. */ if (BE (preg->used == 0 || dfa->init_state == NULL || dfa->init_state_word == NULL || dfa->init_state_nl == NULL || dfa->init_state_begbuf == NULL, 0)) return REG_NOMATCH; re_node_set_init_empty (&empty_set); memset (&mctx, '\0', sizeof (re_match_context_t)); /* We must check the longest matching, if nmatch > 0. */ fl_longest_match = (nmatch != 0 || dfa->nbackref); err = re_string_allocate (&input, string, length, dfa->nodes_len + 1, preg->translate, preg->syntax & RE_ICASE); if (BE (err != REG_NOERROR, 0)) goto free_return; input.stop = stop; err = match_ctx_init (&mctx, eflags, &input, dfa->nbackref * 2); if (BE (err != REG_NOERROR, 0)) goto free_return; /* We will log all the DFA states through which the dfa pass, if nmatch > 1, or this dfa has "multibyte node", which is a back-reference or a node which can accept multibyte character or multi character collating element. */ if (nmatch > 1 || dfa->has_mb_node) { mctx.state_log = re_malloc (re_dfastate_t *, dfa->nodes_len + 1); if (BE (mctx.state_log == NULL, 0)) { err = REG_ESPACE; goto free_return; } } else mctx.state_log = NULL; #ifdef DEBUG /* We assume front-end functions already check them. */ assert (start + range >= 0 && start + range <= length); #endif match_first = start; input.tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF : CONTEXT_NEWLINE | CONTEXT_BEGBUF); /* Check incrementally whether of not the input string match. */ incr = (range < 0) ? -1 : 1; left_lim = (range < 0) ? start + range : start; right_lim = (range < 0) ? start : start + range; sb = MB_CUR_MAX == 1; fast_translate = sb || !(preg->syntax & RE_ICASE || preg->translate); for (;;) { /* At first get the current byte from input string. */ if (fastmap) { if (BE (fast_translate, 1)) { unsigned RE_TRANSLATE_TYPE t = (unsigned RE_TRANSLATE_TYPE) preg->translate; if (BE (range >= 0, 1)) { if (BE (t != NULL, 0)) { while (BE (match_first < right_lim, 1) && !fastmap[t[(unsigned char) string[match_first]]]) ++match_first; } else { while (BE (match_first < right_lim, 1) && !fastmap[(unsigned char) string[match_first]]) ++match_first; } if (BE (match_first == right_lim, 0)) { int ch = match_first >= length ? 0 : (unsigned char) string[match_first]; if (!fastmap[t ? t[ch] : ch]) break; } } else { while (match_first >= left_lim) { int ch = match_first >= length ? 0 : (unsigned char) string[match_first]; if (fastmap[t ? t[ch] : ch]) break; --match_first; } if (match_first < left_lim) break; } } else { int ch; do { /* In this case, we can't determine easily the current byte, since it might be a component byte of a multibyte character. Then we use the constructed buffer instead. */ /* If MATCH_FIRST is out of the valid range, reconstruct the buffers. */ if (input.raw_mbs_idx + input.valid_len <= match_first || match_first < input.raw_mbs_idx) { err = re_string_reconstruct (&input, match_first, eflags, preg->newline_anchor); if (BE (err != REG_NOERROR, 0)) goto free_return; } /* If MATCH_FIRST is out of the buffer, leave it as '\0'. Note that MATCH_FIRST must not be smaller than 0. */ ch = ((match_first >= length) ? 0 : re_string_byte_at (&input, match_first - input.raw_mbs_idx)); if (fastmap[ch]) break; match_first += incr; } while (match_first >= left_lim && match_first <= right_lim); if (! fastmap[ch]) break; } } /* Reconstruct the buffers so that the matcher can assume that the matching starts from the begining of the buffer. */ err = re_string_reconstruct (&input, match_first, eflags, preg->newline_anchor); if (BE (err != REG_NOERROR, 0)) goto free_return; #ifdef RE_ENABLE_I18N /* Eliminate it when it is a component of a multibyte character and isn't the head of a multibyte character. */ if (sb || re_string_first_byte (&input, 0)) #endif { /* It seems to be appropriate one, then use the matcher. */ /* We assume that the matching starts from 0. */ mctx.state_log_top = mctx.nbkref_ents = mctx.max_mb_elem_len = 0; match_last = check_matching (preg, &mctx, 0, fl_longest_match); if (match_last != -1) { if (BE (match_last == -2, 0)) { err = REG_ESPACE; goto free_return; } else { mctx.match_last = match_last; if ((!preg->no_sub && nmatch > 1) || dfa->nbackref) { re_dfastate_t *pstate = mctx.state_log[match_last]; mctx.last_node = check_halt_state_context (preg, pstate, &mctx, match_last); } if ((!preg->no_sub && nmatch > 1 && dfa->has_plural_match) || dfa->nbackref) { err = prune_impossible_nodes (preg, &mctx); if (err == REG_NOERROR) break; if (BE (err != REG_NOMATCH, 0)) goto free_return; } else break; /* We found a matching. */ } } match_ctx_clean (&mctx); } /* Update counter. */ match_first += incr; if (match_first < left_lim || right_lim < match_first) break; } /* Set pmatch[] if we need. */ if (match_last != -1 && nmatch > 0) { int reg_idx; /* Initialize registers. */ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) pmatch[reg_idx].rm_so = pmatch[reg_idx].rm_eo = -1; /* Set the points where matching start/end. */ pmatch[0].rm_so = 0; pmatch[0].rm_eo = mctx.match_last; if (!preg->no_sub && nmatch > 1) { err = set_regs (preg, &mctx, nmatch, pmatch, dfa->has_plural_match && dfa->nbackref > 0); if (BE (err != REG_NOERROR, 0)) goto free_return; } /* At last, add the offset to the each registers, since we slided the buffers so that We can assume that the matching starts from 0. */ for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) if (pmatch[reg_idx].rm_so != -1) { pmatch[reg_idx].rm_so += match_first; pmatch[reg_idx].rm_eo += match_first; } } err = (match_last == -1) ? REG_NOMATCH : REG_NOERROR; free_return: re_free (mctx.state_log); if (dfa->nbackref) match_ctx_free (&mctx); re_string_destruct (&input); return err; } static reg_errcode_t prune_impossible_nodes (preg, mctx) const regex_t *preg; re_match_context_t *mctx; { int halt_node, match_last; reg_errcode_t ret; re_dfa_t *dfa = (re_dfa_t *)preg->buffer; re_dfastate_t **sifted_states; re_dfastate_t **lim_states = NULL; re_sift_context_t sctx; #ifdef DEBUG assert (mctx->state_log != NULL); #endif match_last = mctx->match_last; halt_node = mctx->last_node; sifted_states = re_malloc (re_dfastate_t *, match_last + 1); if (BE (sifted_states == NULL, 0)) { ret = REG_ESPACE; goto free_return; } if (dfa->nbackref) { lim_states = re_malloc (re_dfastate_t *, match_last + 1); if (BE (lim_states == NULL, 0)) { ret = REG_ESPACE; goto free_return; } while (1) { memset (lim_states, '\0', sizeof (re_dfastate_t *) * (match_last + 1)); match_ctx_clear_flag (mctx); sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last, 0); ret = sift_states_backward (preg, mctx, &sctx); re_node_set_free (&sctx.limits); if (BE (ret != REG_NOERROR, 0)) goto free_return; if (sifted_states[0] != NULL || lim_states[0] != NULL) break; do { --match_last; if (match_last < 0) { ret = REG_NOMATCH; goto free_return; } } while (!mctx->state_log[match_last]->halt); halt_node = check_halt_state_context (preg, mctx->state_log[match_last], mctx, match_last); } ret = merge_state_array (dfa, sifted_states, lim_states, match_last + 1); re_free (lim_states); lim_states = NULL; if (BE (ret != REG_NOERROR, 0)) goto free_return; } else { sift_ctx_init (&sctx, sifted_states, lim_states, halt_node, match_last, 0); ret = sift_states_backward (preg, mctx, &sctx); re_node_set_free (&sctx.limits); if (BE (ret != REG_NOERROR, 0)) goto free_return; } re_free (mctx->state_log); mctx->state_log = sifted_states; sifted_states = NULL; mctx->last_node = halt_node; mctx->match_last = match_last; ret = REG_NOERROR; free_return: re_free (sifted_states); re_free (lim_states); return ret; } /* Acquire an initial state and return it. We must select appropriate initial state depending on the context, since initial states may have constraints like "\<", "^", etc.. */ static inline re_dfastate_t * acquire_init_state_context (err, preg, mctx, idx) reg_errcode_t *err; const regex_t *preg; const re_match_context_t *mctx; int idx; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; *err = REG_NOERROR; if (dfa->init_state->has_constraint) { unsigned int context; context = re_string_context_at (mctx->input, idx - 1, mctx->eflags, preg->newline_anchor); if (IS_WORD_CONTEXT (context)) return dfa->init_state_word; else if (IS_ORDINARY_CONTEXT (context)) return dfa->init_state; else if (IS_BEGBUF_CONTEXT (context) && IS_NEWLINE_CONTEXT (context)) return dfa->init_state_begbuf; else if (IS_NEWLINE_CONTEXT (context)) return dfa->init_state_nl; else if (IS_BEGBUF_CONTEXT (context)) { /* It is relatively rare case, then calculate on demand. */ return re_acquire_state_context (err, dfa, dfa->init_state->entrance_nodes, context); } else /* Must not happen? */ return dfa->init_state; } else return dfa->init_state; } /* Check whether the regular expression match input string INPUT or not, and return the index where the matching end, return -1 if not match, or return -2 in case of an error. FL_SEARCH means we must search where the matching starts, FL_LONGEST_MATCH means we want the POSIX longest matching. Note that the matcher assume that the maching starts from the current index of the buffer. */ static int check_matching (preg, mctx, fl_search, fl_longest_match) const regex_t *preg; re_match_context_t *mctx; int fl_search, fl_longest_match; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; reg_errcode_t err; int match = 0; int match_last = -1; int cur_str_idx = re_string_cur_idx (mctx->input); re_dfastate_t *cur_state; cur_state = acquire_init_state_context (&err, preg, mctx, cur_str_idx); /* An initial state must not be NULL(invalid state). */ if (BE (cur_state == NULL, 0)) return -2; if (mctx->state_log != NULL) mctx->state_log[cur_str_idx] = cur_state; /* Check OP_OPEN_SUBEXP in the initial state in case that we use them later. E.g. Processing back references. */ if (dfa->nbackref) { err = check_subexp_matching_top (dfa, mctx, &cur_state->nodes, 0); if (BE (err != REG_NOERROR, 0)) return err; } if (cur_state->has_backref) { err = transit_state_bkref (preg, &cur_state->nodes, mctx); if (BE (err != REG_NOERROR, 0)) return err; } /* If the RE accepts NULL string. */ if (cur_state->halt) { if (!cur_state->has_constraint || check_halt_state_context (preg, cur_state, mctx, cur_str_idx)) { if (!fl_longest_match) return cur_str_idx; else { match_last = cur_str_idx; match = 1; } } } while (!re_string_eoi (mctx->input)) { cur_state = transit_state (&err, preg, mctx, cur_state, fl_search && !match); if (cur_state == NULL) /* Reached at the invalid state or an error. */ { cur_str_idx = re_string_cur_idx (mctx->input); if (BE (err != REG_NOERROR, 0)) return -2; if (fl_search && !match) { /* Restart from initial state, since we are searching the point from where matching start. */ #ifdef RE_ENABLE_I18N if (MB_CUR_MAX == 1 || re_string_first_byte (mctx->input, cur_str_idx)) #endif /* RE_ENABLE_I18N */ cur_state = acquire_init_state_context (&err, preg, mctx, cur_str_idx); if (BE (cur_state == NULL && err != REG_NOERROR, 0)) return -2; if (mctx->state_log != NULL) mctx->state_log[cur_str_idx] = cur_state; } else if (!fl_longest_match && match) break; else /* (fl_longest_match && match) || (!fl_search && !match) */ { if (mctx->state_log == NULL) break; else { int max = mctx->state_log_top; for (; cur_str_idx <= max; ++cur_str_idx) if (mctx->state_log[cur_str_idx] != NULL) break; if (cur_str_idx > max) break; } } } if (cur_state != NULL && cur_state->halt) { /* Reached at a halt state. Check the halt state can satisfy the current context. */ if (!cur_state->has_constraint || check_halt_state_context (preg, cur_state, mctx, re_string_cur_idx (mctx->input))) { /* We found an appropriate halt state. */ match_last = re_string_cur_idx (mctx->input); match = 1; if (!fl_longest_match) break; } } } return match_last; } /* Check NODE match the current context. */ static int check_halt_node_context (dfa, node, context) const re_dfa_t *dfa; int node; unsigned int context; { re_token_type_t type = dfa->nodes[node].type; unsigned int constraint = dfa->nodes[node].constraint; if (type != END_OF_RE) return 0; if (!constraint) return 1; if (NOT_SATISFY_NEXT_CONSTRAINT (constraint, context)) return 0; return 1; } /* Check the halt state STATE match the current context. Return 0 if not match, if the node, STATE has, is a halt node and match the context, return the node. */ static int check_halt_state_context (preg, state, mctx, idx) const regex_t *preg; const re_dfastate_t *state; const re_match_context_t *mctx; int idx; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int i; unsigned int context; #ifdef DEBUG assert (state->halt); #endif context = re_string_context_at (mctx->input, idx, mctx->eflags, preg->newline_anchor); for (i = 0; i < state->nodes.nelem; ++i) if (check_halt_node_context (dfa, state->nodes.elems[i], context)) return state->nodes.elems[i]; return 0; } /* Compute the next node to which "NFA" transit from NODE("NFA" is a NFA corresponding to the DFA). Return the destination node, and update EPS_VIA_NODES, return -1 in case of errors. */ static int proceed_next_node (preg, nregs, regs, mctx, pidx, node, eps_via_nodes, fs) const regex_t *preg; regmatch_t *regs; const re_match_context_t *mctx; int nregs, *pidx, node; re_node_set *eps_via_nodes; struct re_fail_stack_t *fs; { re_dfa_t *dfa = (re_dfa_t *)preg->buffer; int i, err, dest_node; dest_node = -1; if (IS_EPSILON_NODE (dfa->nodes[node].type)) { re_node_set *cur_nodes = &mctx->state_log[*pidx]->nodes; int ndest, dest_nodes[2]; err = re_node_set_insert (eps_via_nodes, node); if (BE (err < 0, 0)) return -1; /* Pick up valid destinations. */ for (ndest = 0, i = 0; i < dfa->edests[node].nelem; ++i) { int candidate = dfa->edests[node].elems[i]; if (!re_node_set_contains (cur_nodes, candidate)) continue; dest_nodes[0] = (ndest == 0) ? candidate : dest_nodes[0]; dest_nodes[1] = (ndest == 1) ? candidate : dest_nodes[1]; ++ndest; } if (ndest <= 1) return ndest == 0 ? -1 : (ndest == 1 ? dest_nodes[0] : 0); /* In order to avoid infinite loop like "(a*)*". */ if (re_node_set_contains (eps_via_nodes, dest_nodes[0])) return dest_nodes[1]; if (fs != NULL) push_fail_stack (fs, *pidx, dest_nodes, nregs, regs, eps_via_nodes); return dest_nodes[0]; } else { int naccepted = 0; re_token_type_t type = dfa->nodes[node].type; #ifdef RE_ENABLE_I18N if (ACCEPT_MB_NODE (type)) naccepted = check_node_accept_bytes (preg, node, mctx->input, *pidx); else #endif /* RE_ENABLE_I18N */ if (type == OP_BACK_REF) { int subexp_idx = dfa->nodes[node].opr.idx; naccepted = regs[subexp_idx].rm_eo - regs[subexp_idx].rm_so; if (fs != NULL) { if (regs[subexp_idx].rm_so == -1 || regs[subexp_idx].rm_eo == -1) return -1; else if (naccepted) { char *buf = (char *) re_string_get_buffer (mctx->input); if (memcmp (buf + regs[subexp_idx].rm_so, buf + *pidx, naccepted) != 0) return -1; } } if (naccepted == 0) { err = re_node_set_insert (eps_via_nodes, node); if (BE (err < 0, 0)) return -2; dest_node = dfa->edests[node].elems[0]; if (re_node_set_contains (&mctx->state_log[*pidx]->nodes, dest_node)) return dest_node; } } if (naccepted != 0 || check_node_accept (preg, dfa->nodes + node, mctx, *pidx)) { dest_node = dfa->nexts[node]; *pidx = (naccepted == 0) ? *pidx + 1 : *pidx + naccepted; if (fs && (*pidx > mctx->match_last || mctx->state_log[*pidx] == NULL || !re_node_set_contains (&mctx->state_log[*pidx]->nodes, dest_node))) return -1; re_node_set_empty (eps_via_nodes); return dest_node; } } return -1; } static reg_errcode_t push_fail_stack (fs, str_idx, dests, nregs, regs, eps_via_nodes) struct re_fail_stack_t *fs; int str_idx, *dests, nregs; regmatch_t *regs; re_node_set *eps_via_nodes; { reg_errcode_t err; int num = fs->num++; if (fs->num == fs->alloc) { struct re_fail_stack_ent_t *new_array; fs->alloc *= 2; new_array = realloc (fs->stack, (sizeof (struct re_fail_stack_ent_t) * fs->alloc)); if (new_array == NULL) return REG_ESPACE; fs->stack = new_array; } fs->stack[num].idx = str_idx; fs->stack[num].node = dests[1]; fs->stack[num].regs = re_malloc (regmatch_t, nregs); memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); return err; } static int pop_fail_stack (fs, pidx, nregs, regs, eps_via_nodes) struct re_fail_stack_t *fs; int *pidx, nregs; regmatch_t *regs; re_node_set *eps_via_nodes; { int num = --fs->num; assert (num >= 0); *pidx = fs->stack[num].idx; memcpy (regs, fs->stack[num].regs, sizeof (regmatch_t) * nregs); re_node_set_free (eps_via_nodes); re_free (fs->stack[num].regs); *eps_via_nodes = fs->stack[num].eps_via_nodes; return fs->stack[num].node; } /* Set the positions where the subexpressions are starts/ends to registers PMATCH. Note: We assume that pmatch[0] is already set, and pmatch[i].rm_so == pmatch[i].rm_eo == -1 (i > 1). */ static reg_errcode_t set_regs (preg, mctx, nmatch, pmatch, fl_backtrack) const regex_t *preg; const re_match_context_t *mctx; size_t nmatch; regmatch_t *pmatch; int fl_backtrack; { re_dfa_t *dfa = (re_dfa_t *)preg->buffer; int idx, cur_node, real_nmatch; re_node_set eps_via_nodes; struct re_fail_stack_t *fs; struct re_fail_stack_t fs_body = {0, 2, NULL}; #ifdef DEBUG assert (nmatch > 1); assert (mctx->state_log != NULL); #endif if (fl_backtrack) { fs = &fs_body; fs->stack = re_malloc (struct re_fail_stack_ent_t, fs->alloc); } else fs = NULL; cur_node = dfa->init_node; real_nmatch = (nmatch <= preg->re_nsub) ? nmatch : preg->re_nsub + 1; re_node_set_init_empty (&eps_via_nodes); for (idx = pmatch[0].rm_so; idx <= pmatch[0].rm_eo ;) { update_regs (dfa, pmatch, cur_node, idx, real_nmatch); if (idx == pmatch[0].rm_eo && cur_node == mctx->last_node) { int reg_idx; if (fs) { for (reg_idx = 0; reg_idx < nmatch; ++reg_idx) if (pmatch[reg_idx].rm_so > -1 && pmatch[reg_idx].rm_eo == -1) break; if (reg_idx == nmatch) { re_node_set_free (&eps_via_nodes); return free_fail_stack_return (fs); } cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, &eps_via_nodes); } else { re_node_set_free (&eps_via_nodes); return REG_NOERROR; } } /* Proceed to next node. */ cur_node = proceed_next_node (preg, nmatch, pmatch, mctx, &idx, cur_node, &eps_via_nodes, fs); if (BE (cur_node < 0, 0)) { if (cur_node == -2) return REG_ESPACE; if (fs) cur_node = pop_fail_stack (fs, &idx, nmatch, pmatch, &eps_via_nodes); else { re_node_set_free (&eps_via_nodes); return REG_NOMATCH; } } } re_node_set_free (&eps_via_nodes); return free_fail_stack_return (fs); } static reg_errcode_t free_fail_stack_return (fs) struct re_fail_stack_t *fs; { if (fs) { int fs_idx; for (fs_idx = 0; fs_idx < fs->num; ++fs_idx) { re_node_set_free (&fs->stack[fs_idx].eps_via_nodes); re_free (fs->stack[fs_idx].regs); } re_free (fs->stack); } return REG_NOERROR; } static void update_regs (dfa, pmatch, cur_node, cur_idx, nmatch) re_dfa_t *dfa; regmatch_t *pmatch; int cur_node, cur_idx, nmatch; { int type = dfa->nodes[cur_node].type; int reg_num; if (type != OP_OPEN_SUBEXP && type != OP_CLOSE_SUBEXP) return; reg_num = dfa->nodes[cur_node].opr.idx + 1; if (reg_num >= nmatch) return; if (type == OP_OPEN_SUBEXP) { /* We are at the first node of this sub expression. */ pmatch[reg_num].rm_so = cur_idx; pmatch[reg_num].rm_eo = -1; } else if (type == OP_CLOSE_SUBEXP) /* We are at the first node of this sub expression. */ pmatch[reg_num].rm_eo = cur_idx; } #define NUMBER_OF_STATE 1 /* This function checks the STATE_LOG from the SCTX->last_str_idx to 0 and sift the nodes in each states according to the following rules. Updated state_log will be wrote to STATE_LOG. Rules: We throw away the Node `a' in the STATE_LOG[STR_IDX] if... 1. When STR_IDX == MATCH_LAST(the last index in the state_log): If `a' isn't the LAST_NODE and `a' can't epsilon transit to the LAST_NODE, we throw away the node `a'. 2. When 0 <= STR_IDX < MATCH_LAST and `a' accepts string `s' and transit to `b': i. If 'b' isn't in the STATE_LOG[STR_IDX+strlen('s')], we throw away the node `a'. ii. If 'b' is in the STATE_LOG[STR_IDX+strlen('s')] but 'b' is throwed away, we throw away the node `a'. 3. When 0 <= STR_IDX < n and 'a' epsilon transit to 'b': i. If 'b' isn't in the STATE_LOG[STR_IDX], we throw away the node `a'. ii. If 'b' is in the STATE_LOG[STR_IDX] but 'b' is throwed away, we throw away the node `a'. */ #define STATE_NODE_CONTAINS(state,node) \ ((state) != NULL && re_node_set_contains (&(state)->nodes, node)) static reg_errcode_t sift_states_backward (preg, mctx, sctx) const regex_t *preg; re_match_context_t *mctx; re_sift_context_t *sctx; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *)preg->buffer; int null_cnt = 0; int str_idx = sctx->last_str_idx; re_node_set cur_dest; re_node_set *cur_src; /* Points the state_log[str_idx]->nodes */ #ifdef DEBUG assert (mctx->state_log != NULL && mctx->state_log[str_idx] != NULL); #endif cur_src = &mctx->state_log[str_idx]->nodes; /* Build sifted state_log[str_idx]. It has the nodes which can epsilon transit to the last_node and the last_node itself. */ err = re_node_set_init_1 (&cur_dest, sctx->last_node); if (BE (err != REG_NOERROR, 0)) return err; err = update_cur_sifted_state (preg, mctx, sctx, str_idx, &cur_dest); if (BE (err != REG_NOERROR, 0)) goto free_return; /* Then check each states in the state_log. */ while (str_idx > 0) { int i, ret; /* Update counters. */ null_cnt = (sctx->sifted_states[str_idx] == NULL) ? null_cnt + 1 : 0; if (null_cnt > mctx->max_mb_elem_len) { memset (sctx->sifted_states, '\0', sizeof (re_dfastate_t *) * str_idx); re_node_set_free (&cur_dest); return REG_NOERROR; } re_node_set_empty (&cur_dest); --str_idx; cur_src = ((mctx->state_log[str_idx] == NULL) ? &empty_set : &mctx->state_log[str_idx]->nodes); /* Then build the next sifted state. We build the next sifted state on `cur_dest', and update `sifted_states[str_idx]' with `cur_dest'. Note: `cur_dest' is the sifted state from `state_log[str_idx + 1]'. `cur_src' points the node_set of the old `state_log[str_idx]'. */ for (i = 0; i < cur_src->nelem; i++) { int prev_node = cur_src->elems[i]; int naccepted = 0; re_token_type_t type = dfa->nodes[prev_node].type; if (IS_EPSILON_NODE(type)) continue; #ifdef RE_ENABLE_I18N /* If the node may accept `multi byte'. */ if (ACCEPT_MB_NODE (type)) naccepted = sift_states_iter_mb (preg, mctx, sctx, prev_node, str_idx, sctx->last_str_idx); #endif /* RE_ENABLE_I18N */ /* We don't check backreferences here. See update_cur_sifted_state(). */ if (!naccepted && check_node_accept (preg, dfa->nodes + prev_node, mctx, str_idx) && STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + 1], dfa->nexts[prev_node])) naccepted = 1; if (naccepted == 0) continue; if (sctx->limits.nelem) { int to_idx = str_idx + naccepted; if (check_dst_limits (dfa, &sctx->limits, mctx, dfa->nexts[prev_node], to_idx, prev_node, str_idx)) continue; } ret = re_node_set_insert (&cur_dest, prev_node); if (BE (ret == -1, 0)) { err = REG_ESPACE; goto free_return; } } /* Add all the nodes which satisfy the following conditions: - It can epsilon transit to a node in CUR_DEST. - It is in CUR_SRC. And update state_log. */ err = update_cur_sifted_state (preg, mctx, sctx, str_idx, &cur_dest); if (BE (err != REG_NOERROR, 0)) goto free_return; } err = REG_NOERROR; free_return: re_node_set_free (&cur_dest); return err; } /* Helper functions. */ static inline reg_errcode_t clean_state_log_if_need (mctx, next_state_log_idx) re_match_context_t *mctx; int next_state_log_idx; { int top = mctx->state_log_top; if (next_state_log_idx >= mctx->input->bufs_len || (next_state_log_idx >= mctx->input->valid_len && mctx->input->valid_len < mctx->input->len)) { reg_errcode_t err; err = extend_buffers (mctx); if (BE (err != REG_NOERROR, 0)) return err; } if (top < next_state_log_idx) { memset (mctx->state_log + top + 1, '\0', sizeof (re_dfastate_t *) * (next_state_log_idx - top)); mctx->state_log_top = next_state_log_idx; } return REG_NOERROR; } static reg_errcode_t merge_state_array (dfa, dst, src, num) re_dfa_t *dfa; re_dfastate_t **dst; re_dfastate_t **src; int num; { int st_idx; reg_errcode_t err; for (st_idx = 0; st_idx < num; ++st_idx) { if (dst[st_idx] == NULL) dst[st_idx] = src[st_idx]; else if (src[st_idx] != NULL) { re_node_set merged_set; err = re_node_set_init_union (&merged_set, &dst[st_idx]->nodes, &src[st_idx]->nodes); if (BE (err != REG_NOERROR, 0)) return err; dst[st_idx] = re_acquire_state (&err, dfa, &merged_set); re_node_set_free (&merged_set); if (BE (err != REG_NOERROR, 0)) return err; } } return REG_NOERROR; } static reg_errcode_t update_cur_sifted_state (preg, mctx, sctx, str_idx, dest_nodes) const regex_t *preg; re_match_context_t *mctx; re_sift_context_t *sctx; int str_idx; re_node_set *dest_nodes; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *)preg->buffer; const re_node_set *candidates; candidates = ((mctx->state_log[str_idx] == NULL) ? &empty_set : &mctx->state_log[str_idx]->nodes); /* At first, add the nodes which can epsilon transit to a node in DEST_NODE. */ if (dest_nodes->nelem) { err = add_epsilon_src_nodes (dfa, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; } /* Then, check the limitations in the current sift_context. */ if (dest_nodes->nelem && sctx->limits.nelem) { err = check_subexp_limits (dfa, dest_nodes, candidates, &sctx->limits, mctx->bkref_ents, str_idx); if (BE (err != REG_NOERROR, 0)) return err; } /* Update state_log. */ sctx->sifted_states[str_idx] = re_acquire_state (&err, dfa, dest_nodes); if (BE (sctx->sifted_states[str_idx] == NULL && err != REG_NOERROR, 0)) return err; if ((mctx->state_log[str_idx] != NULL && mctx->state_log[str_idx]->has_backref)) { err = sift_states_bkref (preg, mctx, sctx, str_idx, dest_nodes); if (BE (err != REG_NOERROR, 0)) return err; } return REG_NOERROR; } static reg_errcode_t add_epsilon_src_nodes (dfa, dest_nodes, candidates) re_dfa_t *dfa; re_node_set *dest_nodes; const re_node_set *candidates; { reg_errcode_t err; int src_idx; re_node_set src_copy; err = re_node_set_init_copy (&src_copy, dest_nodes); if (BE (err != REG_NOERROR, 0)) return err; for (src_idx = 0; src_idx < src_copy.nelem; ++src_idx) { err = re_node_set_add_intersect (dest_nodes, candidates, dfa->inveclosures + src_copy.elems[src_idx]); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&src_copy); return err; } } re_node_set_free (&src_copy); return REG_NOERROR; } static reg_errcode_t sub_epsilon_src_nodes (dfa, node, dest_nodes, candidates) re_dfa_t *dfa; int node; re_node_set *dest_nodes; const re_node_set *candidates; { int ecl_idx; reg_errcode_t err; re_node_set *inv_eclosure = dfa->inveclosures + node; re_node_set except_nodes; re_node_set_init_empty (&except_nodes); for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) { int cur_node = inv_eclosure->elems[ecl_idx]; if (cur_node == node) continue; if (IS_EPSILON_NODE (dfa->nodes[cur_node].type)) { int edst1 = dfa->edests[cur_node].elems[0]; int edst2 = ((dfa->edests[cur_node].nelem > 1) ? dfa->edests[cur_node].elems[1] : -1); if ((!re_node_set_contains (inv_eclosure, edst1) && re_node_set_contains (dest_nodes, edst1)) || (edst2 > 0 && !re_node_set_contains (inv_eclosure, edst2) && re_node_set_contains (dest_nodes, edst2))) { err = re_node_set_add_intersect (&except_nodes, candidates, dfa->inveclosures + cur_node); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&except_nodes); return err; } } } } for (ecl_idx = 0; ecl_idx < inv_eclosure->nelem; ++ecl_idx) { int cur_node = inv_eclosure->elems[ecl_idx]; if (!re_node_set_contains (&except_nodes, cur_node)) { int idx = re_node_set_contains (dest_nodes, cur_node) - 1; re_node_set_remove_at (dest_nodes, idx); } } re_node_set_free (&except_nodes); return REG_NOERROR; } static int check_dst_limits (dfa, limits, mctx, dst_node, dst_idx, src_node, src_idx) re_dfa_t *dfa; re_node_set *limits; re_match_context_t *mctx; int dst_node, dst_idx, src_node, src_idx; { int lim_idx, src_pos, dst_pos; for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) { int subexp_idx; struct re_backref_cache_entry *ent; ent = mctx->bkref_ents + limits->elems[lim_idx]; subexp_idx = dfa->nodes[ent->node].opr.idx - 1; dst_pos = check_dst_limits_calc_pos (dfa, mctx, limits->elems[lim_idx], dfa->eclosures + dst_node, subexp_idx, dst_node, dst_idx); src_pos = check_dst_limits_calc_pos (dfa, mctx, limits->elems[lim_idx], dfa->eclosures + src_node, subexp_idx, src_node, src_idx); /* In case of: <src> <dst> ( <subexp> ) ( <subexp> ) <src> <dst> ( <subexp1> <src> <subexp2> <dst> <subexp3> ) */ if (src_pos == dst_pos) continue; /* This is unrelated limitation. */ else return 1; } return 0; } static int check_dst_limits_calc_pos (dfa, mctx, limit, eclosures, subexp_idx, node, str_idx) re_dfa_t *dfa; re_match_context_t *mctx; re_node_set *eclosures; int limit, subexp_idx, node, str_idx; { struct re_backref_cache_entry *lim = mctx->bkref_ents + limit; int pos = (str_idx < lim->subexp_from ? -1 : (lim->subexp_to < str_idx ? 1 : 0)); if (pos == 0 && (str_idx == lim->subexp_from || str_idx == lim->subexp_to)) { int node_idx; for (node_idx = 0; node_idx < eclosures->nelem; ++node_idx) { int node = eclosures->elems[node_idx]; re_token_type_t type= dfa->nodes[node].type; if (type == OP_BACK_REF) { int bi = search_cur_bkref_entry (mctx, str_idx); for (; bi < mctx->nbkref_ents; ++bi) { struct re_backref_cache_entry *ent = mctx->bkref_ents + bi; if (ent->str_idx > str_idx) break; if (ent->node == node && ent->subexp_from == ent->subexp_to) { int cpos, dst; dst = dfa->edests[node].elems[0]; cpos = check_dst_limits_calc_pos (dfa, mctx, limit, dfa->eclosures + dst, subexp_idx, dst, str_idx); if ((str_idx == lim->subexp_from && cpos == -1) || (str_idx == lim->subexp_to && cpos == 0)) return cpos; } } } if (type == OP_OPEN_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx && str_idx == lim->subexp_from) { pos = -1; break; } if (type == OP_CLOSE_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx && str_idx == lim->subexp_to) break; } if (node_idx == eclosures->nelem && str_idx == lim->subexp_to) pos = 1; } return pos; } /* Check the limitations of sub expressions LIMITS, and remove the nodes which are against limitations from DEST_NODES. */ static reg_errcode_t check_subexp_limits (dfa, dest_nodes, candidates, limits, bkref_ents, str_idx) re_dfa_t *dfa; re_node_set *dest_nodes; const re_node_set *candidates; re_node_set *limits; struct re_backref_cache_entry *bkref_ents; int str_idx; { reg_errcode_t err; int node_idx, lim_idx; for (lim_idx = 0; lim_idx < limits->nelem; ++lim_idx) { int subexp_idx; struct re_backref_cache_entry *ent; ent = bkref_ents + limits->elems[lim_idx]; if (str_idx <= ent->subexp_from || ent->str_idx < str_idx) continue; /* This is unrelated limitation. */ subexp_idx = dfa->nodes[ent->node].opr.idx - 1; if (ent->subexp_to == str_idx) { int ops_node = -1; int cls_node = -1; for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) { int node = dest_nodes->elems[node_idx]; re_token_type_t type= dfa->nodes[node].type; if (type == OP_OPEN_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx) ops_node = node; else if (type == OP_CLOSE_SUBEXP && subexp_idx == dfa->nodes[node].opr.idx) cls_node = node; } /* Check the limitation of the open subexpression. */ /* Note that (ent->subexp_to = str_idx != ent->subexp_from). */ if (ops_node >= 0) { err = sub_epsilon_src_nodes(dfa, ops_node, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; } /* Check the limitation of the close subexpression. */ for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) { int node = dest_nodes->elems[node_idx]; if (!re_node_set_contains (dfa->inveclosures + node, cls_node) && !re_node_set_contains (dfa->eclosures + node, cls_node)) { /* It is against this limitation. Remove it form the current sifted state. */ err = sub_epsilon_src_nodes(dfa, node, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; --node_idx; } } } else /* (ent->subexp_to != str_idx) */ { for (node_idx = 0; node_idx < dest_nodes->nelem; ++node_idx) { int node = dest_nodes->elems[node_idx]; re_token_type_t type= dfa->nodes[node].type; if (type == OP_CLOSE_SUBEXP || type == OP_OPEN_SUBEXP) { if (subexp_idx != dfa->nodes[node].opr.idx) continue; if ((type == OP_CLOSE_SUBEXP && ent->subexp_to != str_idx) || (type == OP_OPEN_SUBEXP)) { /* It is against this limitation. Remove it form the current sifted state. */ err = sub_epsilon_src_nodes(dfa, node, dest_nodes, candidates); if (BE (err != REG_NOERROR, 0)) return err; } } } } } return REG_NOERROR; } static reg_errcode_t sift_states_bkref (preg, mctx, sctx, str_idx, dest_nodes) const regex_t *preg; re_match_context_t *mctx; re_sift_context_t *sctx; int str_idx; re_node_set *dest_nodes; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *)preg->buffer; int node_idx, node; re_sift_context_t local_sctx; const re_node_set *candidates; candidates = ((mctx->state_log[str_idx] == NULL) ? &empty_set : &mctx->state_log[str_idx]->nodes); local_sctx.sifted_states = NULL; /* Mark that it hasn't been initialized. */ for (node_idx = 0; node_idx < candidates->nelem; ++node_idx) { int cur_bkref_idx = re_string_cur_idx (mctx->input); re_token_type_t type; node = candidates->elems[node_idx]; type = dfa->nodes[node].type; if (node == sctx->cur_bkref && str_idx == cur_bkref_idx) continue; /* Avoid infinite loop for the REs like "()\1+". */ if (node == sctx->last_node && str_idx == sctx->last_str_idx) continue; if (type == OP_BACK_REF) { int enabled_idx = search_cur_bkref_entry (mctx, str_idx); for (; enabled_idx < mctx->nbkref_ents; ++enabled_idx) { int disabled_idx, subexp_len, to_idx, dst_node; struct re_backref_cache_entry *entry; entry = mctx->bkref_ents + enabled_idx; if (entry->str_idx > str_idx) break; if (entry->node != node) continue; subexp_len = entry->subexp_to - entry->subexp_from; to_idx = str_idx + subexp_len; dst_node = (subexp_len ? dfa->nexts[node] : dfa->edests[node].elems[0]); if (to_idx > sctx->last_str_idx || sctx->sifted_states[to_idx] == NULL || !STATE_NODE_CONTAINS (sctx->sifted_states[to_idx], dst_node) || check_dst_limits (dfa, &sctx->limits, mctx, node, str_idx, dst_node, to_idx)) continue; { re_dfastate_t *cur_state; entry->flag = 0; for (disabled_idx = enabled_idx + 1; disabled_idx < mctx->nbkref_ents; ++disabled_idx) { struct re_backref_cache_entry *entry2; entry2 = mctx->bkref_ents + disabled_idx; if (entry2->str_idx > str_idx) break; entry2->flag = (entry2->node == node) ? 1 : entry2->flag; } if (local_sctx.sifted_states == NULL) { local_sctx = *sctx; err = re_node_set_init_copy (&local_sctx.limits, &sctx->limits); if (BE (err != REG_NOERROR, 0)) goto free_return; } local_sctx.last_node = node; local_sctx.last_str_idx = str_idx; err = re_node_set_insert (&local_sctx.limits, enabled_idx); if (BE (err < 0, 0)) { err = REG_ESPACE; goto free_return; } cur_state = local_sctx.sifted_states[str_idx]; err = sift_states_backward (preg, mctx, &local_sctx); if (BE (err != REG_NOERROR, 0)) goto free_return; if (sctx->limited_states != NULL) { err = merge_state_array (dfa, sctx->limited_states, local_sctx.sifted_states, str_idx + 1); if (BE (err != REG_NOERROR, 0)) goto free_return; } local_sctx.sifted_states[str_idx] = cur_state; re_node_set_remove (&local_sctx.limits, enabled_idx); /* We must not use the variable entry here, since mctx->bkref_ents might be realloced. */ mctx->bkref_ents[enabled_idx].flag = 1; } } enabled_idx = search_cur_bkref_entry (mctx, str_idx); for (; enabled_idx < mctx->nbkref_ents; ++enabled_idx) { struct re_backref_cache_entry *entry; entry = mctx->bkref_ents + enabled_idx; if (entry->str_idx > str_idx) break; if (entry->node == node) entry->flag = 0; } } } err = REG_NOERROR; free_return: if (local_sctx.sifted_states != NULL) { re_node_set_free (&local_sctx.limits); } return err; } #ifdef RE_ENABLE_I18N static int sift_states_iter_mb (preg, mctx, sctx, node_idx, str_idx, max_str_idx) const regex_t *preg; const re_match_context_t *mctx; re_sift_context_t *sctx; int node_idx, str_idx, max_str_idx; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int naccepted; /* Check the node can accept `multi byte'. */ naccepted = check_node_accept_bytes (preg, node_idx, mctx->input, str_idx); if (naccepted > 0 && str_idx + naccepted <= max_str_idx && !STATE_NODE_CONTAINS (sctx->sifted_states[str_idx + naccepted], dfa->nexts[node_idx])) /* The node can't accept the `multi byte', or the destination was already throwed away, then the node could't accept the current input `multi byte'. */ naccepted = 0; /* Otherwise, it is sure that the node could accept `naccepted' bytes input. */ return naccepted; } #endif /* RE_ENABLE_I18N */ /* Functions for state transition. */ /* Return the next state to which the current state STATE will transit by accepting the current input byte, and update STATE_LOG if necessary. If STATE can accept a multibyte char/collating element/back reference update the destination of STATE_LOG. */ static re_dfastate_t * transit_state (err, preg, mctx, state, fl_search) reg_errcode_t *err; const regex_t *preg; re_match_context_t *mctx; re_dfastate_t *state; int fl_search; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; re_dfastate_t **trtable, *next_state; unsigned char ch; int cur_idx; if (re_string_cur_idx (mctx->input) + 1 >= mctx->input->bufs_len || (re_string_cur_idx (mctx->input) + 1 >= mctx->input->valid_len && mctx->input->valid_len < mctx->input->len)) { *err = extend_buffers (mctx); if (BE (*err != REG_NOERROR, 0)) return NULL; } *err = REG_NOERROR; if (state == NULL) { next_state = state; re_string_skip_bytes (mctx->input, 1); } else { #ifdef RE_ENABLE_I18N /* If the current state can accept multibyte. */ if (state->accept_mb) { *err = transit_state_mb (preg, state, mctx); if (BE (*err != REG_NOERROR, 0)) return NULL; } #endif /* RE_ENABLE_I18N */ /* Then decide the next state with the single byte. */ if (1) { /* Use transition table */ ch = re_string_fetch_byte (mctx->input); trtable = fl_search ? state->trtable_search : state->trtable; if (trtable == NULL) { trtable = build_trtable (preg, state, fl_search); if (fl_search) state->trtable_search = trtable; else state->trtable = trtable; } next_state = trtable[ch]; } else { /* don't use transition table */ next_state = transit_state_sb (err, preg, state, fl_search, mctx); if (BE (next_state == NULL && err != REG_NOERROR, 0)) return NULL; } } cur_idx = re_string_cur_idx (mctx->input); /* Update the state_log if we need. */ if (mctx->state_log != NULL) { if (cur_idx > mctx->state_log_top) { mctx->state_log[cur_idx] = next_state; mctx->state_log_top = cur_idx; } else if (mctx->state_log[cur_idx] == 0) { mctx->state_log[cur_idx] = next_state; } else { re_dfastate_t *pstate; unsigned int context; re_node_set next_nodes, *log_nodes, *table_nodes = NULL; /* If (state_log[cur_idx] != 0), it implies that cur_idx is the destination of a multibyte char/collating element/ back reference. Then the next state is the union set of these destinations and the results of the transition table. */ pstate = mctx->state_log[cur_idx]; log_nodes = pstate->entrance_nodes; if (next_state != NULL) { table_nodes = next_state->entrance_nodes; *err = re_node_set_init_union (&next_nodes, table_nodes, log_nodes); if (BE (*err != REG_NOERROR, 0)) return NULL; } else next_nodes = *log_nodes; /* Note: We already add the nodes of the initial state, then we don't need to add them here. */ context = re_string_context_at (mctx->input, re_string_cur_idx (mctx->input) - 1, mctx->eflags, preg->newline_anchor); next_state = mctx->state_log[cur_idx] = re_acquire_state_context (err, dfa, &next_nodes, context); /* We don't need to check errors here, since the return value of this function is next_state and ERR is already set. */ if (table_nodes != NULL) re_node_set_free (&next_nodes); } } /* Check OP_OPEN_SUBEXP in the current state in case that we use them later. We must check them here, since the back references in the next state might use them. */ if (dfa->nbackref && next_state/* && fl_process_bkref */) { *err = check_subexp_matching_top (dfa, mctx, &next_state->nodes, cur_idx); if (BE (*err != REG_NOERROR, 0)) return NULL; } /* If the next state has back references. */ if (next_state != NULL && next_state->has_backref) { *err = transit_state_bkref (preg, &next_state->nodes, mctx); if (BE (*err != REG_NOERROR, 0)) return NULL; next_state = mctx->state_log[cur_idx]; } return next_state; } /* Helper functions for transit_state. */ /* From the node set CUR_NODES, pick up the nodes whose types are OP_OPEN_SUBEXP and which have corresponding back references in the regular expression. And register them to use them later for evaluating the correspoding back references. */ static reg_errcode_t check_subexp_matching_top (dfa, mctx, cur_nodes, str_idx) re_dfa_t *dfa; re_match_context_t *mctx; re_node_set *cur_nodes; int str_idx; { int node_idx; reg_errcode_t err; /* TODO: This isn't efficient. Because there might be more than one nodes whose types are OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all nodes. E.g. RE: (a){2} */ for (node_idx = 0; node_idx < cur_nodes->nelem; ++node_idx) { int node = cur_nodes->elems[node_idx]; if (dfa->nodes[node].type == OP_OPEN_SUBEXP && dfa->used_bkref_map & (1 << dfa->nodes[node].opr.idx)) { err = match_ctx_add_subtop (mctx, node, str_idx); if (BE (err != REG_NOERROR, 0)) return err; } } return REG_NOERROR; } /* Return the next state to which the current state STATE will transit by accepting the current input byte. */ static re_dfastate_t * transit_state_sb (err, preg, state, fl_search, mctx) reg_errcode_t *err; const regex_t *preg; re_dfastate_t *state; int fl_search; re_match_context_t *mctx; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; re_node_set next_nodes; re_dfastate_t *next_state; int node_cnt, cur_str_idx = re_string_cur_idx (mctx->input); unsigned int context; *err = re_node_set_alloc (&next_nodes, state->nodes.nelem + 1); if (BE (*err != REG_NOERROR, 0)) return NULL; for (node_cnt = 0; node_cnt < state->nodes.nelem; ++node_cnt) { int cur_node = state->nodes.elems[node_cnt]; if (check_node_accept (preg, dfa->nodes + cur_node, mctx, cur_str_idx)) { *err = re_node_set_merge (&next_nodes, dfa->eclosures + dfa->nexts[cur_node]); if (BE (*err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return NULL; } } } if (fl_search) { #ifdef RE_ENABLE_I18N int not_initial = 0; if (MB_CUR_MAX > 1) for (node_cnt = 0; node_cnt < next_nodes.nelem; ++node_cnt) if (dfa->nodes[next_nodes.elems[node_cnt]].type == CHARACTER) { not_initial = dfa->nodes[next_nodes.elems[node_cnt]].mb_partial; break; } if (!not_initial) #endif { *err = re_node_set_merge (&next_nodes, dfa->init_state->entrance_nodes); if (BE (*err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return NULL; } } } context = re_string_context_at (mctx->input, cur_str_idx, mctx->eflags, preg->newline_anchor); next_state = re_acquire_state_context (err, dfa, &next_nodes, context); /* We don't need to check errors here, since the return value of this function is next_state and ERR is already set. */ re_node_set_free (&next_nodes); re_string_skip_bytes (mctx->input, 1); return next_state; } #ifdef RE_ENABLE_I18N static reg_errcode_t transit_state_mb (preg, pstate, mctx) const regex_t *preg; re_dfastate_t *pstate; re_match_context_t *mctx; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int i; for (i = 0; i < pstate->nodes.nelem; ++i) { re_node_set dest_nodes, *new_nodes; int cur_node_idx = pstate->nodes.elems[i]; int naccepted = 0, dest_idx; unsigned int context; re_dfastate_t *dest_state; if (dfa->nodes[cur_node_idx].constraint) { context = re_string_context_at (mctx->input, re_string_cur_idx (mctx->input), mctx->eflags, preg->newline_anchor); if (NOT_SATISFY_NEXT_CONSTRAINT (dfa->nodes[cur_node_idx].constraint, context)) continue; } /* How many bytes the node can accepts? */ if (ACCEPT_MB_NODE (dfa->nodes[cur_node_idx].type)) naccepted = check_node_accept_bytes (preg, cur_node_idx, mctx->input, re_string_cur_idx (mctx->input)); if (naccepted == 0) continue; /* The node can accepts `naccepted' bytes. */ dest_idx = re_string_cur_idx (mctx->input) + naccepted; mctx->max_mb_elem_len = ((mctx->max_mb_elem_len < naccepted) ? naccepted : mctx->max_mb_elem_len); err = clean_state_log_if_need (mctx, dest_idx); if (BE (err != REG_NOERROR, 0)) return err; #ifdef DEBUG assert (dfa->nexts[cur_node_idx] != -1); #endif /* `cur_node_idx' may point the entity of the OP_CONTEXT_NODE, then we use pstate->nodes.elems[i] instead. */ new_nodes = dfa->eclosures + dfa->nexts[pstate->nodes.elems[i]]; dest_state = mctx->state_log[dest_idx]; if (dest_state == NULL) dest_nodes = *new_nodes; else { err = re_node_set_init_union (&dest_nodes, dest_state->entrance_nodes, new_nodes); if (BE (err != REG_NOERROR, 0)) return err; } context = re_string_context_at (mctx->input, dest_idx - 1, mctx->eflags, preg->newline_anchor); mctx->state_log[dest_idx] = re_acquire_state_context (&err, dfa, &dest_nodes, context); if (dest_state != NULL) re_node_set_free (&dest_nodes); if (BE (mctx->state_log[dest_idx] == NULL && err != REG_NOERROR, 0)) return err; } return REG_NOERROR; } #endif /* RE_ENABLE_I18N */ static reg_errcode_t transit_state_bkref (preg, nodes, mctx) const regex_t *preg; re_node_set *nodes; re_match_context_t *mctx; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int i; int cur_str_idx = re_string_cur_idx (mctx->input); for (i = 0; i < nodes->nelem; ++i) { int dest_str_idx, prev_nelem, bkc_idx; int node_idx = nodes->elems[i]; unsigned int context; re_token_t *node = dfa->nodes + node_idx; re_node_set *new_dest_nodes; /* Check whether `node' is a backreference or not. */ if (node->type != OP_BACK_REF) continue; if (node->constraint) { context = re_string_context_at (mctx->input, cur_str_idx, mctx->eflags, preg->newline_anchor); if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) continue; } /* `node' is a backreference. Check the substring which the substring matched. */ bkc_idx = mctx->nbkref_ents; err = get_subexp (preg, mctx, node_idx, cur_str_idx); if (BE (err != REG_NOERROR, 0)) goto free_return; /* And add the epsilon closures (which is `new_dest_nodes') of the backreference to appropriate state_log. */ #ifdef DEBUG assert (dfa->nexts[node_idx] != -1); #endif for (; bkc_idx < mctx->nbkref_ents; ++bkc_idx) { int subexp_len; re_dfastate_t *dest_state; struct re_backref_cache_entry *bkref_ent; bkref_ent = mctx->bkref_ents + bkc_idx; if (bkref_ent->node != node_idx || bkref_ent->str_idx != cur_str_idx) continue; subexp_len = bkref_ent->subexp_to - bkref_ent->subexp_from; new_dest_nodes = (subexp_len == 0 ? dfa->eclosures + dfa->edests[node_idx].elems[0] : dfa->eclosures + dfa->nexts[node_idx]); dest_str_idx = (cur_str_idx + bkref_ent->subexp_to - bkref_ent->subexp_from); context = re_string_context_at (mctx->input, dest_str_idx - 1, mctx->eflags, preg->newline_anchor); dest_state = mctx->state_log[dest_str_idx]; prev_nelem = ((mctx->state_log[cur_str_idx] == NULL) ? 0 : mctx->state_log[cur_str_idx]->nodes.nelem); /* Add `new_dest_node' to state_log. */ if (dest_state == NULL) { mctx->state_log[dest_str_idx] = re_acquire_state_context (&err, dfa, new_dest_nodes, context); if (BE (mctx->state_log[dest_str_idx] == NULL && err != REG_NOERROR, 0)) goto free_return; } else { re_node_set dest_nodes; err = re_node_set_init_union (&dest_nodes, dest_state->entrance_nodes, new_dest_nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&dest_nodes); goto free_return; } mctx->state_log[dest_str_idx] = re_acquire_state_context (&err, dfa, &dest_nodes, context); re_node_set_free (&dest_nodes); if (BE (mctx->state_log[dest_str_idx] == NULL && err != REG_NOERROR, 0)) goto free_return; } /* We need to check recursively if the backreference can epsilon transit. */ if (subexp_len == 0 && mctx->state_log[cur_str_idx]->nodes.nelem > prev_nelem) { err = check_subexp_matching_top (dfa, mctx, new_dest_nodes, cur_str_idx); if (BE (err != REG_NOERROR, 0)) goto free_return; err = transit_state_bkref (preg, new_dest_nodes, mctx); if (BE (err != REG_NOERROR, 0)) goto free_return; } } } err = REG_NOERROR; free_return: return err; } /* Enumerate all the candidates which the backreference BKREF_NODE can match at BKREF_STR_IDX, and register them by match_ctx_add_entry(). Note that we might collect inappropriate candidates here. However, the cost of checking them strictly here is too high, then we delay these checking for prune_impossible_nodes(). */ static reg_errcode_t get_subexp (preg, mctx, bkref_node, bkref_str_idx) const regex_t *preg; re_match_context_t *mctx; int bkref_node, bkref_str_idx; { int subexp_num, sub_top_idx; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; char *buf = (char *) re_string_get_buffer (mctx->input); /* Return if we have already checked BKREF_NODE at BKREF_STR_IDX. */ int cache_idx = search_cur_bkref_entry (mctx, bkref_str_idx); for (; cache_idx < mctx->nbkref_ents; ++cache_idx) { struct re_backref_cache_entry *entry = mctx->bkref_ents + cache_idx; if (entry->str_idx > bkref_str_idx) break; if (entry->node == bkref_node) return REG_NOERROR; /* We already checked it. */ } subexp_num = dfa->nodes[bkref_node].opr.idx - 1; /* For each sub expression */ for (sub_top_idx = 0; sub_top_idx < mctx->nsub_tops; ++sub_top_idx) { reg_errcode_t err; re_sub_match_top_t *sub_top = mctx->sub_tops[sub_top_idx]; re_sub_match_last_t *sub_last; int sub_last_idx, sl_str; char *bkref_str; if (dfa->nodes[sub_top->node].opr.idx != subexp_num) continue; /* It isn't related. */ sl_str = sub_top->str_idx; bkref_str = buf + bkref_str_idx; /* At first, check the last node of sub expressions we already evaluated. */ for (sub_last_idx = 0; sub_last_idx < sub_top->nlasts; ++sub_last_idx) { int sl_str_diff; sub_last = sub_top->lasts[sub_last_idx]; sl_str_diff = sub_last->str_idx - sl_str; /* The matched string by the sub expression match with the substring at the back reference? */ if (sl_str_diff > 0 && memcmp (bkref_str, buf + sl_str, sl_str_diff) != 0) break; /* We don't need to search this sub expression any more. */ bkref_str += sl_str_diff; sl_str += sl_str_diff; err = get_subexp_sub (preg, mctx, sub_top, sub_last, bkref_node, bkref_str_idx); if (err == REG_NOMATCH) continue; if (BE (err != REG_NOERROR, 0)) return err; } if (sub_last_idx < sub_top->nlasts) continue; if (sub_last_idx > 0) ++sl_str; /* Then, search for the other last nodes of the sub expression. */ for (; sl_str <= bkref_str_idx; ++sl_str) { int cls_node, sl_str_off; re_node_set *nodes; sl_str_off = sl_str - sub_top->str_idx; /* The matched string by the sub expression match with the substring at the back reference? */ if (sl_str_off > 0 && memcmp (bkref_str++, buf + sl_str - 1, 1) != 0) break; /* We don't need to search this sub expression any more. */ if (mctx->state_log[sl_str] == NULL) continue; /* Does this state have a ')' of the sub expression? */ nodes = &mctx->state_log[sl_str]->nodes; cls_node = find_subexp_node (dfa, nodes, subexp_num, 0); if (cls_node == -1) continue; /* No. */ if (sub_top->path == NULL) { sub_top->path = calloc (sizeof (state_array_t), sl_str - sub_top->str_idx + 1); if (sub_top->path == NULL) return REG_ESPACE; } /* Can the OP_OPEN_SUBEXP node arrive the OP_CLOSE_SUBEXP node in the current context? */ err = check_arrival (preg, mctx, sub_top->path, sub_top->node, sub_top->str_idx, cls_node, sl_str, 0); if (err == REG_NOMATCH) continue; if (BE (err != REG_NOERROR, 0)) return err; sub_last = match_ctx_add_sublast (sub_top, cls_node, sl_str); if (BE (sub_last == NULL, 0)) return REG_ESPACE; err = get_subexp_sub (preg, mctx, sub_top, sub_last, bkref_node, bkref_str_idx); if (err == REG_NOMATCH) continue; } } return REG_NOERROR; } /* Helper functions for get_subexp(). */ /* Check SUB_LAST can arrive to the back reference BKREF_NODE at BKREF_STR. If it can arrive, register the sub expression expressed with SUB_TOP and SUB_LAST. */ static reg_errcode_t get_subexp_sub (preg, mctx, sub_top, sub_last, bkref_node, bkref_str) const regex_t *preg; re_match_context_t *mctx; re_sub_match_top_t *sub_top; re_sub_match_last_t *sub_last; int bkref_node, bkref_str; { reg_errcode_t err; int to_idx; /* Can the subexpression arrive the back reference? */ err = check_arrival (preg, mctx, &sub_last->path, sub_last->node, sub_last->str_idx, bkref_node, bkref_str, 1); if (err != REG_NOERROR) return err; err = match_ctx_add_entry (mctx, bkref_node, bkref_str, sub_top->str_idx, sub_last->str_idx); if (BE (err != REG_NOERROR, 0)) return err; to_idx = bkref_str + sub_last->str_idx - sub_top->str_idx; clean_state_log_if_need (mctx, to_idx); return REG_NOERROR; } /* Find the first node which is '(' or ')' and whose index is SUBEXP_IDX. Search '(' if FL_OPEN, or search ')' otherwise. TODO: This function isn't efficient... Because there might be more than one nodes whose types are OP_OPEN_SUBEXP and whose index is SUBEXP_IDX, we must check all nodes. E.g. RE: (a){2} */ static int find_subexp_node (dfa, nodes, subexp_idx, fl_open) re_dfa_t *dfa; re_node_set *nodes; int subexp_idx, fl_open; { int cls_idx; for (cls_idx = 0; cls_idx < nodes->nelem; ++cls_idx) { int cls_node = nodes->elems[cls_idx]; re_token_t *node = dfa->nodes + cls_node; if (((fl_open && node->type == OP_OPEN_SUBEXP) || (!fl_open && node->type == OP_CLOSE_SUBEXP)) && node->opr.idx == subexp_idx) return cls_node; } return -1; } /* Check whether the node TOP_NODE at TOP_STR can arrive to the node LAST_NODE at LAST_STR. We record the path onto PATH since it will be heavily reused. Return REG_NOERROR if it can arrive, or REG_NOMATCH otherwise. */ static reg_errcode_t check_arrival (preg, mctx, path, top_node, top_str, last_node, last_str, fl_open) const regex_t *preg; re_match_context_t *mctx; state_array_t *path; int top_node, top_str, last_node, last_str, fl_open; { re_dfa_t *dfa = (re_dfa_t *) preg->buffer; reg_errcode_t err; int subexp_num, backup_cur_idx, str_idx, null_cnt; re_dfastate_t *cur_state = NULL; re_node_set *cur_nodes, next_nodes; re_dfastate_t **backup_state_log; unsigned int context; subexp_num = dfa->nodes[top_node].opr.idx; /* Extend the buffer if we need. */ if (path->alloc < last_str + mctx->max_mb_elem_len + 1) { re_dfastate_t **new_array; int old_alloc = path->alloc; path->alloc += last_str + mctx->max_mb_elem_len + 1; new_array = re_realloc (path->array, re_dfastate_t *, path->alloc); if (new_array == NULL) return REG_ESPACE; path->array = new_array; memset (new_array + old_alloc, '\0', sizeof (re_dfastate_t *) * (path->alloc - old_alloc)); } str_idx = path->next_idx == 0 ? top_str : path->next_idx; /* Temporary modify MCTX. */ backup_state_log = mctx->state_log; backup_cur_idx = mctx->input->cur_idx; mctx->state_log = path->array; mctx->input->cur_idx = str_idx; /* Setup initial node set. */ context = re_string_context_at (mctx->input, str_idx - 1, mctx->eflags, preg->newline_anchor); if (str_idx == top_str) { err = re_node_set_init_1 (&next_nodes, top_node); if (BE (err != REG_NOERROR, 0)) return err; err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, fl_open); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } else { cur_state = mctx->state_log[str_idx]; if (cur_state && cur_state->has_backref) { err = re_node_set_init_copy (&next_nodes, &cur_state->nodes); if (BE ( err != REG_NOERROR, 0)) return err; } else re_node_set_init_empty (&next_nodes); } if (str_idx == top_str || (cur_state && cur_state->has_backref)) { if (next_nodes.nelem) { err = expand_bkref_cache (preg, mctx, &next_nodes, str_idx, last_str, subexp_num, fl_open); if (BE ( err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); if (BE (cur_state == NULL && err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } mctx->state_log[str_idx] = cur_state; } for (null_cnt = 0; str_idx < last_str && null_cnt <= mctx->max_mb_elem_len;) { re_node_set_empty (&next_nodes); if (mctx->state_log[str_idx + 1]) { err = re_node_set_merge (&next_nodes, &mctx->state_log[str_idx + 1]->nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } if (cur_state) { err = check_arrival_add_next_nodes(preg, dfa, mctx, str_idx, &cur_state->nodes, &next_nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } ++str_idx; if (next_nodes.nelem) { err = check_arrival_expand_ecl (dfa, &next_nodes, subexp_num, fl_open); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } err = expand_bkref_cache (preg, mctx, &next_nodes, str_idx, last_str, subexp_num, fl_open); if (BE ( err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } } context = re_string_context_at (mctx->input, str_idx - 1, mctx->eflags, preg->newline_anchor); cur_state = re_acquire_state_context (&err, dfa, &next_nodes, context); if (BE (cur_state == NULL && err != REG_NOERROR, 0)) { re_node_set_free (&next_nodes); return err; } mctx->state_log[str_idx] = cur_state; null_cnt = cur_state == NULL ? null_cnt + 1 : 0; } re_node_set_free (&next_nodes); cur_nodes = (mctx->state_log[last_str] == NULL ? NULL : &mctx->state_log[last_str]->nodes); path->next_idx = str_idx; /* Fix MCTX. */ mctx->state_log = backup_state_log; mctx->input->cur_idx = backup_cur_idx; if (cur_nodes == NULL) return REG_NOMATCH; /* Then check the current node set has the node LAST_NODE. */ return (re_node_set_contains (cur_nodes, last_node) || re_node_set_contains (cur_nodes, last_node) ? REG_NOERROR : REG_NOMATCH); } /* Helper functions for check_arrival. */ /* Calculate the destination nodes of CUR_NODES at STR_IDX, and append them to NEXT_NODES. TODO: This function is similar to the functions transit_state*(), however this function has many additional works. Can't we unify them? */ static reg_errcode_t check_arrival_add_next_nodes (preg, dfa, mctx, str_idx, cur_nodes, next_nodes) const regex_t *preg; re_dfa_t *dfa; re_match_context_t *mctx; int str_idx; re_node_set *cur_nodes, *next_nodes; { int cur_idx; reg_errcode_t err; re_node_set union_set; re_node_set_init_empty (&union_set); for (cur_idx = 0; cur_idx < cur_nodes->nelem; ++cur_idx) { int naccepted = 0; int cur_node = cur_nodes->elems[cur_idx]; re_token_type_t type = dfa->nodes[cur_node].type; if (IS_EPSILON_NODE(type)) continue; #ifdef RE_ENABLE_I18N /* If the node may accept `multi byte'. */ if (ACCEPT_MB_NODE (type)) { naccepted = check_node_accept_bytes (preg, cur_node, mctx->input, str_idx); if (naccepted > 1) { re_dfastate_t *dest_state; int next_node = dfa->nexts[cur_node]; int next_idx = str_idx + naccepted; dest_state = mctx->state_log[next_idx]; re_node_set_empty (&union_set); if (dest_state) { err = re_node_set_merge (&union_set, &dest_state->nodes); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&union_set); return err; } err = re_node_set_insert (&union_set, next_node); if (BE (err < 0, 0)) { re_node_set_free (&union_set); return REG_ESPACE; } } else { err = re_node_set_insert (&union_set, next_node); if (BE (err < 0, 0)) { re_node_set_free (&union_set); return REG_ESPACE; } } mctx->state_log[next_idx] = re_acquire_state (&err, dfa, &union_set); if (BE (mctx->state_log[next_idx] == NULL && err != REG_NOERROR, 0)) { re_node_set_free (&union_set); return err; } } } #endif /* RE_ENABLE_I18N */ if (naccepted || check_node_accept (preg, dfa->nodes + cur_node, mctx, str_idx)) { err = re_node_set_insert (next_nodes, dfa->nexts[cur_node]); if (BE (err < 0, 0)) { re_node_set_free (&union_set); return REG_ESPACE; } } } re_node_set_free (&union_set); return REG_NOERROR; } /* For all the nodes in CUR_NODES, add the epsilon closures of them to CUR_NODES, however exclude the nodes which are: - inside the sub expression whose number is EX_SUBEXP, if FL_OPEN. - out of the sub expression whose number is EX_SUBEXP, if !FL_OPEN. */ static reg_errcode_t check_arrival_expand_ecl (dfa, cur_nodes, ex_subexp, fl_open) re_dfa_t *dfa; re_node_set *cur_nodes; int ex_subexp, fl_open; { reg_errcode_t err; int idx, outside_node; re_node_set new_nodes; #ifdef DEBUG assert (cur_nodes->nelem); #endif err = re_node_set_alloc (&new_nodes, cur_nodes->nelem); if (BE (err != REG_NOERROR, 0)) return err; /* Create a new node set NEW_NODES with the nodes which are epsilon closures of the node in CUR_NODES. */ for (idx = 0; idx < cur_nodes->nelem; ++idx) { int cur_node = cur_nodes->elems[idx]; re_node_set *eclosure = dfa->eclosures + cur_node; outside_node = find_subexp_node (dfa, eclosure, ex_subexp, fl_open); if (outside_node == -1) { /* There are no problematic nodes, just merge them. */ err = re_node_set_merge (&new_nodes, eclosure); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&new_nodes); return err; } } else { /* There are problematic nodes, re-calculate incrementally. */ err = check_arrival_expand_ecl_sub (dfa, &new_nodes, cur_node, ex_subexp, fl_open); if (BE (err != REG_NOERROR, 0)) { re_node_set_free (&new_nodes); return err; } } } re_node_set_free (cur_nodes); *cur_nodes = new_nodes; return REG_NOERROR; } /* Helper function for check_arrival_expand_ecl. Check incrementally the epsilon closure of TARGET, and if it isn't problematic append it to DST_NODES. */ static reg_errcode_t check_arrival_expand_ecl_sub (dfa, dst_nodes, target, ex_subexp, fl_open) re_dfa_t *dfa; int target, ex_subexp, fl_open; re_node_set *dst_nodes; { int cur_node, type; for (cur_node = target; !re_node_set_contains (dst_nodes, cur_node);) { int err; type = dfa->nodes[cur_node].type; if (((type == OP_OPEN_SUBEXP && fl_open) || (type == OP_CLOSE_SUBEXP && !fl_open)) && dfa->nodes[cur_node].opr.idx == ex_subexp) { if (!fl_open) { err = re_node_set_insert (dst_nodes, cur_node); if (BE (err == -1, 0)) return REG_ESPACE; } break; } err = re_node_set_insert (dst_nodes, cur_node); if (BE (err == -1, 0)) return REG_ESPACE; if (dfa->edests[cur_node].nelem == 0) break; if (dfa->edests[cur_node].nelem == 2) { err = check_arrival_expand_ecl_sub (dfa, dst_nodes, dfa->edests[cur_node].elems[1], ex_subexp, fl_open); if (BE (err != REG_NOERROR, 0)) return err; } cur_node = dfa->edests[cur_node].elems[0]; } return REG_NOERROR; } /* For all the back references in the current state, calculate the destination of the back references by the appropriate entry in MCTX->BKREF_ENTS. */ static reg_errcode_t expand_bkref_cache (preg, mctx, cur_nodes, cur_str, last_str, subexp_num, fl_open) const regex_t *preg; re_match_context_t *mctx; int cur_str, last_str, subexp_num, fl_open; re_node_set *cur_nodes; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int cache_idx, cache_idx_start; /* The current state. */ cache_idx_start = search_cur_bkref_entry (mctx, cur_str); for (cache_idx = cache_idx_start; cache_idx < mctx->nbkref_ents; ++cache_idx) { int to_idx, next_node; struct re_backref_cache_entry *ent = mctx->bkref_ents + cache_idx; if (ent->str_idx > cur_str) break; /* Is this entry ENT is appropriate? */ if (!re_node_set_contains (cur_nodes, ent->node)) continue; /* No. */ to_idx = cur_str + ent->subexp_to - ent->subexp_from; /* Calculate the destination of the back reference, and append it to MCTX->STATE_LOG. */ if (to_idx == cur_str) { /* The backreference did epsilon transit, we must re-check all the node in the current state. */ re_node_set new_dests; reg_errcode_t err2, err3; next_node = dfa->edests[ent->node].elems[0]; if (re_node_set_contains (cur_nodes, next_node)) continue; err = re_node_set_init_1 (&new_dests, next_node); err2 = check_arrival_expand_ecl (dfa, &new_dests, subexp_num, fl_open); err3 = re_node_set_merge (cur_nodes, &new_dests); re_node_set_free (&new_dests); if (BE (err != REG_NOERROR || err2 != REG_NOERROR || err3 != REG_NOERROR, 0)) { err = (err != REG_NOERROR ? err : (err2 != REG_NOERROR ? err2 : err3)); return err; } /* TODO: It is still inefficient... */ cache_idx = cache_idx_start - 1; continue; } else { re_node_set union_set; next_node = dfa->nexts[ent->node]; if (mctx->state_log[to_idx]) { int ret; if (re_node_set_contains (&mctx->state_log[to_idx]->nodes, next_node)) continue; err = re_node_set_init_copy (&union_set, &mctx->state_log[to_idx]->nodes); ret = re_node_set_insert (&union_set, next_node); if (BE (err != REG_NOERROR || ret < 0, 0)) { re_node_set_free (&union_set); err = err != REG_NOERROR ? err : REG_ESPACE; return err; } } else { err = re_node_set_init_1 (&union_set, next_node); if (BE (err != REG_NOERROR, 0)) return err; } mctx->state_log[to_idx] = re_acquire_state (&err, dfa, &union_set); re_node_set_free (&union_set); if (BE (mctx->state_log[to_idx] == NULL && err != REG_NOERROR, 0)) return err; } } return REG_NOERROR; } /* Build transition table for the state. Return the new table if succeeded, otherwise return NULL. */ static re_dfastate_t ** build_trtable (preg, state, fl_search) const regex_t *preg; const re_dfastate_t *state; int fl_search; { reg_errcode_t err; re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int i, j, k, ch; int dests_node_malloced = 0, dest_states_malloced = 0; int ndests; /* Number of the destination states from `state'. */ re_dfastate_t **trtable; re_dfastate_t **dest_states = NULL, **dest_states_word, **dest_states_nl; re_node_set follows, *dests_node; bitset *dests_ch; bitset acceptable; /* We build DFA states which corresponds to the destination nodes from `state'. `dests_node[i]' represents the nodes which i-th destination state contains, and `dests_ch[i]' represents the characters which i-th destination state accepts. */ #ifdef _LIBC if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX)) dests_node = (re_node_set *) alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX); else #endif { dests_node = (re_node_set *) malloc ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX); if (BE (dests_node == NULL, 0)) return NULL; dests_node_malloced = 1; } dests_ch = (bitset *) (dests_node + SBC_MAX); /* Initialize transiton table. */ trtable = (re_dfastate_t **) calloc (sizeof (re_dfastate_t *), SBC_MAX); if (BE (trtable == NULL, 0)) { if (dests_node_malloced) free (dests_node); return NULL; } /* At first, group all nodes belonging to `state' into several destinations. */ ndests = group_nodes_into_DFAstates (preg, state, dests_node, dests_ch); if (BE (ndests <= 0, 0)) { if (dests_node_malloced) free (dests_node); /* Return NULL in case of an error, trtable otherwise. */ if (ndests == 0) return trtable; free (trtable); return NULL; } err = re_node_set_alloc (&follows, ndests + 1); if (BE (err != REG_NOERROR, 0)) goto out_free; #ifdef _LIBC if (__libc_use_alloca ((sizeof (re_node_set) + sizeof (bitset)) * SBC_MAX + ndests * 3 * sizeof (re_dfastate_t *))) dest_states = (re_dfastate_t **) alloca (ndests * 3 * sizeof (re_dfastate_t *)); else #endif { dest_states = (re_dfastate_t **) malloc (ndests * 3 * sizeof (re_dfastate_t *)); if (BE (dest_states == NULL, 0)) { out_free: if (dest_states_malloced) free (dest_states); re_node_set_free (&follows); for (i = 0; i < ndests; ++i) re_node_set_free (dests_node + i); free (trtable); if (dests_node_malloced) free (dests_node); return NULL; } dest_states_malloced = 1; } dest_states_word = dest_states + ndests; dest_states_nl = dest_states_word + ndests; bitset_empty (acceptable); /* Then build the states for all destinations. */ for (i = 0; i < ndests; ++i) { int next_node; re_node_set_empty (&follows); /* Merge the follows of this destination states. */ for (j = 0; j < dests_node[i].nelem; ++j) { next_node = dfa->nexts[dests_node[i].elems[j]]; if (next_node != -1) { err = re_node_set_merge (&follows, dfa->eclosures + next_node); if (BE (err != REG_NOERROR, 0)) goto out_free; } } /* If search flag is set, merge the initial state. */ if (fl_search) { #ifdef RE_ENABLE_I18N int not_initial = 0; for (j = 0; j < follows.nelem; ++j) if (dfa->nodes[follows.elems[j]].type == CHARACTER) { not_initial = dfa->nodes[follows.elems[j]].mb_partial; break; } if (!not_initial) #endif { err = re_node_set_merge (&follows, dfa->init_state->entrance_nodes); if (BE (err != REG_NOERROR, 0)) goto out_free; } } dest_states[i] = re_acquire_state_context (&err, dfa, &follows, 0); if (BE (dest_states[i] == NULL && err != REG_NOERROR, 0)) goto out_free; /* If the new state has context constraint, build appropriate states for these contexts. */ if (dest_states[i]->has_constraint) { dest_states_word[i] = re_acquire_state_context (&err, dfa, &follows, CONTEXT_WORD); if (BE (dest_states_word[i] == NULL && err != REG_NOERROR, 0)) goto out_free; dest_states_nl[i] = re_acquire_state_context (&err, dfa, &follows, CONTEXT_NEWLINE); if (BE (dest_states_nl[i] == NULL && err != REG_NOERROR, 0)) goto out_free; } else { dest_states_word[i] = dest_states[i]; dest_states_nl[i] = dest_states[i]; } bitset_merge (acceptable, dests_ch[i]); } /* Update the transition table. */ /* For all characters ch...: */ for (i = 0, ch = 0; i < BITSET_UINTS; ++i) for (j = 0; j < UINT_BITS; ++j, ++ch) if ((acceptable[i] >> j) & 1) { /* The current state accepts the character ch. */ if (IS_WORD_CHAR (ch)) { for (k = 0; k < ndests; ++k) if ((dests_ch[k][i] >> j) & 1) { /* k-th destination accepts the word character ch. */ trtable[ch] = dest_states_word[k]; /* There must be only one destination which accepts character ch. See group_nodes_into_DFAstates. */ break; } } else /* not WORD_CHAR */ { for (k = 0; k < ndests; ++k) if ((dests_ch[k][i] >> j) & 1) { /* k-th destination accepts the non-word character ch. */ trtable[ch] = dest_states[k]; /* There must be only one destination which accepts character ch. See group_nodes_into_DFAstates. */ break; } } } /* new line */ if (bitset_contain (acceptable, NEWLINE_CHAR)) { /* The current state accepts newline character. */ for (k = 0; k < ndests; ++k) if (bitset_contain (dests_ch[k], NEWLINE_CHAR)) { /* k-th destination accepts newline character. */ trtable[NEWLINE_CHAR] = dest_states_nl[k]; /* There must be only one destination which accepts newline. See group_nodes_into_DFAstates. */ break; } } if (dest_states_malloced) free (dest_states); re_node_set_free (&follows); for (i = 0; i < ndests; ++i) re_node_set_free (dests_node + i); if (dests_node_malloced) free (dests_node); return trtable; } /* Group all nodes belonging to STATE into several destinations. Then for all destinations, set the nodes belonging to the destination to DESTS_NODE[i] and set the characters accepted by the destination to DEST_CH[i]. This function return the number of destinations. */ static int group_nodes_into_DFAstates (preg, state, dests_node, dests_ch) const regex_t *preg; const re_dfastate_t *state; re_node_set *dests_node; bitset *dests_ch; { reg_errcode_t err; const re_dfa_t *dfa = (re_dfa_t *) preg->buffer; int i, j, k; int ndests; /* Number of the destinations from `state'. */ bitset accepts; /* Characters a node can accept. */ const re_node_set *cur_nodes = &state->nodes; bitset_empty (accepts); ndests = 0; /* For all the nodes belonging to `state', */ for (i = 0; i < cur_nodes->nelem; ++i) { re_token_t *node = &dfa->nodes[cur_nodes->elems[i]]; re_token_type_t type = node->type; unsigned int constraint = node->constraint; /* Enumerate all single byte character this node can accept. */ if (type == CHARACTER) bitset_set (accepts, node->opr.c); else if (type == SIMPLE_BRACKET) { bitset_merge (accepts, node->opr.sbcset); } else if (type == OP_PERIOD) { bitset_set_all (accepts); if (!(preg->syntax & RE_DOT_NEWLINE)) bitset_clear (accepts, '\n'); if (preg->syntax & RE_DOT_NOT_NULL) bitset_clear (accepts, '\0'); } else continue; /* Check the `accepts' and sift the characters which are not match it the context. */ if (constraint) { if (constraint & NEXT_WORD_CONSTRAINT) for (j = 0; j < BITSET_UINTS; ++j) accepts[j] &= dfa->word_char[j]; if (constraint & NEXT_NOTWORD_CONSTRAINT) for (j = 0; j < BITSET_UINTS; ++j) accepts[j] &= ~dfa->word_char[j]; if (constraint & NEXT_NEWLINE_CONSTRAINT) { int accepts_newline = bitset_contain (accepts, NEWLINE_CHAR); bitset_empty (accepts); if (accepts_newline) bitset_set (accepts, NEWLINE_CHAR); else continue; } } /* Then divide `accepts' into DFA states, or create a new state. */ for (j = 0; j < ndests; ++j) { bitset intersec; /* Intersection sets, see below. */ bitset remains; /* Flags, see below. */ int has_intersec, not_subset, not_consumed; /* Optimization, skip if this state doesn't accept the character. */ if (type == CHARACTER && !bitset_contain (dests_ch[j], node->opr.c)) continue; /* Enumerate the intersection set of this state and `accepts'. */ has_intersec = 0; for (k = 0; k < BITSET_UINTS; ++k) has_intersec |= intersec[k] = accepts[k] & dests_ch[j][k]; /* And skip if the intersection set is empty. */ if (!has_intersec) continue; /* Then check if this state is a subset of `accepts'. */ not_subset = not_consumed = 0; for (k = 0; k < BITSET_UINTS; ++k) { not_subset |= remains[k] = ~accepts[k] & dests_ch[j][k]; not_consumed |= accepts[k] = accepts[k] & ~dests_ch[j][k]; } /* If this state isn't a subset of `accepts', create a new group state, which has the `remains'. */ if (not_subset) { bitset_copy (dests_ch[ndests], remains); bitset_copy (dests_ch[j], intersec); err = re_node_set_init_copy (dests_node + ndests, &dests_node[j]); if (BE (err != REG_NOERROR, 0)) goto error_return; ++ndests; } /* Put the position in the current group. */ err = re_node_set_insert (&dests_node[j], cur_nodes->elems[i]); if (BE (err < 0, 0)) goto error_return; /* If all characters are consumed, go to next node. */ if (!not_consumed) break; } /* Some characters remain, create a new group. */ if (j == ndests) { bitset_copy (dests_ch[ndests], accepts); err = re_node_set_init_1 (dests_node + ndests, cur_nodes->elems[i]); if (BE (err != REG_NOERROR, 0)) goto error_return; ++ndests; bitset_empty (accepts); } } return ndests; error_return: for (j = 0; j < ndests; ++j) re_node_set_free (dests_node + j); return -1; } #ifdef RE_ENABLE_I18N /* Check how many bytes the node `dfa->nodes[node_idx]' accepts. Return the number of the bytes the node accepts. STR_IDX is the current index of the input string. This function handles the nodes which can accept one character, or one collating element like '.', '[a-z]', opposite to the other nodes can only accept one byte. */ static int check_node_accept_bytes (preg, node_idx, input, str_idx) const regex_t *preg; int node_idx, str_idx; const re_string_t *input; { const re_dfa_t *dfa = (re_dfa_t *) preg->buffer; const re_token_t *node = dfa->nodes + node_idx; int elem_len = re_string_elem_size_at (input, str_idx); int char_len = re_string_char_size_at (input, str_idx); int i; # ifdef _LIBC int j; uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); # endif /* _LIBC */ if (elem_len <= 1 && char_len <= 1) return 0; if (node->type == OP_PERIOD) { /* '.' accepts any one character except the following two cases. */ if ((!(preg->syntax & RE_DOT_NEWLINE) && re_string_byte_at (input, str_idx) == '\n') || ((preg->syntax & RE_DOT_NOT_NULL) && re_string_byte_at (input, str_idx) == '\0')) return 0; return char_len; } else if (node->type == COMPLEX_BRACKET) { const re_charset_t *cset = node->opr.mbcset; # ifdef _LIBC const unsigned char *pin = ((char *) re_string_get_buffer (input) + str_idx); # endif /* _LIBC */ int match_len = 0; wchar_t wc = ((cset->nranges || cset->nchar_classes || cset->nmbchars) ? re_string_wchar_at (input, str_idx) : 0); /* match with multibyte character? */ for (i = 0; i < cset->nmbchars; ++i) if (wc == cset->mbchars[i]) { match_len = char_len; goto check_node_accept_bytes_match; } /* match with character_class? */ for (i = 0; i < cset->nchar_classes; ++i) { wctype_t wt = cset->char_classes[i]; if (__iswctype (wc, wt)) { match_len = char_len; goto check_node_accept_bytes_match; } } # ifdef _LIBC if (nrules != 0) { unsigned int in_collseq = 0; const int32_t *table, *indirect; const unsigned char *weights, *extra; const char *collseqwc; int32_t idx; /* This #include defines a local function! */ # include <locale/weight.h> /* match with collating_symbol? */ if (cset->ncoll_syms) extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); for (i = 0; i < cset->ncoll_syms; ++i) { const unsigned char *coll_sym = extra + cset->coll_syms[i]; /* Compare the length of input collating element and the length of current collating element. */ if (*coll_sym != elem_len) continue; /* Compare each bytes. */ for (j = 0; j < *coll_sym; j++) if (pin[j] != coll_sym[1 + j]) break; if (j == *coll_sym) { /* Match if every bytes is equal. */ match_len = j; goto check_node_accept_bytes_match; } } if (cset->nranges) { if (elem_len <= char_len) { collseqwc = _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQWC); in_collseq = collseq_table_lookup (collseqwc, wc); } else in_collseq = find_collation_sequence_value (pin, elem_len); } /* match with range expression? */ for (i = 0; i < cset->nranges; ++i) if (cset->range_starts[i] <= in_collseq && in_collseq <= cset->range_ends[i]) { match_len = elem_len; goto check_node_accept_bytes_match; } /* match with equivalence_class? */ if (cset->nequiv_classes) { const unsigned char *cp = pin; table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); weights = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); idx = findidx (&cp); if (idx > 0) for (i = 0; i < cset->nequiv_classes; ++i) { int32_t equiv_class_idx = cset->equiv_classes[i]; size_t weight_len = weights[idx]; if (weight_len == weights[equiv_class_idx]) { int cnt = 0; while (cnt <= weight_len && (weights[equiv_class_idx + 1 + cnt] == weights[idx + 1 + cnt])) ++cnt; if (cnt > weight_len) { match_len = elem_len; goto check_node_accept_bytes_match; } } } } } else # endif /* _LIBC */ { /* match with range expression? */ #if __GNUC__ >= 2 wchar_t cmp_buf[] = {L'\0', L'\0', wc, L'\0', L'\0', L'\0'}; #else wchar_t cmp_buf[] = {L'\0', L'\0', L'\0', L'\0', L'\0', L'\0'}; cmp_buf[2] = wc; #endif for (i = 0; i < cset->nranges; ++i) { cmp_buf[0] = cset->range_starts[i]; cmp_buf[4] = cset->range_ends[i]; if (wcscoll (cmp_buf, cmp_buf + 2) <= 0 && wcscoll (cmp_buf + 2, cmp_buf + 4) <= 0) { match_len = char_len; goto check_node_accept_bytes_match; } } } check_node_accept_bytes_match: if (!cset->non_match) return match_len; else { if (match_len > 0) return 0; else return (elem_len > char_len) ? elem_len : char_len; } } return 0; } # ifdef _LIBC static unsigned int find_collation_sequence_value (mbs, mbs_len) const unsigned char *mbs; size_t mbs_len; { uint32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules == 0) { if (mbs_len == 1) { /* No valid character. Match it as a single byte character. */ const unsigned char *collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_COLLSEQMB); return collseq[mbs[0]]; } return UINT_MAX; } else { int32_t idx; const unsigned char *extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); for (idx = 0; ;) { int mbs_cnt, found = 0; int32_t elem_mbs_len; /* Skip the name of collating element name. */ idx = idx + extra[idx] + 1; elem_mbs_len = extra[idx++]; if (mbs_len == elem_mbs_len) { for (mbs_cnt = 0; mbs_cnt < elem_mbs_len; ++mbs_cnt) if (extra[idx + mbs_cnt] != mbs[mbs_cnt]) break; if (mbs_cnt == elem_mbs_len) /* Found the entry. */ found = 1; } /* Skip the byte sequence of the collating element. */ idx += elem_mbs_len; /* Adjust for the alignment. */ idx = (idx + 3) & ~3; /* Skip the collation sequence value. */ idx += sizeof (uint32_t); /* Skip the wide char sequence of the collating element. */ idx = idx + sizeof (uint32_t) * (extra[idx] + 1); /* If we found the entry, return the sequence value. */ if (found) return *(uint32_t *) (extra + idx); /* Skip the collation sequence value. */ idx += sizeof (uint32_t); } } } # endif /* _LIBC */ #endif /* RE_ENABLE_I18N */ /* Check whether the node accepts the byte which is IDX-th byte of the INPUT. */ static int check_node_accept (preg, node, mctx, idx) const regex_t *preg; const re_token_t *node; const re_match_context_t *mctx; int idx; { unsigned char ch; if (node->constraint) { /* The node has constraints. Check whether the current context satisfies the constraints. */ unsigned int context = re_string_context_at (mctx->input, idx, mctx->eflags, preg->newline_anchor); if (NOT_SATISFY_NEXT_CONSTRAINT (node->constraint, context)) return 0; } ch = re_string_byte_at (mctx->input, idx); if (node->type == CHARACTER) return node->opr.c == ch; else if (node->type == SIMPLE_BRACKET) return bitset_contain (node->opr.sbcset, ch); else if (node->type == OP_PERIOD) return !((ch == '\n' && !(preg->syntax & RE_DOT_NEWLINE)) || (ch == '\0' && (preg->syntax & RE_DOT_NOT_NULL))); else return 0; } /* Extend the buffers, if the buffers have run out. */ static reg_errcode_t extend_buffers (mctx) re_match_context_t *mctx; { reg_errcode_t ret; re_string_t *pstr = mctx->input; /* Double the lengthes of the buffers. */ ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2); if (BE (ret != REG_NOERROR, 0)) return ret; if (mctx->state_log != NULL) { /* And double the length of state_log. */ re_dfastate_t **new_array; new_array = re_realloc (mctx->state_log, re_dfastate_t *, pstr->bufs_len * 2); if (BE (new_array == NULL, 0)) return REG_ESPACE; mctx->state_log = new_array; } /* Then reconstruct the buffers. */ if (pstr->icase) { #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) build_wcs_upper_buffer (pstr); else #endif /* RE_ENABLE_I18N */ build_upper_buffer (pstr); } else { #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) build_wcs_buffer (pstr); else #endif /* RE_ENABLE_I18N */ { if (pstr->trans != NULL) re_string_translate_buffer (pstr); else pstr->valid_len = pstr->bufs_len; } } return REG_NOERROR; } /* Functions for matching context. */ /* Initialize MCTX. */ static reg_errcode_t match_ctx_init (mctx, eflags, input, n) re_match_context_t *mctx; int eflags, n; re_string_t *input; { mctx->eflags = eflags; mctx->input = input; mctx->match_last = -1; if (n > 0) { mctx->bkref_ents = re_malloc (struct re_backref_cache_entry, n); mctx->sub_tops = re_malloc (re_sub_match_top_t *, n); if (BE (mctx->bkref_ents == NULL || mctx->sub_tops == NULL, 0)) return REG_ESPACE; } else mctx->bkref_ents = NULL; mctx->nbkref_ents = 0; mctx->abkref_ents = n; mctx->max_mb_elem_len = 1; mctx->nsub_tops = 0; mctx->asub_tops = n; return REG_NOERROR; } /* Clean the entries which depend on the current input in MCTX. This function must be invoked when the matcher changes the start index of the input, or changes the input string. */ static void match_ctx_clean (mctx) re_match_context_t *mctx; { match_ctx_free_subtops (mctx); mctx->nsub_tops = 0; mctx->nbkref_ents = 0; } /* Free all the memory associated with MCTX. */ static void match_ctx_free (mctx) re_match_context_t *mctx; { match_ctx_free_subtops (mctx); re_free (mctx->sub_tops); re_free (mctx->bkref_ents); } /* Free all the memory associated with MCTX->SUB_TOPS. */ static void match_ctx_free_subtops (mctx) re_match_context_t *mctx; { int st_idx; for (st_idx = 0; st_idx < mctx->nsub_tops; ++st_idx) { int sl_idx; re_sub_match_top_t *top = mctx->sub_tops[st_idx]; for (sl_idx = 0; sl_idx < top->nlasts; ++sl_idx) { re_sub_match_last_t *last = top->lasts[sl_idx]; re_free (last->path.array); re_free (last); } re_free (top->lasts); if (top->path) { re_free (top->path->array); re_free (top->path); } free (top); } } /* Add a new backreference entry to MCTX. Note that we assume that caller never call this function with duplicate entry, and call with STR_IDX which isn't smaller than any existing entry. */ static reg_errcode_t match_ctx_add_entry (mctx, node, str_idx, from, to) re_match_context_t *mctx; int node, str_idx, from, to; { if (mctx->nbkref_ents >= mctx->abkref_ents) { struct re_backref_cache_entry* new_entry; new_entry = re_realloc (mctx->bkref_ents, struct re_backref_cache_entry, mctx->abkref_ents * 2); if (BE (new_entry == NULL, 0)) { re_free (mctx->bkref_ents); return REG_ESPACE; } mctx->bkref_ents = new_entry; memset (mctx->bkref_ents + mctx->nbkref_ents, '\0', sizeof (struct re_backref_cache_entry) * mctx->abkref_ents); mctx->abkref_ents *= 2; } mctx->bkref_ents[mctx->nbkref_ents].node = node; mctx->bkref_ents[mctx->nbkref_ents].str_idx = str_idx; mctx->bkref_ents[mctx->nbkref_ents].subexp_from = from; mctx->bkref_ents[mctx->nbkref_ents].subexp_to = to; mctx->bkref_ents[mctx->nbkref_ents++].flag = 0; if (mctx->max_mb_elem_len < to - from) mctx->max_mb_elem_len = to - from; return REG_NOERROR; } /* Search for the first entry which has the same str_idx. Note that MCTX->BKREF_ENTS is already sorted by MCTX->STR_IDX. */ static int search_cur_bkref_entry (mctx, str_idx) re_match_context_t *mctx; int str_idx; { int left, right, mid; right = mctx->nbkref_ents; for (left = 0; left < right;) { mid = (left + right) / 2; if (mctx->bkref_ents[mid].str_idx < str_idx) left = mid + 1; else right = mid; } return left; } static void match_ctx_clear_flag (mctx) re_match_context_t *mctx; { int i; for (i = 0; i < mctx->nbkref_ents; ++i) { mctx->bkref_ents[i].flag = 0; } } /* Register the node NODE, whose type is OP_OPEN_SUBEXP, and which matches at STR_IDX. */ static reg_errcode_t match_ctx_add_subtop (mctx, node, str_idx) re_match_context_t *mctx; int node, str_idx; { #ifdef DEBUG assert (mctx->sub_tops != NULL); assert (mctx->asub_tops > 0); #endif if (mctx->nsub_tops == mctx->asub_tops) { re_sub_match_top_t **new_array; mctx->asub_tops *= 2; new_array = re_realloc (mctx->sub_tops, re_sub_match_top_t *, mctx->asub_tops); if (BE (new_array == NULL, 0)) return REG_ESPACE; mctx->sub_tops = new_array; } mctx->sub_tops[mctx->nsub_tops] = calloc (1, sizeof (re_sub_match_top_t)); if (mctx->sub_tops[mctx->nsub_tops] == NULL) return REG_ESPACE; mctx->sub_tops[mctx->nsub_tops]->node = node; mctx->sub_tops[mctx->nsub_tops++]->str_idx = str_idx; return REG_NOERROR; } /* Register the node NODE, whose type is OP_CLOSE_SUBEXP, and which matches at STR_IDX, whose corresponding OP_OPEN_SUBEXP is SUB_TOP. */ static re_sub_match_last_t * match_ctx_add_sublast (subtop, node, str_idx) re_sub_match_top_t *subtop; int node, str_idx; { re_sub_match_last_t *new_entry; if (subtop->nlasts == subtop->alasts) { re_sub_match_last_t **new_array; subtop->alasts = 2 * subtop->alasts + 1; new_array = re_realloc (subtop->lasts, re_sub_match_last_t *, subtop->alasts); if (BE (new_array == NULL, 0)) return NULL; subtop->lasts = new_array; } new_entry = calloc (1, sizeof (re_sub_match_last_t)); if (BE (new_entry == NULL, 0)) return NULL; subtop->lasts[subtop->nlasts] = new_entry; new_entry->node = node; new_entry->str_idx = str_idx; ++subtop->nlasts; return new_entry; } static void sift_ctx_init (sctx, sifted_sts, limited_sts, last_node, last_str_idx, check_subexp) re_sift_context_t *sctx; re_dfastate_t **sifted_sts, **limited_sts; int last_node, last_str_idx, check_subexp; { sctx->sifted_states = sifted_sts; sctx->limited_states = limited_sts; sctx->last_node = last_node; sctx->last_str_idx = last_str_idx; sctx->check_subexp = check_subexp; sctx->cur_bkref = -1; sctx->cls_subexp_idx = -1; re_node_set_init_empty (&sctx->limits); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/regex/regex.h��������������������������������������������������������0000644�0000000�0000000�00000052345�12062407372�017472� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Definitions for data structures and routines for the regular expression library. Copyright (C) 1985,1989-93,1995-98,2000,2001,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _REGEX_H #define _REGEX_H 1 /* Allow the use in C++ code. */ #ifdef __cplusplus extern "C" { #endif /* POSIX says that <sys/types.h> must be included (by the caller) before <regex.h>. */ #if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && (defined VMS || defined _MSC_VER) /* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it should be there. Same for Microsoft Visual C++ 6.0 */ # include <stddef.h> #endif /* The following two types have to be signed and unsigned integer type wide enough to hold a value of a pointer. For most ANSI compilers ptrdiff_t and size_t should be likely OK. Still size of these two types is 2 for Microsoft C. Ugh... */ typedef long int s_reg_t; typedef unsigned long int active_reg_t; /* The following bits are used to determine the regexp syntax we recognize. The set/not-set meanings are chosen so that Emacs syntax remains the value 0. The bits are given in alphabetical order, and the definitions shifted by one from the previous bit; thus, when we add or remove a bit, only one other definition need change. */ typedef unsigned long int reg_syntax_t; /* If this bit is not set, then \ inside a bracket expression is literal. If set, then such a \ quotes the following character. */ #define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1) /* If this bit is not set, then + and ? are operators, and \+ and \? are literals. If set, then \+ and \? are operators and + and ? are literals. */ #define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1) /* If this bit is set, then character classes are supported. They are: [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:], [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:]. If not set, then character classes are not supported. */ #define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1) /* If this bit is set, then ^ and $ are always anchors (outside bracket expressions, of course). If this bit is not set, then it depends: ^ is an anchor if it is at the beginning of a regular expression or after an open-group or an alternation operator; $ is an anchor if it is at the end of a regular expression, or before a close-group or an alternation operator. This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because POSIX draft 11.2 says that * etc. in leading positions is undefined. We already implemented a previous draft which made those constructs invalid, though, so we haven't changed the code back. */ #define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1) /* If this bit is set, then special characters are always special regardless of where they are in the pattern. If this bit is not set, then special characters are special only in some contexts; otherwise they are ordinary. Specifically, * + ? and intervals are only special when not after the beginning, open-group, or alternation operator. */ #define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1) /* If this bit is set, then *, +, ?, and { cannot be first in an re or immediately after an alternation or begin-group operator. */ #define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1) /* If this bit is set, then . matches newline. If not set, then it doesn't. */ #define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1) /* If this bit is set, then . doesn't match NUL. If not set, then it does. */ #define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1) /* If this bit is set, nonmatching lists [^...] do not match newline. If not set, they do. */ #define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1) /* If this bit is set, either \{...\} or {...} defines an interval, depending on RE_NO_BK_BRACES. If not set, \{, \}, {, and } are literals. */ #define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1) /* If this bit is set, +, ? and | aren't recognized as operators. If not set, they are. */ #define RE_LIMITED_OPS (RE_INTERVALS << 1) /* If this bit is set, newline is an alternation operator. If not set, newline is literal. */ #define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1) /* If this bit is set, then `{...}' defines an interval, and \{ and \} are literals. If not set, then `\{...\}' defines an interval. */ #define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1) /* If this bit is set, (...) defines a group, and \( and \) are literals. If not set, \(...\) defines a group, and ( and ) are literals. */ #define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1) /* If this bit is set, then \<digit> matches <digit>. If not set, then \<digit> is a back-reference. */ #define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1) /* If this bit is set, then | is an alternation operator, and \| is literal. If not set, then \| is an alternation operator, and | is literal. */ #define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1) /* If this bit is set, then an ending range point collating higher than the starting range point, as in [z-a], is invalid. If not set, then when ending range point collates higher than the starting range point, the range is ignored. */ #define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1) /* If this bit is set, then an unmatched ) is ordinary. If not set, then an unmatched ) is invalid. */ #define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1) /* If this bit is set, succeed as soon as we match the whole pattern, without further backtracking. */ #define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1) /* If this bit is set, do not process the GNU regex operators. If not set, then the GNU regex operators are recognized. */ #define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1) /* If this bit is set, turn on internal regex debugging. If not set, and debugging was on, turn it off. This only works if regex.c is compiled -DDEBUG. We define this bit always, so that all that's needed to turn on debugging is to recompile regex.c; the calling code can always have this bit set, and it won't affect anything in the normal case. */ #define RE_DEBUG (RE_NO_GNU_OPS << 1) /* If this bit is set, a syntactically invalid interval is treated as a string of ordinary characters. For example, the ERE 'a{1' is treated as 'a\{1'. */ #define RE_INVALID_INTERVAL_ORD (RE_DEBUG << 1) /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define RE_ICASE (RE_INVALID_INTERVAL_ORD << 1) /* This global variable defines the particular regexp syntax to use (for some interfaces). When a regexp is compiled, the syntax used is stored in the pattern buffer, so changing this does not affect already-compiled regexps. */ extern reg_syntax_t re_syntax_options; /* Define combinations of the above bits for the standard possibilities. (The [[[ comments delimit what gets put into the Texinfo file, so don't delete them!) */ /* [[[begin syntaxes]]] */ #define RE_SYNTAX_EMACS 0 #define RE_SYNTAX_AWK \ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \ | RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \ | RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS) #define RE_SYNTAX_GNU_AWK \ ((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \ & ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS \ | RE_CONTEXT_INVALID_OPS )) #define RE_SYNTAX_POSIX_AWK \ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \ | RE_INTERVALS | RE_NO_GNU_OPS) #define RE_SYNTAX_GREP \ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \ | RE_NEWLINE_ALT) #define RE_SYNTAX_EGREP \ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \ | RE_NO_BK_VBAR) #define RE_SYNTAX_POSIX_EGREP \ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES \ | RE_INVALID_INTERVAL_ORD) /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ #define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC #define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC /* Syntax bits common to both basic and extended POSIX regex syntax. */ #define _RE_SYNTAX_POSIX_COMMON \ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \ | RE_INTERVALS | RE_NO_EMPTY_RANGES) #define RE_SYNTAX_POSIX_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM) /* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this isn't minimal, since other operators, such as \`, aren't disabled. */ #define RE_SYNTAX_POSIX_MINIMAL_BASIC \ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS) #define RE_SYNTAX_POSIX_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \ | RE_CONTEXT_INVALID_OPS | RE_UNMATCHED_RIGHT_PAREN_ORD) /* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INDEP_OPS is removed and RE_NO_BK_REFS is added. */ #define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \ | RE_NO_BK_PARENS | RE_NO_BK_REFS \ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD) /* [[[end syntaxes]]] */ /* Maximum number of duplicates an interval can allow. Some systems (erroneously) define this in other header files, but we want our value, so remove any previous define. */ #ifdef RE_DUP_MAX # undef RE_DUP_MAX #endif /* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */ #define RE_DUP_MAX (0x7fff) /* POSIX `cflags' bits (i.e., information for `regcomp'). */ /* If this bit is set, then use extended regular expression syntax. If not set, then use basic regular expression syntax. */ #define REG_EXTENDED 1 /* If this bit is set, then ignore case when matching. If not set, then case is significant. */ #define REG_ICASE (REG_EXTENDED << 1) /* If this bit is set, then anchors do not match at newline characters in the string. If not set, then anchors do match at newlines. */ #define REG_NEWLINE (REG_ICASE << 1) /* If this bit is set, then report only success or fail in regexec. If not set, then returns differ between not matching and errors. */ #define REG_NOSUB (REG_NEWLINE << 1) /* POSIX `eflags' bits (i.e., information for regexec). */ /* If this bit is set, then the beginning-of-line operator doesn't match the beginning of the string (presumably because it's not the beginning of a line). If not set, then the beginning-of-line operator does match the beginning of the string. */ #define REG_NOTBOL 1 /* Like REG_NOTBOL, except for the end-of-line. */ #define REG_NOTEOL (1 << 1) /* If any error codes are removed, changed, or added, update the `re_error_msg' table in regex.c. */ typedef enum { #ifdef _XOPEN_SOURCE REG_ENOSYS = -1, /* This will never happen for this implementation. */ #endif REG_NOERROR = 0, /* Success. */ REG_NOMATCH, /* Didn't find a match (for regexec). */ /* POSIX regcomp return error codes. (In the order listed in the standard.) */ REG_BADPAT, /* Invalid pattern. */ REG_ECOLLATE, /* Not implemented. */ REG_ECTYPE, /* Invalid character class name. */ REG_EESCAPE, /* Trailing backslash. */ REG_ESUBREG, /* Invalid back reference. */ REG_EBRACK, /* Unmatched left bracket. */ REG_EPAREN, /* Parenthesis imbalance. */ REG_EBRACE, /* Unmatched \{. */ REG_BADBR, /* Invalid contents of \{\}. */ REG_ERANGE, /* Invalid range end. */ REG_ESPACE, /* Ran out of memory. */ REG_BADRPT, /* No preceding re for repetition op. */ /* Error codes we've added. */ REG_EEND, /* Premature end. */ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */ } reg_errcode_t; /* This data structure represents a compiled pattern. Before calling the pattern compiler, the fields `buffer', `allocated', `fastmap', `translate', and `no_sub' can be set. After the pattern has been compiled, the `re_nsub' field is available. All other fields are private to the regex routines. */ #ifndef RE_TRANSLATE_TYPE # define RE_TRANSLATE_TYPE char * #endif struct re_pattern_buffer { /* [[[begin pattern_buffer]]] */ /* Space that holds the compiled pattern. It is declared as `unsigned char *' because its elements are sometimes used as array indexes. */ unsigned char *buffer; /* Number of bytes to which `buffer' points. */ unsigned long int allocated; /* Number of bytes actually used in `buffer'. */ unsigned long int used; /* Syntax setting with which the pattern was compiled. */ reg_syntax_t syntax; /* Pointer to a fastmap, if any, otherwise zero. re_search uses the fastmap, if there is one, to skip over impossible starting points for matches. */ char *fastmap; /* Either a translate table to apply to all characters before comparing them, or zero for no translation. The translation is applied to a pattern when it is compiled and to a string when it is matched. */ RE_TRANSLATE_TYPE translate; /* Number of subexpressions found by the compiler. */ size_t re_nsub; /* Zero if this pattern cannot match the empty string, one else. Well, in truth it's used only in `re_search_2', to see whether or not we should use the fastmap, so we don't set this absolutely perfectly; see `re_compile_fastmap' (the `duplicate' case). */ unsigned can_be_null : 1; /* If REGS_UNALLOCATED, allocate space in the `regs' structure for `max (RE_NREGS, re_nsub + 1)' groups. If REGS_REALLOCATE, reallocate space if necessary. If REGS_FIXED, use what's there. */ #define REGS_UNALLOCATED 0 #define REGS_REALLOCATE 1 #define REGS_FIXED 2 unsigned regs_allocated : 2; /* Set to zero when `regex_compile' compiles a pattern; set to one by `re_compile_fastmap' if it updates the fastmap. */ unsigned fastmap_accurate : 1; /* If set, `re_match_2' does not return information about subexpressions. */ unsigned no_sub : 1; /* If set, a beginning-of-line anchor doesn't match at the beginning of the string. */ unsigned not_bol : 1; /* Similarly for an end-of-line anchor. */ unsigned not_eol : 1; /* If true, an anchor at a newline matches. */ unsigned newline_anchor : 1; /* [[[end pattern_buffer]]] */ }; typedef struct re_pattern_buffer regex_t; /* Type for byte offsets within the string. POSIX mandates this. */ typedef int regoff_t; /* This is the structure we store register match data in. See regex.texinfo for a full description of what registers match. */ struct re_registers { unsigned num_regs; regoff_t *start; regoff_t *end; }; /* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer, `re_match_2' returns information about at least this many registers the first time a `regs' structure is passed. */ #ifndef RE_NREGS # define RE_NREGS 30 #endif /* POSIX specification for registers. Aside from the different names than `re_registers', POSIX uses an array of structures, instead of a structure of arrays. */ typedef struct { regoff_t rm_so; /* Byte offset from string's start to substring's start. */ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */ } regmatch_t; /* Declarations for routines. */ /* To avoid duplicating every routine declaration -- once with a prototype (if we are ANSI), and once without (if we aren't) -- we use the following macro to declare argument types. This unfortunately clutters up the declarations a bit, but I think it's worth it. */ #if defined(__STDC__) || defined(__cplusplus) # define _RE_ARGS(args) args #else /* not __STDC__ */ # define _RE_ARGS(args) () #endif /* not __STDC__ */ /* Sets the current default syntax to SYNTAX, and return the old syntax. You can also simply assign to the `re_syntax_options' variable. */ extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax)); /* Compile the regular expression PATTERN, with length LENGTH and syntax given by the global `re_syntax_options', into the buffer BUFFER. Return NULL if successful, and an error string if not. */ extern const char *re_compile_pattern _RE_ARGS ((const char *pattern, size_t length, struct re_pattern_buffer *buffer)); /* Compile a fastmap for the compiled pattern in BUFFER; used to accelerate searches. Return 0 if successful and -2 if was an internal error. */ extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer)); /* Search in the string STRING (with length LENGTH) for the pattern compiled into BUFFER. Start searching at position START, for RANGE characters. Return the starting position of the match, -1 for no match, or -2 for an internal error. Also return register information in REGS (if REGS and BUFFER->no_sub are nonzero). */ extern int re_search _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, int length, int start, int range, struct re_registers *regs)); /* Like `re_search', but search in the concatenation of STRING1 and STRING2. Also, stop searching at index START + STOP. */ extern int re_search_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, int length1, const char *string2, int length2, int start, int range, struct re_registers *regs, int stop)); /* Like `re_search', but return how many characters in STRING the regexp in BUFFER matched, starting at position START. */ extern int re_match _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string, int length, int start, struct re_registers *regs)); /* Relates to `re_match' as `re_search_2' relates to `re_search'. */ extern int re_match_2 _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1, int length1, const char *string2, int length2, int start, struct re_registers *regs, int stop)); /* Set REGS to hold NUM_REGS registers, storing them in STARTS and ENDS. Subsequent matches using BUFFER and REGS will use this memory for recording register information. STARTS and ENDS must be allocated with malloc, and must each be at least `NUM_REGS * sizeof (regoff_t)' bytes long. If NUM_REGS == 0, then subsequent matches should allocate their own register data. Unless this function is called, the first search or match using PATTERN_BUFFER will allocate its own register data, without freeing the old data. */ extern void re_set_registers _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs, unsigned num_regs, regoff_t *starts, regoff_t *ends)); #if defined _REGEX_RE_COMP || defined _LIBC # ifndef _CRAY /* 4.2 bsd compatibility. */ extern char *re_comp _RE_ARGS ((const char *)); extern int re_exec _RE_ARGS ((const char *)); # endif #endif /* GCC 2.95 and later have "__restrict"; C99 compilers have "restrict", and "configure" may have defined "restrict". */ #ifndef __restrict # if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) # if defined restrict || 199901L <= __STDC_VERSION__ # define __restrict restrict # else # define __restrict # endif # endif #endif /* gcc 3.1 and up support the [restrict] syntax. */ #ifndef __restrict_arr # if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) && !defined(__WIN32__) # define __restrict_arr __restrict # else # define __restrict_arr # endif #endif /* POSIX compatibility. */ extern int regcomp _RE_ARGS ((regex_t *__restrict __preg, const char *__restrict __pattern, int __cflags)); extern int regexec _RE_ARGS ((const regex_t *__restrict __preg, const char *__restrict __string, size_t __nmatch, regmatch_t __pmatch[__restrict_arr], int __eflags)); extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg, char *__errbuf, size_t __errbuf_size)); extern void regfree _RE_ARGS ((regex_t *__preg)); #ifdef __cplusplus } #endif /* C++ */ #endif /* regex.h */ /* Local variables: make-backup-files: t version-control: t trim-versions-without-asking: nil End: */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/regex/regex_internal.c�����������������������������������������������0000644�0000000�0000000�00000103143�12062407372�021352� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Extended regular expression matching and search library. Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ static void re_string_construct_common (const char *str, int len, re_string_t *pstr, RE_TRANSLATE_TYPE trans, int icase); #ifdef RE_ENABLE_I18N static int re_string_skip_chars (re_string_t *pstr, int new_raw_idx, wint_t *last_wc); #endif /* RE_ENABLE_I18N */ static re_dfastate_t *create_newstate_common (re_dfa_t *dfa, const re_node_set *nodes, unsigned int hash); static reg_errcode_t register_state (re_dfa_t *dfa, re_dfastate_t *newstate, unsigned int hash); static re_dfastate_t *create_ci_newstate (re_dfa_t *dfa, const re_node_set *nodes, unsigned int hash); static re_dfastate_t *create_cd_newstate (re_dfa_t *dfa, const re_node_set *nodes, unsigned int context, unsigned int hash); static unsigned int inline calc_state_hash (const re_node_set *nodes, unsigned int context); /* Functions for string operation. */ /* This function allocate the buffers. It is necessary to call re_string_reconstruct before using the object. */ static reg_errcode_t re_string_allocate (pstr, str, len, init_len, trans, icase) re_string_t *pstr; const char *str; int len, init_len, icase; RE_TRANSLATE_TYPE trans; { reg_errcode_t ret; int init_buf_len = (len + 1 < init_len) ? len + 1: init_len; re_string_construct_common (str, len, pstr, trans, icase); pstr->stop = pstr->len; ret = re_string_realloc_buffers (pstr, init_buf_len); if (BE (ret != REG_NOERROR, 0)) return ret; pstr->mbs_case = (MBS_CASE_ALLOCATED (pstr) ? pstr->mbs_case : (unsigned char *) str); pstr->mbs = MBS_ALLOCATED (pstr) ? pstr->mbs : pstr->mbs_case; pstr->valid_len = (MBS_CASE_ALLOCATED (pstr) || MBS_ALLOCATED (pstr) || MB_CUR_MAX > 1) ? pstr->valid_len : len; return REG_NOERROR; } /* This function allocate the buffers, and initialize them. */ static reg_errcode_t re_string_construct (pstr, str, len, trans, icase) re_string_t *pstr; const char *str; int len, icase; RE_TRANSLATE_TYPE trans; { reg_errcode_t ret; re_string_construct_common (str, len, pstr, trans, icase); pstr->stop = pstr->len; /* Set 0 so that this function can initialize whole buffers. */ pstr->valid_len = 0; if (len > 0) { ret = re_string_realloc_buffers (pstr, len + 1); if (BE (ret != REG_NOERROR, 0)) return ret; } pstr->mbs_case = (MBS_CASE_ALLOCATED (pstr) ? pstr->mbs_case : (unsigned char *) str); pstr->mbs = MBS_ALLOCATED (pstr) ? pstr->mbs : pstr->mbs_case; if (icase) { #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) build_wcs_upper_buffer (pstr); else #endif /* RE_ENABLE_I18N */ build_upper_buffer (pstr); } else { #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) build_wcs_buffer (pstr); else #endif /* RE_ENABLE_I18N */ { if (trans != NULL) re_string_translate_buffer (pstr); else pstr->valid_len = len; } } /* Initialized whole buffers, then valid_len == bufs_len. */ pstr->valid_len = pstr->bufs_len; return REG_NOERROR; } /* Helper functions for re_string_allocate, and re_string_construct. */ static reg_errcode_t re_string_realloc_buffers (pstr, new_buf_len) re_string_t *pstr; int new_buf_len; { #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) { wint_t *new_array = re_realloc (pstr->wcs, wint_t, new_buf_len); if (BE (new_array == NULL, 0)) return REG_ESPACE; pstr->wcs = new_array; } #endif /* RE_ENABLE_I18N */ if (MBS_ALLOCATED (pstr)) { unsigned char *new_array = re_realloc (pstr->mbs, unsigned char, new_buf_len); if (BE (new_array == NULL, 0)) return REG_ESPACE; pstr->mbs = new_array; } if (MBS_CASE_ALLOCATED (pstr)) { unsigned char *new_array = re_realloc (pstr->mbs_case, unsigned char, new_buf_len); if (BE (new_array == NULL, 0)) return REG_ESPACE; pstr->mbs_case = new_array; if (!MBS_ALLOCATED (pstr)) pstr->mbs = pstr->mbs_case; } pstr->bufs_len = new_buf_len; return REG_NOERROR; } static void re_string_construct_common (str, len, pstr, trans, icase) const char *str; int len; re_string_t *pstr; RE_TRANSLATE_TYPE trans; int icase; { memset (pstr, '\0', sizeof (re_string_t)); pstr->raw_mbs = (const unsigned char *) str; pstr->len = len; pstr->trans = trans; pstr->icase = icase ? 1 : 0; } #ifdef RE_ENABLE_I18N /* Build wide character buffer PSTR->WCS. If the byte sequence of the string are: <mb1>(0), <mb1>(1), <mb2>(0), <mb2>(1), <sb3> Then wide character buffer will be: <wc1> , WEOF , <wc2> , WEOF , <wc3> We use WEOF for padding, they indicate that the position isn't a first byte of a multibyte character. Note that this function assumes PSTR->VALID_LEN elements are already built and starts from PSTR->VALID_LEN. */ static void build_wcs_buffer (pstr) re_string_t *pstr; { mbstate_t prev_st; int byte_idx, end_idx, mbclen, remain_len; /* Build the buffers from pstr->valid_len to either pstr->len or pstr->bufs_len. */ end_idx = (pstr->bufs_len > pstr->len)? pstr->len : pstr->bufs_len; for (byte_idx = pstr->valid_len; byte_idx < end_idx;) { wchar_t wc; remain_len = end_idx - byte_idx; prev_st = pstr->cur_state; mbclen = mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx), remain_len, &pstr->cur_state); if (BE (mbclen == (size_t) -2, 0)) { /* The buffer doesn't have enough space, finish to build. */ pstr->cur_state = prev_st; break; } else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0)) { /* We treat these cases as a singlebyte character. */ mbclen = 1; wc = (wchar_t) pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; pstr->cur_state = prev_st; } /* Apply the translateion if we need. */ if (pstr->trans != NULL && mbclen == 1) { int ch = pstr->trans[pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]]; pstr->mbs_case[byte_idx] = ch; } /* Write wide character and padding. */ pstr->wcs[byte_idx++] = wc; /* Write paddings. */ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) pstr->wcs[byte_idx++] = WEOF; } pstr->valid_len = byte_idx; } /* Build wide character buffer PSTR->WCS like build_wcs_buffer, but for REG_ICASE. */ static void build_wcs_upper_buffer (pstr) re_string_t *pstr; { mbstate_t prev_st; int byte_idx, end_idx, mbclen, remain_len; /* Build the buffers from pstr->valid_len to either pstr->len or pstr->bufs_len. */ end_idx = (pstr->bufs_len > pstr->len)? pstr->len : pstr->bufs_len; for (byte_idx = pstr->valid_len; byte_idx < end_idx;) { wchar_t wc; remain_len = end_idx - byte_idx; prev_st = pstr->cur_state; mbclen = mbrtowc (&wc, ((const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx), remain_len, &pstr->cur_state); if (BE (mbclen == (size_t) -2, 0)) { /* The buffer doesn't have enough space, finish to build. */ pstr->cur_state = prev_st; break; } else if (mbclen == 1 || mbclen == (size_t) -1 || mbclen == 0) { /* In case of a singlebyte character. */ int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx]; /* Apply the translateion if we need. */ if (pstr->trans != NULL && mbclen == 1) { ch = pstr->trans[ch]; pstr->mbs_case[byte_idx] = ch; } pstr->wcs[byte_idx] = iswlower (wc) ? toupper (wc) : wc; pstr->mbs[byte_idx++] = islower (ch) ? toupper (ch) : ch; if (BE (mbclen == (size_t) -1, 0)) pstr->cur_state = prev_st; } else /* mbclen > 1 */ { if (iswlower (wc)) wcrtomb ((char *) pstr->mbs + byte_idx, towupper (wc), &prev_st); else memcpy (pstr->mbs + byte_idx, pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx, mbclen); pstr->wcs[byte_idx++] = iswlower (wc) ? toupper (wc) : wc; /* Write paddings. */ for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;) pstr->wcs[byte_idx++] = WEOF; } } pstr->valid_len = byte_idx; } /* Skip characters until the index becomes greater than NEW_RAW_IDX. Return the index. */ static int re_string_skip_chars (pstr, new_raw_idx, last_wc) re_string_t *pstr; int new_raw_idx; wint_t *last_wc; { mbstate_t prev_st; int rawbuf_idx, mbclen; wchar_t wc = 0; /* Skip the characters which are not necessary to check. */ for (rawbuf_idx = pstr->raw_mbs_idx + pstr->valid_len; rawbuf_idx < new_raw_idx;) { int remain_len; remain_len = pstr->len - rawbuf_idx; prev_st = pstr->cur_state; mbclen = mbrtowc (&wc, (const char *) pstr->raw_mbs + rawbuf_idx, remain_len, &pstr->cur_state); if (BE (mbclen == (size_t) -2 || mbclen == (size_t) -1 || mbclen == 0, 0)) { /* We treat these cases as a singlebyte character. */ mbclen = 1; pstr->cur_state = prev_st; } /* Then proceed the next character. */ rawbuf_idx += mbclen; } *last_wc = (wint_t) wc; return rawbuf_idx; } #endif /* RE_ENABLE_I18N */ /* Build the buffer PSTR->MBS, and apply the translation if we need. This function is used in case of REG_ICASE. */ static void build_upper_buffer (pstr) re_string_t *pstr; { int char_idx, end_idx; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; for (char_idx = pstr->valid_len; char_idx < end_idx; ++char_idx) { int ch = pstr->raw_mbs[pstr->raw_mbs_idx + char_idx]; if (pstr->trans != NULL) { ch = pstr->trans[ch]; pstr->mbs_case[char_idx] = ch; } if (islower (ch)) pstr->mbs[char_idx] = toupper (ch); else pstr->mbs[char_idx] = ch; } pstr->valid_len = char_idx; } /* Apply TRANS to the buffer in PSTR. */ static void re_string_translate_buffer (pstr) re_string_t *pstr; { int buf_idx, end_idx; end_idx = (pstr->bufs_len > pstr->len) ? pstr->len : pstr->bufs_len; for (buf_idx = pstr->valid_len; buf_idx < end_idx; ++buf_idx) { int ch = pstr->raw_mbs[pstr->raw_mbs_idx + buf_idx]; pstr->mbs_case[buf_idx] = pstr->trans[ch]; } pstr->valid_len = buf_idx; } /* This function re-construct the buffers. Concretely, convert to wide character in case of MB_CUR_MAX > 1, convert to upper case in case of REG_ICASE, apply translation. */ static reg_errcode_t re_string_reconstruct (pstr, idx, eflags, newline) re_string_t *pstr; int idx, eflags, newline; { int offset = idx - pstr->raw_mbs_idx; if (offset < 0) { /* Reset buffer. */ #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) memset (&pstr->cur_state, '\0', sizeof (mbstate_t)); #endif /* RE_ENABLE_I18N */ pstr->len += pstr->raw_mbs_idx; pstr->stop += pstr->raw_mbs_idx; pstr->valid_len = pstr->raw_mbs_idx = 0; pstr->tip_context = ((eflags & REG_NOTBOL) ? CONTEXT_BEGBUF : CONTEXT_NEWLINE | CONTEXT_BEGBUF); if (!MBS_CASE_ALLOCATED (pstr)) pstr->mbs_case = (unsigned char *) pstr->raw_mbs; if (!MBS_ALLOCATED (pstr) && !MBS_CASE_ALLOCATED (pstr)) pstr->mbs = (unsigned char *) pstr->raw_mbs; offset = idx; } if (offset != 0) { /* Are the characters which are already checked remain? */ if (offset < pstr->valid_len) { /* Yes, move them to the front of the buffer. */ pstr->tip_context = re_string_context_at (pstr, offset - 1, eflags, newline); #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) memmove (pstr->wcs, pstr->wcs + offset, (pstr->valid_len - offset) * sizeof (wint_t)); #endif /* RE_ENABLE_I18N */ if (MBS_ALLOCATED (pstr)) memmove (pstr->mbs, pstr->mbs + offset, pstr->valid_len - offset); if (MBS_CASE_ALLOCATED (pstr)) memmove (pstr->mbs_case, pstr->mbs_case + offset, pstr->valid_len - offset); pstr->valid_len -= offset; #if DEBUG assert (pstr->valid_len > 0); #endif } else { /* No, skip all characters until IDX. */ pstr->valid_len = 0; #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) { int wcs_idx; wint_t wc; pstr->valid_len = re_string_skip_chars (pstr, idx, &wc) - idx; for (wcs_idx = 0; wcs_idx < pstr->valid_len; ++wcs_idx) pstr->wcs[wcs_idx] = WEOF; if (pstr->trans && wc <= 0xff) wc = pstr->trans[wc]; pstr->tip_context = (IS_WIDE_WORD_CHAR (wc) ? CONTEXT_WORD : ((newline && IS_WIDE_NEWLINE (wc)) ? CONTEXT_NEWLINE : 0)); } else #endif /* RE_ENABLE_I18N */ { int c = pstr->raw_mbs[pstr->raw_mbs_idx + offset - 1]; if (pstr->trans) c = pstr->trans[c]; pstr->tip_context = (IS_WORD_CHAR (c) ? CONTEXT_WORD : ((newline && IS_NEWLINE (c)) ? CONTEXT_NEWLINE : 0)); } } if (!MBS_CASE_ALLOCATED (pstr)) { pstr->mbs_case += offset; /* In case of !MBS_ALLOCATED && !MBS_CASE_ALLOCATED. */ if (!MBS_ALLOCATED (pstr)) pstr->mbs += offset; } } pstr->raw_mbs_idx = idx; pstr->len -= offset; pstr->stop -= offset; /* Then build the buffers. */ #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) { if (pstr->icase) build_wcs_upper_buffer (pstr); else build_wcs_buffer (pstr); } else #endif /* RE_ENABLE_I18N */ { if (pstr->icase) build_upper_buffer (pstr); else if (pstr->trans != NULL) re_string_translate_buffer (pstr); } pstr->cur_idx = 0; return REG_NOERROR; } static void re_string_destruct (pstr) re_string_t *pstr; { #ifdef RE_ENABLE_I18N re_free (pstr->wcs); #endif /* RE_ENABLE_I18N */ if (MBS_ALLOCATED (pstr)) re_free (pstr->mbs); if (MBS_CASE_ALLOCATED (pstr)) re_free (pstr->mbs_case); } /* Return the context at IDX in INPUT. */ static unsigned int re_string_context_at (input, idx, eflags, newline_anchor) const re_string_t *input; int idx, eflags, newline_anchor; { int c; if (idx < 0 || idx == input->len) { if (idx < 0) /* In this case, we use the value stored in input->tip_context, since we can't know the character in input->mbs[-1] here. */ return input->tip_context; else /* (idx == input->len) */ return ((eflags & REG_NOTEOL) ? CONTEXT_ENDBUF : CONTEXT_NEWLINE | CONTEXT_ENDBUF); } #ifdef RE_ENABLE_I18N if (MB_CUR_MAX > 1) { wint_t wc; int wc_idx = idx; while(input->wcs[wc_idx] == WEOF) { #ifdef DEBUG /* It must not happen. */ assert (wc_idx >= 0); #endif --wc_idx; if (wc_idx < 0) return input->tip_context; } wc = input->wcs[wc_idx]; if (IS_WIDE_WORD_CHAR (wc)) return CONTEXT_WORD; return (newline_anchor && IS_WIDE_NEWLINE (wc)) ? CONTEXT_NEWLINE : 0; } else #endif { c = re_string_byte_at (input, idx); if (IS_WORD_CHAR (c)) return CONTEXT_WORD; return (newline_anchor && IS_NEWLINE (c)) ? CONTEXT_NEWLINE : 0; } } /* Functions for set operation. */ static reg_errcode_t re_node_set_alloc (set, size) re_node_set *set; int size; { set->alloc = size; set->nelem = 0; set->elems = re_malloc (int, size); if (BE (set->elems == NULL, 0)) return REG_ESPACE; return REG_NOERROR; } static reg_errcode_t re_node_set_init_1 (set, elem) re_node_set *set; int elem; { set->alloc = 1; set->nelem = 1; set->elems = re_malloc (int, 1); if (BE (set->elems == NULL, 0)) { set->alloc = set->nelem = 0; return REG_ESPACE; } set->elems[0] = elem; return REG_NOERROR; } static reg_errcode_t re_node_set_init_2 (set, elem1, elem2) re_node_set *set; int elem1, elem2; { set->alloc = 2; set->elems = re_malloc (int, 2); if (BE (set->elems == NULL, 0)) return REG_ESPACE; if (elem1 == elem2) { set->nelem = 1; set->elems[0] = elem1; } else { set->nelem = 2; if (elem1 < elem2) { set->elems[0] = elem1; set->elems[1] = elem2; } else { set->elems[0] = elem2; set->elems[1] = elem1; } } return REG_NOERROR; } static reg_errcode_t re_node_set_init_copy (dest, src) re_node_set *dest; const re_node_set *src; { dest->nelem = src->nelem; if (src->nelem > 0) { dest->alloc = dest->nelem; dest->elems = re_malloc (int, dest->alloc); if (BE (dest->elems == NULL, 0)) { dest->alloc = dest->nelem = 0; return REG_ESPACE; } memcpy (dest->elems, src->elems, src->nelem * sizeof (int)); } else re_node_set_init_empty (dest); return REG_NOERROR; } /* Calculate the intersection of the sets SRC1 and SRC2. And merge it to DEST. Return value indicate the error code or REG_NOERROR if succeeded. Note: We assume dest->elems is NULL, when dest->alloc is 0. */ static reg_errcode_t re_node_set_add_intersect (dest, src1, src2) re_node_set *dest; const re_node_set *src1, *src2; { int i1, i2, id; if (src1->nelem > 0 && src2->nelem > 0) { if (src1->nelem + src2->nelem + dest->nelem > dest->alloc) { dest->alloc = src1->nelem + src2->nelem + dest->nelem; dest->elems = re_realloc (dest->elems, int, dest->alloc); if (BE (dest->elems == NULL, 0)) return REG_ESPACE; } } else return REG_NOERROR; for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) { if (src1->elems[i1] > src2->elems[i2]) { ++i2; continue; } if (src1->elems[i1] == src2->elems[i2]) { while (id < dest->nelem && dest->elems[id] < src2->elems[i2]) ++id; if (id < dest->nelem && dest->elems[id] == src2->elems[i2]) ++id; else { memmove (dest->elems + id + 1, dest->elems + id, sizeof (int) * (dest->nelem - id)); dest->elems[id++] = src2->elems[i2++]; ++dest->nelem; } } ++i1; } return REG_NOERROR; } /* Calculate the union set of the sets SRC1 and SRC2. And store it to DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ static reg_errcode_t re_node_set_init_union (dest, src1, src2) re_node_set *dest; const re_node_set *src1, *src2; { int i1, i2, id; if (src1 != NULL && src1->nelem > 0 && src2 != NULL && src2->nelem > 0) { dest->alloc = src1->nelem + src2->nelem; dest->elems = re_malloc (int, dest->alloc); if (BE (dest->elems == NULL, 0)) return REG_ESPACE; } else { if (src1 != NULL && src1->nelem > 0) return re_node_set_init_copy (dest, src1); else if (src2 != NULL && src2->nelem > 0) return re_node_set_init_copy (dest, src2); else re_node_set_init_empty (dest); return REG_NOERROR; } for (i1 = i2 = id = 0 ; i1 < src1->nelem && i2 < src2->nelem ;) { if (src1->elems[i1] > src2->elems[i2]) { dest->elems[id++] = src2->elems[i2++]; continue; } if (src1->elems[i1] == src2->elems[i2]) ++i2; dest->elems[id++] = src1->elems[i1++]; } if (i1 < src1->nelem) { memcpy (dest->elems + id, src1->elems + i1, (src1->nelem - i1) * sizeof (int)); id += src1->nelem - i1; } else if (i2 < src2->nelem) { memcpy (dest->elems + id, src2->elems + i2, (src2->nelem - i2) * sizeof (int)); id += src2->nelem - i2; } dest->nelem = id; return REG_NOERROR; } /* Calculate the union set of the sets DEST and SRC. And store it to DEST. Return value indicate the error code or REG_NOERROR if succeeded. */ static reg_errcode_t re_node_set_merge (dest, src) re_node_set *dest; const re_node_set *src; { int si, di; if (src == NULL || src->nelem == 0) return REG_NOERROR; if (dest->alloc < src->nelem + dest->nelem) { int *new_buffer; dest->alloc = 2 * (src->nelem + dest->alloc); new_buffer = re_realloc (dest->elems, int, dest->alloc); if (BE (new_buffer == NULL, 0)) return REG_ESPACE; dest->elems = new_buffer; } for (si = 0, di = 0 ; si < src->nelem && di < dest->nelem ;) { int cp_from, ncp, mid, right, src_elem = src->elems[si]; /* Binary search the spot we will add the new element. */ right = dest->nelem; while (di < right) { mid = (di + right) / 2; if (dest->elems[mid] < src_elem) di = mid + 1; else right = mid; } if (di >= dest->nelem) break; if (dest->elems[di] == src_elem) { /* Skip since, DEST already has the element. */ ++di; ++si; continue; } /* Skip the src elements which are less than dest->elems[di]. */ cp_from = si; while (si < src->nelem && src->elems[si] < dest->elems[di]) ++si; /* Copy these src elements. */ ncp = si - cp_from; memmove (dest->elems + di + ncp, dest->elems + di, sizeof (int) * (dest->nelem - di)); memcpy (dest->elems + di, src->elems + cp_from, sizeof (int) * ncp); /* Update counters. */ di += ncp; dest->nelem += ncp; } /* Copy remaining src elements. */ if (si < src->nelem) { memcpy (dest->elems + di, src->elems + si, sizeof (int) * (src->nelem - si)); dest->nelem += src->nelem - si; } return REG_NOERROR; } /* Insert the new element ELEM to the re_node_set* SET. return 0 if SET already has ELEM, return -1 if an error is occured, return 1 otherwise. */ static int re_node_set_insert (set, elem) re_node_set *set; int elem; { int idx, right, mid; /* In case of the set is empty. */ if (set->elems == NULL || set->alloc == 0) { if (BE (re_node_set_init_1 (set, elem) == REG_NOERROR, 1)) return 1; else return -1; } /* Binary search the spot we will add the new element. */ idx = 0; right = set->nelem; while (idx < right) { mid = (idx + right) / 2; if (set->elems[mid] < elem) idx = mid + 1; else right = mid; } /* Realloc if we need. */ if (set->alloc < set->nelem + 1) { int *new_array; set->alloc = set->alloc * 2; new_array = re_malloc (int, set->alloc); if (BE (new_array == NULL, 0)) return -1; /* Copy the elements they are followed by the new element. */ if (idx > 0) memcpy (new_array, set->elems, sizeof (int) * (idx)); /* Copy the elements which follows the new element. */ if (set->nelem - idx > 0) memcpy (new_array + idx + 1, set->elems + idx, sizeof (int) * (set->nelem - idx)); re_free (set->elems); set->elems = new_array; } else { /* Move the elements which follows the new element. */ if (set->nelem - idx > 0) memmove (set->elems + idx + 1, set->elems + idx, sizeof (int) * (set->nelem - idx)); } /* Insert the new element. */ set->elems[idx] = elem; ++set->nelem; return 1; } /* Compare two node sets SET1 and SET2. return 1 if SET1 and SET2 are equivalent, retrun 0 otherwise. */ static int re_node_set_compare (set1, set2) const re_node_set *set1, *set2; { int i; if (set1 == NULL || set2 == NULL || set1->nelem != set2->nelem) return 0; for (i = 0 ; i < set1->nelem ; i++) if (set1->elems[i] != set2->elems[i]) return 0; return 1; } /* Return (idx + 1) if SET contains the element ELEM, return 0 otherwise. */ static int re_node_set_contains (set, elem) const re_node_set *set; int elem; { int idx, right, mid; if (set->nelem <= 0) return 0; /* Binary search the element. */ idx = 0; right = set->nelem - 1; while (idx < right) { mid = (idx + right) / 2; if (set->elems[mid] < elem) idx = mid + 1; else right = mid; } return set->elems[idx] == elem ? idx + 1 : 0; } static void re_node_set_remove_at (set, idx) re_node_set *set; int idx; { if (idx < 0 || idx >= set->nelem) return; if (idx < set->nelem - 1) memmove (set->elems + idx, set->elems + idx + 1, sizeof (int) * (set->nelem - idx - 1)); --set->nelem; } /* Add the token TOKEN to dfa->nodes, and return the index of the token. Or return -1, if an error will be occured. */ static int re_dfa_add_node (dfa, token, mode) re_dfa_t *dfa; re_token_t token; int mode; { if (dfa->nodes_len >= dfa->nodes_alloc) { re_token_t *new_array; dfa->nodes_alloc *= 2; new_array = re_realloc (dfa->nodes, re_token_t, dfa->nodes_alloc); if (BE (new_array == NULL, 0)) return -1; else dfa->nodes = new_array; if (mode) { int *new_nexts, *new_indices; re_node_set *new_edests, *new_eclosures, *new_inveclosures; new_nexts = re_realloc (dfa->nexts, int, dfa->nodes_alloc); new_indices = re_realloc (dfa->org_indices, int, dfa->nodes_alloc); new_edests = re_realloc (dfa->edests, re_node_set, dfa->nodes_alloc); new_eclosures = re_realloc (dfa->eclosures, re_node_set, dfa->nodes_alloc); new_inveclosures = re_realloc (dfa->inveclosures, re_node_set, dfa->nodes_alloc); if (BE (new_nexts == NULL || new_indices == NULL || new_edests == NULL || new_eclosures == NULL || new_inveclosures == NULL, 0)) return -1; dfa->nexts = new_nexts; dfa->org_indices = new_indices; dfa->edests = new_edests; dfa->eclosures = new_eclosures; dfa->inveclosures = new_inveclosures; } } dfa->nodes[dfa->nodes_len] = token; dfa->nodes[dfa->nodes_len].duplicated = 0; dfa->nodes[dfa->nodes_len].constraint = 0; return dfa->nodes_len++; } static unsigned int inline calc_state_hash (nodes, context) const re_node_set *nodes; unsigned int context; { unsigned int hash = nodes->nelem + context; int i; for (i = 0 ; i < nodes->nelem ; i++) hash += nodes->elems[i]; return hash; } /* Search for the state whose node_set is equivalent to NODES. Return the pointer to the state, if we found it in the DFA. Otherwise create the new one and return it. In case of an error return NULL and set the error code in ERR. Note: - We assume NULL as the invalid state, then it is possible that return value is NULL and ERR is REG_NOERROR. - We never return non-NULL value in case of any errors, it is for optimization. */ static re_dfastate_t* re_acquire_state (err, dfa, nodes) reg_errcode_t *err; re_dfa_t *dfa; const re_node_set *nodes; { unsigned int hash; re_dfastate_t *new_state; struct re_state_table_entry *spot; int i; if (BE (nodes->nelem == 0, 0)) { *err = REG_NOERROR; return NULL; } hash = calc_state_hash (nodes, 0); spot = dfa->state_table + (hash & dfa->state_hash_mask); for (i = 0 ; i < spot->num ; i++) { re_dfastate_t *state = spot->array[i]; if (hash != state->hash) continue; if (re_node_set_compare (&state->nodes, nodes)) return state; } /* There are no appropriate state in the dfa, create the new one. */ new_state = create_ci_newstate (dfa, nodes, hash); if (BE (new_state != NULL, 1)) return new_state; else { *err = REG_ESPACE; return NULL; } } /* Search for the state whose node_set is equivalent to NODES and whose context is equivalent to CONTEXT. Return the pointer to the state, if we found it in the DFA. Otherwise create the new one and return it. In case of an error return NULL and set the error code in ERR. Note: - We assume NULL as the invalid state, then it is possible that return value is NULL and ERR is REG_NOERROR. - We never return non-NULL value in case of any errors, it is for optimization. */ static re_dfastate_t* re_acquire_state_context (err, dfa, nodes, context) reg_errcode_t *err; re_dfa_t *dfa; const re_node_set *nodes; unsigned int context; { unsigned int hash; re_dfastate_t *new_state; struct re_state_table_entry *spot; int i; if (nodes->nelem == 0) { *err = REG_NOERROR; return NULL; } hash = calc_state_hash (nodes, context); spot = dfa->state_table + (hash & dfa->state_hash_mask); for (i = 0 ; i < spot->num ; i++) { re_dfastate_t *state = spot->array[i]; if (hash != state->hash) continue; if (re_node_set_compare (state->entrance_nodes, nodes) && state->context == context) return state; } /* There are no appropriate state in `dfa', create the new one. */ new_state = create_cd_newstate (dfa, nodes, context, hash); if (BE (new_state != NULL, 1)) return new_state; else { *err = REG_ESPACE; return NULL; } } /* Allocate memory for DFA state and initialize common properties. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * create_newstate_common (dfa, nodes, hash) re_dfa_t *dfa; const re_node_set *nodes; unsigned int hash; { re_dfastate_t *newstate; reg_errcode_t err; newstate = (re_dfastate_t *) calloc (sizeof (re_dfastate_t), 1); if (BE (newstate == NULL, 0)) return NULL; err = re_node_set_init_copy (&newstate->nodes, nodes); if (BE (err != REG_NOERROR, 0)) { re_free (newstate); return NULL; } newstate->trtable = NULL; newstate->trtable_search = NULL; newstate->hash = hash; return newstate; } /* Store the new state NEWSTATE whose hash value is HASH in appropriate position. Return value indicate the error code if failed. */ static reg_errcode_t register_state (dfa, newstate, hash) re_dfa_t *dfa; re_dfastate_t *newstate; unsigned int hash; { struct re_state_table_entry *spot; spot = dfa->state_table + (hash & dfa->state_hash_mask); if (spot->alloc <= spot->num) { re_dfastate_t **new_array; spot->alloc = 2 * spot->num + 2; new_array = re_realloc (spot->array, re_dfastate_t *, spot->alloc); if (BE (new_array == NULL, 0)) return REG_ESPACE; spot->array = new_array; } spot->array[spot->num++] = newstate; return REG_NOERROR; } /* Create the new state which is independ of contexts. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * create_ci_newstate (dfa, nodes, hash) re_dfa_t *dfa; const re_node_set *nodes; unsigned int hash; { int i; reg_errcode_t err; re_dfastate_t *newstate; newstate = create_newstate_common (dfa, nodes, hash); if (BE (newstate == NULL, 0)) return NULL; newstate->entrance_nodes = &newstate->nodes; for (i = 0 ; i < nodes->nelem ; i++) { re_token_t *node = dfa->nodes + nodes->elems[i]; re_token_type_t type = node->type; if (type == CHARACTER && !node->constraint) continue; /* If the state has the halt node, the state is a halt state. */ else if (type == END_OF_RE) newstate->halt = 1; #ifdef RE_ENABLE_I18N else if (type == COMPLEX_BRACKET || (type == OP_PERIOD && MB_CUR_MAX > 1)) newstate->accept_mb = 1; #endif /* RE_ENABLE_I18N */ else if (type == OP_BACK_REF) newstate->has_backref = 1; else if (type == ANCHOR || node->constraint) newstate->has_constraint = 1; } err = register_state (dfa, newstate, hash); if (BE (err != REG_NOERROR, 0)) { free_state (newstate); newstate = NULL; } return newstate; } /* Create the new state which is depend on the context CONTEXT. Return the new state if succeeded, otherwise return NULL. */ static re_dfastate_t * create_cd_newstate (dfa, nodes, context, hash) re_dfa_t *dfa; const re_node_set *nodes; unsigned int context, hash; { int i, nctx_nodes = 0; reg_errcode_t err; re_dfastate_t *newstate; newstate = create_newstate_common (dfa, nodes, hash); if (BE (newstate == NULL, 0)) return NULL; newstate->context = context; newstate->entrance_nodes = &newstate->nodes; for (i = 0 ; i < nodes->nelem ; i++) { unsigned int constraint = 0; re_token_t *node = dfa->nodes + nodes->elems[i]; re_token_type_t type = node->type; if (node->constraint) constraint = node->constraint; if (type == CHARACTER && !constraint) continue; /* If the state has the halt node, the state is a halt state. */ else if (type == END_OF_RE) newstate->halt = 1; #ifdef RE_ENABLE_I18N else if (type == COMPLEX_BRACKET || (type == OP_PERIOD && MB_CUR_MAX > 1)) newstate->accept_mb = 1; #endif /* RE_ENABLE_I18N */ else if (type == OP_BACK_REF) newstate->has_backref = 1; else if (type == ANCHOR) constraint = node->opr.ctx_type; if (constraint) { if (newstate->entrance_nodes == &newstate->nodes) { newstate->entrance_nodes = re_malloc (re_node_set, 1); if (BE (newstate->entrance_nodes == NULL, 0)) { free_state (newstate); return NULL; } re_node_set_init_copy (newstate->entrance_nodes, nodes); nctx_nodes = 0; newstate->has_constraint = 1; } if (NOT_SATISFY_PREV_CONSTRAINT (constraint,context)) { re_node_set_remove_at (&newstate->nodes, i - nctx_nodes); ++nctx_nodes; } } } err = register_state (dfa, newstate, hash); if (BE (err != REG_NOERROR, 0)) { free_state (newstate); newstate = NULL; } return newstate; } static void free_state (state) re_dfastate_t *state; { if (state->entrance_nodes != &state->nodes) { re_node_set_free (state->entrance_nodes); re_free (state->entrance_nodes); } re_node_set_free (&state->nodes); re_free (state->trtable); re_free (state->trtable_search); re_free (state); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/regex/regex.c��������������������������������������������������������0000644�0000000�0000000�00000005131�12062407372�017454� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Extended regular expression matching and search library. Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef _LIBC /* We have to keep the namespace clean. */ # define regfree(preg) __regfree (preg) # define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) # define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) # define regerror(errcode, preg, errbuf, errbuf_size) \ __regerror(errcode, preg, errbuf, errbuf_size) # define re_set_registers(bu, re, nu, st, en) \ __re_set_registers (bu, re, nu, st, en) # define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ __re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) # define re_match(bufp, string, size, pos, regs) \ __re_match (bufp, string, size, pos, regs) # define re_search(bufp, string, size, startpos, range, regs) \ __re_search (bufp, string, size, startpos, range, regs) # define re_compile_pattern(pattern, length, bufp) \ __re_compile_pattern (pattern, length, bufp) # define re_set_syntax(syntax) __re_set_syntax (syntax) # define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ __re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) # define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) #endif /* POSIX says that <sys/types.h> must be included (by the caller) before <regex.h>. */ #include <sys/types.h> #include <regex.h> #include "regex_internal.h" #include "regex_internal.c" #include "regcomp.c" #include "regexec.c" /* Binary backward compatibility. */ #if _LIBC # include <shlib-compat.h> # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) link_warning (re_max_failures, "the 're_max_failures' variable is obsolete and will go away.") int re_max_failures = 2000; # endif #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/regex/regex_internal.h�����������������������������������������������0000644�0000000�0000000�00000051340�12062407372�021360� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Extended regular expression matching and search library. Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _REGEX_INTERNAL_H #define _REGEX_INTERNAL_H 1 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <assert.h> #include <ctype.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #if defined HAVE_LOCALE_H || defined _LIBC # include <locale.h> #endif #if defined HAVE_WCHAR_H || defined _LIBC # include <wchar.h> #endif /* HAVE_WCHAR_H || _LIBC */ #if defined HAVE_WCTYPE_H || defined _LIBC # include <wctype.h> #endif /* HAVE_WCTYPE_H || _LIBC */ /* In case that the system doesn't have isblank(). */ #if !defined _LIBC && !defined HAVE_ISBLANK && !defined isblank # define isblank(ch) ((ch) == ' ' || (ch) == '\t') #endif #ifdef _LIBC # ifndef _RE_DEFINE_LOCALE_FUNCTIONS # define _RE_DEFINE_LOCALE_FUNCTIONS 1 # include <locale/localeinfo.h> # include <locale/elem-hash.h> # include <locale/coll-lookup.h> # endif #endif /* This is for other GNU distributions with internationalized messages. */ #if HAVE_LIBINTL_H || defined _LIBC # include <libintl.h> # ifdef _LIBC # undef gettext # define gettext(msgid) \ INTUSE(__dcgettext) (INTUSE(_libc_intl_domainname), msgid, LC_MESSAGES) # endif #else # define gettext(msgid) (msgid) #endif #ifndef gettext_noop /* This define is so xgettext can find the internationalizable strings. */ # define gettext_noop(String) String #endif #if (defined MB_CUR_MAX && HAVE_LOCALE_H && HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_WCRTOMB && HAVE_MBRTOWC && HAVE_WCSCOLL) || _LIBC # define RE_ENABLE_I18N #endif #if __GNUC__ >= 3 # define BE(expr, val) __builtin_expect (expr, val) #else # define BE(expr, val) (expr) # define inline #endif /* Number of bits in a byte. */ #define BYTE_BITS 8 /* Number of single byte character. */ #define SBC_MAX 256 #define COLL_ELEM_LEN_MAX 8 /* The character which represents newline. */ #define NEWLINE_CHAR '\n' #define WIDE_NEWLINE_CHAR L'\n' /* Rename to standard API for using out of glibc. */ #ifndef _LIBC # define __wctype wctype # define __iswctype iswctype # define __btowc btowc # define __mempcpy mempcpy # define __wcrtomb wcrtomb # define attribute_hidden #endif /* not _LIBC */ extern const char __re_error_msgid[] attribute_hidden; extern const size_t __re_error_msgid_idx[] attribute_hidden; /* Number of bits in an unsinged int. */ #define UINT_BITS (sizeof (unsigned int) * BYTE_BITS) /* Number of unsigned int in an bit_set. */ #define BITSET_UINTS ((SBC_MAX + UINT_BITS - 1) / UINT_BITS) typedef unsigned int bitset[BITSET_UINTS]; typedef unsigned int *re_bitset_ptr_t; #define bitset_set(set,i) (set[i / UINT_BITS] |= 1 << i % UINT_BITS) #define bitset_clear(set,i) (set[i / UINT_BITS] &= ~(1 << i % UINT_BITS)) #define bitset_contain(set,i) (set[i / UINT_BITS] & (1 << i % UINT_BITS)) #define bitset_empty(set) memset (set, 0, sizeof (unsigned int) * BITSET_UINTS) #define bitset_set_all(set) \ memset (set, 255, sizeof (unsigned int) * BITSET_UINTS) #define bitset_copy(dest,src) \ memcpy (dest, src, sizeof (unsigned int) * BITSET_UINTS) static inline void bitset_not (bitset set); static inline void bitset_merge (bitset dest, const bitset src); static inline void bitset_not_merge (bitset dest, const bitset src); #define PREV_WORD_CONSTRAINT 0x0001 #define PREV_NOTWORD_CONSTRAINT 0x0002 #define NEXT_WORD_CONSTRAINT 0x0004 #define NEXT_NOTWORD_CONSTRAINT 0x0008 #define PREV_NEWLINE_CONSTRAINT 0x0010 #define NEXT_NEWLINE_CONSTRAINT 0x0020 #define PREV_BEGBUF_CONSTRAINT 0x0040 #define NEXT_ENDBUF_CONSTRAINT 0x0080 #define DUMMY_CONSTRAINT 0x0100 typedef enum { INSIDE_WORD = PREV_WORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, WORD_FIRST = PREV_NOTWORD_CONSTRAINT | NEXT_WORD_CONSTRAINT, WORD_LAST = PREV_WORD_CONSTRAINT | NEXT_NOTWORD_CONSTRAINT, LINE_FIRST = PREV_NEWLINE_CONSTRAINT, LINE_LAST = NEXT_NEWLINE_CONSTRAINT, BUF_FIRST = PREV_BEGBUF_CONSTRAINT, BUF_LAST = NEXT_ENDBUF_CONSTRAINT, WORD_DELIM = DUMMY_CONSTRAINT } re_context_type; typedef struct { int alloc; int nelem; int *elems; } re_node_set; typedef enum { NON_TYPE = 0, /* Token type, these are used only by token. */ OP_OPEN_BRACKET, OP_CLOSE_BRACKET, OP_CHARSET_RANGE, OP_OPEN_DUP_NUM, OP_CLOSE_DUP_NUM, OP_NON_MATCH_LIST, OP_OPEN_COLL_ELEM, OP_CLOSE_COLL_ELEM, OP_OPEN_EQUIV_CLASS, OP_CLOSE_EQUIV_CLASS, OP_OPEN_CHAR_CLASS, OP_CLOSE_CHAR_CLASS, OP_WORD, OP_NOTWORD, BACK_SLASH, /* Tree type, these are used only by tree. */ CONCAT, ALT, SUBEXP, SIMPLE_BRACKET, #ifdef RE_ENABLE_I18N COMPLEX_BRACKET, #endif /* RE_ENABLE_I18N */ /* Node type, These are used by token, node, tree. */ OP_OPEN_SUBEXP, OP_CLOSE_SUBEXP, OP_PERIOD, CHARACTER, END_OF_RE, OP_ALT, OP_DUP_ASTERISK, OP_DUP_PLUS, OP_DUP_QUESTION, OP_BACK_REF, ANCHOR, /* Dummy marker. */ END_OF_RE_TOKEN_T } re_token_type_t; #ifdef RE_ENABLE_I18N typedef struct { /* Multibyte characters. */ wchar_t *mbchars; /* Collating symbols. */ # ifdef _LIBC int32_t *coll_syms; # endif /* Equivalence classes. */ # ifdef _LIBC int32_t *equiv_classes; # endif /* Range expressions. */ # ifdef _LIBC uint32_t *range_starts; uint32_t *range_ends; # else /* not _LIBC */ wchar_t *range_starts; wchar_t *range_ends; # endif /* not _LIBC */ /* Character classes. */ wctype_t *char_classes; /* If this character set is the non-matching list. */ unsigned int non_match : 1; /* # of multibyte characters. */ int nmbchars; /* # of collating symbols. */ int ncoll_syms; /* # of equivalence classes. */ int nequiv_classes; /* # of range expressions. */ int nranges; /* # of character classes. */ int nchar_classes; } re_charset_t; #endif /* RE_ENABLE_I18N */ typedef struct { union { unsigned char c; /* for CHARACTER */ re_bitset_ptr_t sbcset; /* for SIMPLE_BRACKET */ #ifdef RE_ENABLE_I18N re_charset_t *mbcset; /* for COMPLEX_BRACKET */ #endif /* RE_ENABLE_I18N */ int idx; /* for BACK_REF */ re_context_type ctx_type; /* for ANCHOR */ } opr; #if __GNUC__ >= 2 re_token_type_t type : 8; #else re_token_type_t type; #endif unsigned int constraint : 10; /* context constraint */ unsigned int duplicated : 1; #ifdef RE_ENABLE_I18N unsigned int mb_partial : 1; #endif } re_token_t; #define IS_EPSILON_NODE(type) \ ((type) == OP_ALT || (type) == OP_DUP_ASTERISK || (type) == OP_DUP_PLUS \ || (type) == OP_DUP_QUESTION || (type) == ANCHOR \ || (type) == OP_OPEN_SUBEXP || (type) == OP_CLOSE_SUBEXP) #define ACCEPT_MB_NODE(type) \ ((type) == COMPLEX_BRACKET || (type) == OP_PERIOD) struct re_string_t { /* Indicate the raw buffer which is the original string passed as an argument of regexec(), re_search(), etc.. */ const unsigned char *raw_mbs; /* Store the multibyte string. In case of "case insensitive mode" like REG_ICASE, upper cases of the string are stored, otherwise MBS points the same address that RAW_MBS points. */ unsigned char *mbs; /* Store the case sensitive multibyte string. In case of "case insensitive mode", the original string are stored, otherwise MBS_CASE points the same address that MBS points. */ unsigned char *mbs_case; #ifdef RE_ENABLE_I18N /* Store the wide character string which is corresponding to MBS. */ wint_t *wcs; mbstate_t cur_state; #endif /* Index in RAW_MBS. Each character mbs[i] corresponds to raw_mbs[raw_mbs_idx + i]. */ int raw_mbs_idx; /* The length of the valid characters in the buffers. */ int valid_len; /* The length of the buffers MBS, MBS_CASE, and WCS. */ int bufs_len; /* The index in MBS, which is updated by re_string_fetch_byte. */ int cur_idx; /* This is length_of_RAW_MBS - RAW_MBS_IDX. */ int len; /* End of the buffer may be shorter than its length in the cases such as re_match_2, re_search_2. Then, we use STOP for end of the buffer instead of LEN. */ int stop; /* The context of mbs[0]. We store the context independently, since the context of mbs[0] may be different from raw_mbs[0], which is the beginning of the input string. */ unsigned int tip_context; /* The translation passed as a part of an argument of re_compile_pattern. */ RE_TRANSLATE_TYPE trans; /* 1 if REG_ICASE. */ unsigned int icase : 1; }; typedef struct re_string_t re_string_t; /* In case of REG_ICASE, we allocate the buffer dynamically for mbs. */ #define MBS_ALLOCATED(pstr) (pstr->icase) /* In case that we need translation, we allocate the buffer dynamically for mbs_case. Note that mbs == mbs_case if not REG_ICASE. */ #define MBS_CASE_ALLOCATED(pstr) (pstr->trans != NULL) static reg_errcode_t re_string_allocate (re_string_t *pstr, const char *str, int len, int init_len, RE_TRANSLATE_TYPE trans, int icase); static reg_errcode_t re_string_construct (re_string_t *pstr, const char *str, int len, RE_TRANSLATE_TYPE trans, int icase); static reg_errcode_t re_string_reconstruct (re_string_t *pstr, int idx, int eflags, int newline); static reg_errcode_t re_string_realloc_buffers (re_string_t *pstr, int new_buf_len); #ifdef RE_ENABLE_I18N static void build_wcs_buffer (re_string_t *pstr); static void build_wcs_upper_buffer (re_string_t *pstr); #endif /* RE_ENABLE_I18N */ static void build_upper_buffer (re_string_t *pstr); static void re_string_translate_buffer (re_string_t *pstr); static void re_string_destruct (re_string_t *pstr); #ifdef RE_ENABLE_I18N static int re_string_elem_size_at (const re_string_t *pstr, int idx); static inline int re_string_char_size_at (const re_string_t *pstr, int idx); static inline wint_t re_string_wchar_at (const re_string_t *pstr, int idx); #endif /* RE_ENABLE_I18N */ static unsigned int re_string_context_at (const re_string_t *input, int idx, int eflags, int newline_anchor); #define re_string_peek_byte(pstr, offset) \ ((pstr)->mbs[(pstr)->cur_idx + offset]) #define re_string_peek_byte_case(pstr, offset) \ ((pstr)->mbs_case[(pstr)->cur_idx + offset]) #define re_string_fetch_byte(pstr) \ ((pstr)->mbs[(pstr)->cur_idx++]) #define re_string_fetch_byte_case(pstr) \ ((pstr)->mbs_case[(pstr)->cur_idx++]) #define re_string_first_byte(pstr, idx) \ ((idx) == (pstr)->len || (pstr)->wcs[idx] != WEOF) #define re_string_is_single_byte_char(pstr, idx) \ ((pstr)->wcs[idx] != WEOF && ((pstr)->len == (idx) \ || (pstr)->wcs[(idx) + 1] != WEOF)) #define re_string_eoi(pstr) ((pstr)->stop <= (pstr)->cur_idx) #define re_string_cur_idx(pstr) ((pstr)->cur_idx) #define re_string_get_buffer(pstr) ((pstr)->mbs) #define re_string_length(pstr) ((pstr)->len) #define re_string_byte_at(pstr,idx) ((pstr)->mbs[idx]) #define re_string_skip_bytes(pstr,idx) ((pstr)->cur_idx += (idx)) #define re_string_set_index(pstr,idx) ((pstr)->cur_idx = (idx)) #define re_malloc(t,n) ((t *) malloc ((n) * sizeof (t))) #define re_realloc(p,t,n) ((t *) realloc (p, (n) * sizeof (t))) #define re_free(p) free (p) struct bin_tree_t { struct bin_tree_t *parent; struct bin_tree_t *left; struct bin_tree_t *right; /* `node_idx' is the index in dfa->nodes, if `type' == 0. Otherwise `type' indicate the type of this node. */ re_token_type_t type; int node_idx; int first; int next; re_node_set eclosure; }; typedef struct bin_tree_t bin_tree_t; #define CONTEXT_WORD 1 #define CONTEXT_NEWLINE (CONTEXT_WORD << 1) #define CONTEXT_BEGBUF (CONTEXT_NEWLINE << 1) #define CONTEXT_ENDBUF (CONTEXT_BEGBUF << 1) #define IS_WORD_CONTEXT(c) ((c) & CONTEXT_WORD) #define IS_NEWLINE_CONTEXT(c) ((c) & CONTEXT_NEWLINE) #define IS_BEGBUF_CONTEXT(c) ((c) & CONTEXT_BEGBUF) #define IS_ENDBUF_CONTEXT(c) ((c) & CONTEXT_ENDBUF) #define IS_ORDINARY_CONTEXT(c) ((c) == 0) #define IS_WORD_CHAR(ch) (isalnum (ch) || (ch) == '_') #define IS_NEWLINE(ch) ((ch) == NEWLINE_CHAR) #define IS_WIDE_WORD_CHAR(ch) (iswalnum (ch) || (ch) == L'_') #define IS_WIDE_NEWLINE(ch) ((ch) == WIDE_NEWLINE_CHAR) #define NOT_SATISFY_PREV_CONSTRAINT(constraint,context) \ ((((constraint) & PREV_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ || ((constraint & PREV_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ || ((constraint & PREV_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context))\ || ((constraint & PREV_BEGBUF_CONSTRAINT) && !IS_BEGBUF_CONTEXT (context))) #define NOT_SATISFY_NEXT_CONSTRAINT(constraint,context) \ ((((constraint) & NEXT_WORD_CONSTRAINT) && !IS_WORD_CONTEXT (context)) \ || (((constraint) & NEXT_NOTWORD_CONSTRAINT) && IS_WORD_CONTEXT (context)) \ || (((constraint) & NEXT_NEWLINE_CONSTRAINT) && !IS_NEWLINE_CONTEXT (context)) \ || (((constraint) & NEXT_ENDBUF_CONSTRAINT) && !IS_ENDBUF_CONTEXT (context))) struct re_dfastate_t { unsigned int hash; re_node_set nodes; re_node_set *entrance_nodes; struct re_dfastate_t **trtable; struct re_dfastate_t **trtable_search; /* If this state is a special state. A state is a special state if the state is the halt state, or a anchor. */ unsigned int context : 2; unsigned int halt : 1; /* If this state can accept `multi byte'. Note that we refer to multibyte characters, and multi character collating elements as `multi byte'. */ unsigned int accept_mb : 1; /* If this state has backreference node(s). */ unsigned int has_backref : 1; unsigned int has_constraint : 1; }; typedef struct re_dfastate_t re_dfastate_t; typedef struct { /* start <= node < end */ int start; int end; } re_subexp_t; struct re_state_table_entry { int num; int alloc; re_dfastate_t **array; }; /* Array type used in re_sub_match_last_t and re_sub_match_top_t. */ typedef struct { int next_idx; int alloc; re_dfastate_t **array; } state_array_t; /* Store information about the node NODE whose type is OP_CLOSE_SUBEXP. */ typedef struct { int node; int str_idx; /* The position NODE match at. */ state_array_t path; } re_sub_match_last_t; /* Store information about the node NODE whose type is OP_OPEN_SUBEXP. And information about the node, whose type is OP_CLOSE_SUBEXP, corresponding to NODE is stored in LASTS. */ typedef struct { int str_idx; int node; int next_last_offset; state_array_t *path; int alasts; /* Allocation size of LASTS. */ int nlasts; /* The number of LASTS. */ re_sub_match_last_t **lasts; } re_sub_match_top_t; struct re_backref_cache_entry { int node; int str_idx; int subexp_from; int subexp_to; int flag; }; typedef struct { /* EFLAGS of the argument of regexec. */ int eflags; /* Where the matching ends. */ int match_last; int last_node; /* The string object corresponding to the input string. */ re_string_t *input; /* The state log used by the matcher. */ re_dfastate_t **state_log; int state_log_top; /* Back reference cache. */ int nbkref_ents; int abkref_ents; struct re_backref_cache_entry *bkref_ents; int max_mb_elem_len; int nsub_tops; int asub_tops; re_sub_match_top_t **sub_tops; } re_match_context_t; typedef struct { int cur_bkref; int cls_subexp_idx; re_dfastate_t **sifted_states; re_dfastate_t **limited_states; re_node_set limits; int last_node; int last_str_idx; int check_subexp; } re_sift_context_t; struct re_fail_stack_ent_t { int idx; int node; regmatch_t *regs; re_node_set eps_via_nodes; }; struct re_fail_stack_t { int num; int alloc; struct re_fail_stack_ent_t *stack; }; struct re_dfa_t { re_bitset_ptr_t word_char; /* number of subexpressions `re_nsub' is in regex_t. */ int subexps_alloc; re_subexp_t *subexps; re_token_t *nodes; int nodes_alloc; int nodes_len; bin_tree_t *str_tree; int *nexts; int *org_indices; re_node_set *edests; re_node_set *eclosures; re_node_set *inveclosures; struct re_state_table_entry *state_table; unsigned int state_hash_mask; re_dfastate_t *init_state; re_dfastate_t *init_state_word; re_dfastate_t *init_state_nl; re_dfastate_t *init_state_begbuf; int states_alloc; int init_node; int nbackref; /* The number of backreference in this dfa. */ /* Bitmap expressing which backreference is used. */ unsigned int used_bkref_map; #ifdef DEBUG char* re_str; #endif unsigned int has_plural_match : 1; /* If this dfa has "multibyte node", which is a backreference or a node which can accept multibyte character or multi character collating element. */ unsigned int has_mb_node : 1; }; typedef struct re_dfa_t re_dfa_t; static reg_errcode_t re_node_set_alloc (re_node_set *set, int size); static reg_errcode_t re_node_set_init_1 (re_node_set *set, int elem); static reg_errcode_t re_node_set_init_2 (re_node_set *set, int elem1, int elem2); #define re_node_set_init_empty(set) memset (set, '\0', sizeof (re_node_set)) static reg_errcode_t re_node_set_init_copy (re_node_set *dest, const re_node_set *src); static reg_errcode_t re_node_set_add_intersect (re_node_set *dest, const re_node_set *src1, const re_node_set *src2); static reg_errcode_t re_node_set_init_union (re_node_set *dest, const re_node_set *src1, const re_node_set *src2); static reg_errcode_t re_node_set_merge (re_node_set *dest, const re_node_set *src); static int re_node_set_insert (re_node_set *set, int elem); static int re_node_set_compare (const re_node_set *set1, const re_node_set *set2); static int re_node_set_contains (const re_node_set *set, int elem); static void re_node_set_remove_at (re_node_set *set, int idx); #define re_node_set_remove(set,id) \ (re_node_set_remove_at (set, re_node_set_contains (set, id) - 1)) #define re_node_set_empty(p) ((p)->nelem = 0) #define re_node_set_free(set) re_free ((set)->elems) static int re_dfa_add_node (re_dfa_t *dfa, re_token_t token, int mode); static re_dfastate_t *re_acquire_state (reg_errcode_t *err, re_dfa_t *dfa, const re_node_set *nodes); static re_dfastate_t *re_acquire_state_context (reg_errcode_t *err, re_dfa_t *dfa, const re_node_set *nodes, unsigned int context); static void free_state (re_dfastate_t *state); typedef enum { SB_CHAR, MB_CHAR, EQUIV_CLASS, COLL_SYM, CHAR_CLASS } bracket_elem_type; typedef struct { bracket_elem_type type; union { unsigned char ch; unsigned char *name; wchar_t wch; } opr; } bracket_elem_t; /* Inline functions for bitset operation. */ static inline void bitset_not (set) bitset set; { int bitset_i; for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) set[bitset_i] = ~set[bitset_i]; } static inline void bitset_merge (dest, src) bitset dest; const bitset src; { int bitset_i; for (bitset_i = 0; bitset_i < BITSET_UINTS; ++bitset_i) dest[bitset_i] |= src[bitset_i]; } static inline void bitset_not_merge (dest, src) bitset dest; const bitset src; { int i; for (i = 0; i < BITSET_UINTS; ++i) dest[i] |= ~src[i]; } #ifdef RE_ENABLE_I18N /* Inline functions for re_string. */ static inline int re_string_char_size_at (pstr, idx) const re_string_t *pstr; int idx; { int byte_idx; if (MB_CUR_MAX == 1) return 1; for (byte_idx = 1; idx + byte_idx < pstr->len; ++byte_idx) if (pstr->wcs[idx + byte_idx] != WEOF) break; return byte_idx; } static inline wint_t re_string_wchar_at (pstr, idx) const re_string_t *pstr; int idx; { if (MB_CUR_MAX == 1) return (wint_t) pstr->mbs[idx]; return (wint_t) pstr->wcs[idx]; } static int re_string_elem_size_at (pstr, idx) const re_string_t *pstr; int idx; { #ifdef _LIBC const unsigned char *p, *extra; const int32_t *table, *indirect; int32_t tmp; # include <locale/weight.h> uint_fast32_t nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); if (nrules != 0) { table = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); extra = (const unsigned char *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); indirect = (const int32_t *) _NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); p = pstr->mbs + idx; tmp = findidx (&p); return p - pstr->mbs - idx; } else #endif /* _LIBC */ return 1; } #endif /* RE_ENABLE_I18N */ #endif /* _REGEX_INTERNAL_H */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/atacmds.cpp����������������������������������������������������������0000644�0000000�0000000�00000302052�12166107121�017200� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * atacmds.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> #include <ctype.h> #include "config.h" #include "int64.h" #include "atacmds.h" #include "utility.h" #include "dev_ata_cmd_set.h" // for parsed_ata_device const char * atacmds_cpp_cvsid = "$Id: atacmds.cpp 3825 2013-07-06 21:38:25Z samm2 $" ATACMDS_H_CVSID; // Print ATA debug messages? unsigned char ata_debugmode = 0; // Suppress serial number? // (also used in scsiprint.cpp) bool dont_print_serial_number = false; #define SMART_CYL_LOW 0x4F #define SMART_CYL_HI 0xC2 // SMART RETURN STATUS yields SMART_CYL_HI,SMART_CYL_LOW to indicate drive // is healthy and SRET_STATUS_HI_EXCEEDED,SRET_STATUS_MID_EXCEEDED to // indicate that a threshhold exceeded condition has been detected. // Those values (byte pairs) are placed in ATA register "LBA 23:8". #define SRET_STATUS_HI_EXCEEDED 0x2C #define SRET_STATUS_MID_EXCEEDED 0xF4 // Get ID and increase flag of current pending or offline // uncorrectable attribute. unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs & defs, bool & increase) { unsigned char id = (!offline ? 197 : 198); const ata_vendor_attr_defs::entry & def = defs[id]; if (def.flags & ATTRFLAG_INCREASING) increase = true; // '-v 19[78],increasing' option else if (def.name.empty() || (id == 198 && def.name == "Offline_Scan_UNC_SectCt")) increase = false; // no or '-v 198,offlinescanuncsectorct' option else id = 0; // other '-v 19[78],...' option return id; } #if 0 // TODO: never used // This are the meanings of the Self-test failure checkpoint byte. // This is in the self-test log at offset 4 bytes into the self-test // descriptor and in the SMART READ DATA structure at byte offset // 371. These codes are not well documented. The meanings returned by // this routine are used (at least) by Maxtor and IBM. Returns NULL if // not recognized. Currently the maximum length is 15 bytes. const char *SelfTestFailureCodeName(unsigned char which){ switch (which) { case 0: return "Write_Test"; case 1: return "Servo_Basic"; case 2: return "Servo_Random"; case 3: return "G-list_Scan"; case 4: return "Handling_Damage"; case 5: return "Read_Scan"; default: return NULL; } } #endif // Table of raw print format names struct format_name_entry { const char * name; ata_attr_raw_format format; }; const format_name_entry format_names[] = { {"raw8" , RAWFMT_RAW8}, {"raw16" , RAWFMT_RAW16}, {"raw48" , RAWFMT_RAW48}, {"hex48" , RAWFMT_HEX48}, {"raw56" , RAWFMT_RAW56}, {"hex56" , RAWFMT_HEX56}, {"raw64" , RAWFMT_RAW64}, {"hex64" , RAWFMT_HEX64}, {"raw16(raw16)" , RAWFMT_RAW16_OPT_RAW16}, {"raw16(avg16)" , RAWFMT_RAW16_OPT_AVG16}, {"raw24(raw8)" , RAWFMT_RAW24_OPT_RAW8}, {"raw24/raw24" , RAWFMT_RAW24_DIV_RAW24}, {"raw24/raw32" , RAWFMT_RAW24_DIV_RAW32}, {"sec2hour" , RAWFMT_SEC2HOUR}, {"min2hour" , RAWFMT_MIN2HOUR}, {"halfmin2hour" , RAWFMT_HALFMIN2HOUR}, {"msec24hour32" , RAWFMT_MSEC24_HOUR32}, {"tempminmax" , RAWFMT_TEMPMINMAX}, {"temp10x" , RAWFMT_TEMP10X}, }; const unsigned num_format_names = sizeof(format_names)/sizeof(format_names[0]); // Table to map old to new '-v' option arguments const char * map_old_vendor_opts[][2] = { { "9,halfminutes" , "9,halfmin2hour,Power_On_Half_Minutes"}, { "9,minutes" , "9,min2hour,Power_On_Minutes"}, { "9,seconds" , "9,sec2hour,Power_On_Seconds"}, { "9,temp" , "9,tempminmax,Temperature_Celsius"}, {"192,emergencyretractcyclect" , "192,raw48,Emerg_Retract_Cycle_Ct"}, {"193,loadunload" , "193,raw24/raw24"}, {"194,10xCelsius" , "194,temp10x,Temperature_Celsius_x10"}, {"194,unknown" , "194,raw48,Unknown_Attribute"}, {"197,increasing" , "197,raw48+,Total_Pending_Sectors"}, // '+' sets flag {"198,offlinescanuncsectorct" , "198,raw48,Offline_Scan_UNC_SectCt"}, // see also get_unc_attr_id() above {"198,increasing" , "198,raw48+,Total_Offl_Uncorrectabl"}, // '+' sets flag {"200,writeerrorcount" , "200,raw48,Write_Error_Count"}, {"201,detectedtacount" , "201,raw48,Detected_TA_Count"}, {"220,temp" , "220,tempminmax,Temperature_Celsius"}, }; const unsigned num_old_vendor_opts = sizeof(map_old_vendor_opts)/sizeof(map_old_vendor_opts[0]); // Parse vendor attribute display def (-v option). // Return false on error. bool parse_attribute_def(const char * opt, ata_vendor_attr_defs & defs, ata_vendor_def_prior priority) { // Map old -> new options unsigned i; for (i = 0; i < num_old_vendor_opts; i++) { if (!strcmp(opt, map_old_vendor_opts[i][0])) { opt = map_old_vendor_opts[i][1]; break; } } // Parse option int len = strlen(opt); int id = 0, n1 = -1, n2 = -1; char fmtname[32+1], attrname[32+1]; if (opt[0] == 'N') { // "N,format" if (!( sscanf(opt, "N,%32[^,]%n,%32[^,]%n", fmtname, &n1, attrname, &n2) >= 1 && (n1 == len || n2 == len))) return false; } else { // "id,format[+][,name]" if (!( sscanf(opt, "%d,%32[^,]%n,%32[^,]%n", &id, fmtname, &n1, attrname, &n2) >= 2 && 1 <= id && id <= 255 && (n1 == len || n2 == len))) return false; } if (n1 == len) attrname[0] = 0; unsigned flags = 0; // For "-v 19[78],increasing" above if (fmtname[strlen(fmtname)-1] == '+') { fmtname[strlen(fmtname)-1] = 0; flags = ATTRFLAG_INCREASING; } // Split "format[:byteorder]" char byteorder[8+1] = ""; if (strchr(fmtname, ':')) { if (!( sscanf(fmtname, "%*[^:]%n:%8[012345rvwz]%n", &n1, byteorder, &n2) >= 1 && n2 == (int)strlen(fmtname))) return false; fmtname[n1] = 0; if (strchr(byteorder, 'v')) flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL); if (strchr(byteorder, 'w')) flags |= ATTRFLAG_NO_WORSTVAL; } // Find format name for (i = 0; ; i++) { if (i >= num_format_names) return false; // Not found if (!strcmp(fmtname, format_names[i].name)) break; } ata_attr_raw_format format = format_names[i].format; // 64-bit formats use the normalized and worst value bytes. if (!*byteorder && (format == RAWFMT_RAW64 || format == RAWFMT_HEX64)) flags |= (ATTRFLAG_NO_NORMVAL|ATTRFLAG_NO_WORSTVAL); if (!id) { // "N,format" -> set format for all entries for (i = 0; i < MAX_ATTRIBUTE_NUM; i++) { if (defs[i].priority >= priority) continue; if (attrname[0]) defs[i].name = attrname; defs[i].priority = priority; defs[i].raw_format = format; defs[i].flags = flags; snprintf(defs[i].byteorder, sizeof(defs[i].byteorder), "%s", byteorder); } } else if (defs[id].priority <= priority) { // "id,format[,name]" if (attrname[0]) defs[id].name = attrname; defs[id].raw_format = format; defs[id].priority = priority; defs[id].flags = flags; snprintf(defs[id].byteorder, sizeof(defs[id].byteorder), "%s", byteorder); } return true; } // Return a multiline string containing a list of valid arguments for // parse_attribute_def(). The strings are preceeded by tabs and followed // (except for the last) by newlines. std::string create_vendor_attribute_arg_list() { std::string s; unsigned i; for (i = 0; i < num_format_names; i++) s += strprintf("%s\tN,%s[:012345rvwz][,ATTR_NAME]", (i>0 ? "\n" : ""), format_names[i].name); for (i = 0; i < num_old_vendor_opts; i++) s += strprintf("\n\t%s", map_old_vendor_opts[i][0]); return s; } // Parse firmwarebug def (-F option). // Return false on error. bool parse_firmwarebug_def(const char * opt, firmwarebug_defs & firmwarebugs) { if (!strcmp(opt, "none")) firmwarebugs.set(BUG_NONE); else if (!strcmp(opt, "nologdir")) firmwarebugs.set(BUG_NOLOGDIR); else if (!strcmp(opt, "samsung")) firmwarebugs.set(BUG_SAMSUNG); else if (!strcmp(opt, "samsung2")) firmwarebugs.set(BUG_SAMSUNG2); else if (!strcmp(opt, "samsung3")) firmwarebugs.set(BUG_SAMSUNG3); else if (!strcmp(opt, "xerrorlba")) firmwarebugs.set(BUG_XERRORLBA); else return false; return true; } // Return a string of valid argument words for parse_firmwarebug_def() const char * get_valid_firmwarebug_args() { return "none, nologdir, samsung, samsung2, samsung3, xerrorlba"; } // swap two bytes. Point to low address void swap2(char *location){ char tmp=*location; *location=*(location+1); *(location+1)=tmp; return; } // swap four bytes. Point to low address void swap4(char *location){ char tmp=*location; *location=*(location+3); *(location+3)=tmp; swap2(location+1); return; } // swap eight bytes. Points to low address void swap8(char *location){ char tmp=*location; *location=*(location+7); *(location+7)=tmp; tmp=*(location+1); *(location+1)=*(location+6); *(location+6)=tmp; swap4(location+2); return; } // Invalidate serial number and WWN and adjust checksum in IDENTIFY data static void invalidate_serno(ata_identify_device * id) { unsigned char sum = 0; unsigned i; for (i = 0; i < sizeof(id->serial_no); i++) { sum += id->serial_no[i]; sum -= id->serial_no[i] = 'X'; } unsigned char * b = (unsigned char *)id; for (i = 2*108; i < 2*112; i++) { // words108-111: WWN sum += b[i]; sum -= b[i] = 0x00; } #ifndef __NetBSD__ bool must_swap = !!isbigendian(); if (must_swap) swapx(id->words088_255+255-88); #endif if ((id->words088_255[255-88] & 0x00ff) == 0x00a5) id->words088_255[255-88] += sum << 8; #ifndef __NetBSD__ if (must_swap) swapx(id->words088_255+255-88); #endif } static const char * const commandstrings[]={ "SMART ENABLE", "SMART DISABLE", "SMART AUTOMATIC ATTRIBUTE SAVE", "SMART IMMEDIATE OFFLINE", "SMART AUTO OFFLINE", "SMART STATUS", "SMART STATUS CHECK", "SMART READ ATTRIBUTE VALUES", "SMART READ ATTRIBUTE THRESHOLDS", "SMART READ LOG", "IDENTIFY DEVICE", "IDENTIFY PACKET DEVICE", "CHECK POWER MODE", "SMART WRITE LOG", "WARNING (UNDEFINED COMMAND -- CONTACT DEVELOPERS AT " PACKAGE_BUGREPORT ")\n" }; static const char * preg(const ata_register & r, char (& buf)[8]) { if (!r.is_set()) //return "n/a "; return "...."; snprintf(buf, sizeof(buf), "0x%02x", r.val()); return buf; } static void print_regs(const char * prefix, const ata_in_regs & r, const char * suffix = "\n") { char bufs[7][8]; pout("%s FR=%s, SC=%s, LL=%s, LM=%s, LH=%s, DEV=%s, CMD=%s%s", prefix, preg(r.features, bufs[0]), preg(r.sector_count, bufs[1]), preg(r.lba_low, bufs[2]), preg(r.lba_mid, bufs[3]), preg(r.lba_high, bufs[4]), preg(r.device, bufs[5]), preg(r.command, bufs[6]), suffix); } static void print_regs(const char * prefix, const ata_out_regs & r, const char * suffix = "\n") { char bufs[7][8]; pout("%sERR=%s, SC=%s, LL=%s, LM=%s, LH=%s, DEV=%s, STS=%s%s", prefix, preg(r.error, bufs[0]), preg(r.sector_count, bufs[1]), preg(r.lba_low, bufs[2]), preg(r.lba_mid, bufs[3]), preg(r.lba_high, bufs[4]), preg(r.device, bufs[5]), preg(r.status, bufs[6]), suffix); } static void prettyprint(const unsigned char *p, const char *name){ pout("\n===== [%s] DATA START (BASE-16) =====\n", name); for (int i=0; i<512; i+=16, p+=16) #define P(n) (' ' <= p[n] && p[n] <= '~' ? (int)p[n] : '.') // print complete line to avoid slow tty output and extra lines in syslog. pout("%03d-%03d: %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x" " |%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c|" "%c", i, i+16-1, p[ 0], p[ 1], p[ 2], p[ 3], p[ 4], p[ 5], p[ 6], p[ 7], p[ 8], p[ 9], p[10], p[11], p[12], p[13], p[14], p[15], P( 0), P( 1), P( 2), P( 3), P( 4), P( 5), P( 6), P( 7), P( 8), P( 9), P(10), P(11), P(12), P(13), P(14), P(15), '\n'); #undef P pout("===== [%s] DATA END (512 Bytes) =====\n\n", name); } // This function provides the pretty-print reporting for SMART // commands: it implements the various -r "reporting" options for ATA // ioctls. int smartcommandhandler(ata_device * device, smart_command_set command, int select, char *data){ // TODO: Rework old stuff below // This conditional is true for commands that return data int getsdata=(command==PIDENTIFY || command==IDENTIFY || command==READ_LOG || command==READ_THRESHOLDS || command==READ_VALUES || command==CHECK_POWER_MODE); int sendsdata=(command==WRITE_LOG); // If reporting is enabled, say what the command will be before it's executed if (ata_debugmode) { // conditional is true for commands that use parameters int usesparam=(command==READ_LOG || command==AUTO_OFFLINE || command==AUTOSAVE || command==IMMEDIATE_OFFLINE || command==WRITE_LOG); pout("\nREPORT-IOCTL: Device=%s Command=%s", device->get_dev_name(), commandstrings[command]); if (usesparam) pout(" InputParameter=%d\n", select); else pout("\n"); } if ((getsdata || sendsdata) && !data){ pout("REPORT-IOCTL: Unable to execute command %s : data destination address is NULL\n", commandstrings[command]); return -1; } // The reporting is cleaner, and we will find coding bugs faster, if // the commands that failed clearly return empty (zeroed) data // structures if (getsdata) { if (command==CHECK_POWER_MODE) data[0]=0; else memset(data, '\0', 512); } // if requested, pretty-print the input data structure if (ata_debugmode > 1 && sendsdata) //pout("REPORT-IOCTL: Device=%s Command=%s\n", device->get_dev_name(), commandstrings[command]); prettyprint((unsigned char *)data, commandstrings[command]); // now execute the command int retval = -1; { ata_cmd_in in; // Set common register values switch (command) { default: // SMART commands in.in_regs.command = ATA_SMART_CMD; in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW; break; case IDENTIFY: case PIDENTIFY: case CHECK_POWER_MODE: // Non SMART commands break; } // Set specific values switch (command) { case IDENTIFY: in.in_regs.command = ATA_IDENTIFY_DEVICE; in.set_data_in(data, 1); break; case PIDENTIFY: in.in_regs.command = ATA_IDENTIFY_PACKET_DEVICE; in.set_data_in(data, 1); break; case CHECK_POWER_MODE: in.in_regs.command = ATA_CHECK_POWER_MODE; in.out_needed.sector_count = true; // Powermode returned here break; case READ_VALUES: in.in_regs.features = ATA_SMART_READ_VALUES; in.set_data_in(data, 1); break; case READ_THRESHOLDS: in.in_regs.features = ATA_SMART_READ_THRESHOLDS; in.in_regs.lba_low = 1; // TODO: CORRECT ??? in.set_data_in(data, 1); break; case READ_LOG: in.in_regs.features = ATA_SMART_READ_LOG_SECTOR; in.in_regs.lba_low = select; in.set_data_in(data, 1); break; case WRITE_LOG: in.in_regs.features = ATA_SMART_WRITE_LOG_SECTOR; in.in_regs.lba_low = select; in.set_data_out(data, 1); break; case ENABLE: in.in_regs.features = ATA_SMART_ENABLE; in.in_regs.lba_low = 1; // TODO: CORRECT ??? break; case DISABLE: in.in_regs.features = ATA_SMART_DISABLE; in.in_regs.lba_low = 1; // TODO: CORRECT ??? break; case STATUS_CHECK: in.out_needed.lba_high = in.out_needed.lba_mid = true; // Status returned here case STATUS: in.in_regs.features = ATA_SMART_STATUS; break; case AUTO_OFFLINE: in.in_regs.features = ATA_SMART_AUTO_OFFLINE; in.in_regs.sector_count = select; // Caution: Non-DATA command! break; case AUTOSAVE: in.in_regs.features = ATA_SMART_AUTOSAVE; in.in_regs.sector_count = select; // Caution: Non-DATA command! break; case IMMEDIATE_OFFLINE: in.in_regs.features = ATA_SMART_IMMEDIATE_OFFLINE; in.in_regs.lba_low = select; break; default: pout("Unrecognized command %d in smartcommandhandler()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); device->set_err(ENOSYS); return -1; } if (ata_debugmode) print_regs(" Input: ", in.in_regs, (in.direction==ata_cmd_in::data_in ? " IN\n": in.direction==ata_cmd_in::data_out ? " OUT\n":"\n")); ata_cmd_out out; int64_t start_usec = -1; if (ata_debugmode) start_usec = smi()->get_timer_usec(); bool ok = device->ata_pass_through(in, out); if (start_usec >= 0) { int64_t duration_usec = smi()->get_timer_usec() - start_usec; if (duration_usec >= 500) pout(" [Duration: %.3fs]\n", duration_usec / 1000000.0); } if (ata_debugmode && out.out_regs.is_set()) print_regs(" Output: ", out.out_regs); if (ok) switch (command) { default: retval = 0; break; case CHECK_POWER_MODE: if (out.out_regs.sector_count.is_set()) { data[0] = out.out_regs.sector_count; retval = 0; } else { pout("CHECK POWER MODE: incomplete response, ATA output registers missing\n"); device->set_err(ENOSYS); retval = -1; } break; case STATUS_CHECK: // Cyl low and Cyl high unchanged means "Good SMART status" if ((out.out_regs.lba_high == SMART_CYL_HI) && (out.out_regs.lba_mid == SMART_CYL_LOW)) retval = 0; // These values mean "Bad SMART status" else if ((out.out_regs.lba_high == SRET_STATUS_HI_EXCEEDED) && (out.out_regs.lba_mid == SRET_STATUS_MID_EXCEEDED)) retval = 1; else if (out.out_regs.lba_mid == SMART_CYL_LOW) { retval = 0; if (ata_debugmode) pout("SMART STATUS RETURN: half healthy response sequence, " "probable SAT/USB truncation\n"); } else if (out.out_regs.lba_mid == SRET_STATUS_MID_EXCEEDED) { retval = 1; if (ata_debugmode) pout("SMART STATUS RETURN: half unhealthy response sequence, " "probable SAT/USB truncation\n"); } else if (!out.out_regs.is_set()) { pout("SMART STATUS RETURN: incomplete response, ATA output registers missing\n"); device->set_err(ENOSYS); retval = -1; } else { // We haven't gotten output that makes sense; print out some debugging info pout("SMART Status command failed\n"); pout("Please get assistance from %s\n", PACKAGE_HOMEPAGE); pout("Register values returned from SMART Status command are:\n"); print_regs(" ", out.out_regs); device->set_err(EIO); retval = -1; } break; } } // If requested, invalidate serial number before any printing is done if ((command == IDENTIFY || command == PIDENTIFY) && !retval && dont_print_serial_number) invalidate_serno((ata_identify_device *)data); // If reporting is enabled, say what output was produced by the command if (ata_debugmode) { if (device->get_errno()) pout("REPORT-IOCTL: Device=%s Command=%s returned %d errno=%d [%s]\n", device->get_dev_name(), commandstrings[command], retval, device->get_errno(), device->get_errmsg()); else pout("REPORT-IOCTL: Device=%s Command=%s returned %d\n", device->get_dev_name(), commandstrings[command], retval); // if requested, pretty-print the output data structure if (ata_debugmode > 1 && getsdata) { if (command==CHECK_POWER_MODE) pout("Sector Count Register (BASE-16): %02x\n", (unsigned char)(*data)); else prettyprint((unsigned char *)data, commandstrings[command]); } } return retval; } // Get capacity and sector sizes from IDENTIFY data void ata_get_size_info(const ata_identify_device * id, ata_size_info & sizes) { sizes.sectors = sizes.capacity = 0; sizes.log_sector_size = sizes.phy_sector_size = 0; sizes.log_sector_offset = 0; // Return if no LBA support if (!(id->words047_079[49-47] & 0x0200)) return; // Determine 28-bit LBA capacity unsigned lba28 = (unsigned)id->words047_079[61-47] << 16 | (unsigned)id->words047_079[60-47] ; // Determine 48-bit LBA capacity if supported uint64_t lba48 = 0; if ((id->command_set_2 & 0xc400) == 0x4400) lba48 = (uint64_t)id->words088_255[103-88] << 48 | (uint64_t)id->words088_255[102-88] << 32 | (uint64_t)id->words088_255[101-88] << 16 | (uint64_t)id->words088_255[100-88] ; // Return if capacity unknown (ATAPI CD/DVD) if (!(lba28 || lba48)) return; // Determine sector sizes sizes.log_sector_size = sizes.phy_sector_size = 512; unsigned short word106 = id->words088_255[106-88]; if ((word106 & 0xc000) == 0x4000) { // Long Logical/Physical Sectors (LLS/LPS) ? if (word106 & 0x1000) // Logical sector size is specified in 16-bit words sizes.log_sector_size = sizes.phy_sector_size = ((id->words088_255[118-88] << 16) | id->words088_255[117-88]) << 1; if (word106 & 0x2000) // Physical sector size is multiple of logical sector size sizes.phy_sector_size <<= (word106 & 0x0f); unsigned short word209 = id->words088_255[209-88]; if ((word209 & 0xc000) == 0x4000) sizes.log_sector_offset = (word209 & 0x3fff) * sizes.log_sector_size; } // Some early 4KiB LLS disks (Samsung N3U-3) return bogus lba28 value if (lba48 >= lba28 || (lba48 && sizes.log_sector_size > 512)) sizes.sectors = lba48; else sizes.sectors = lba28; sizes.capacity = sizes.sectors * sizes.log_sector_size; } // This function computes the checksum of a single disk sector (512 // bytes). Returns zero if checksum is OK, nonzero if the checksum is // incorrect. The size (512) is correct for all SMART structures. unsigned char checksum(const void * data) { unsigned char sum = 0; for (int i = 0; i < 512; i++) sum += ((const unsigned char *)data)[i]; return sum; } // Copies n bytes (or n-1 if n is odd) from in to out, but swaps adjacents // bytes. static void swapbytes(char * out, const char * in, size_t n) { for (size_t i = 0; i < n; i += 2) { out[i] = in[i+1]; out[i+1] = in[i]; } } // Copies in to out, but removes leading and trailing whitespace. static void trim(char * out, const char * in) { // Find the first non-space character (maybe none). int first = -1; int i; for (i = 0; in[i]; i++) if (!isspace((int)in[i])) { first = i; break; } if (first == -1) { // There are no non-space characters. out[0] = '\0'; return; } // Find the last non-space character. for (i = strlen(in)-1; i >= first && isspace((int)in[i]); i--) ; int last = i; strncpy(out, in+first, last-first+1); out[last-first+1] = '\0'; } // Convenience function for formatting strings from ata_identify_device void ata_format_id_string(char * out, const unsigned char * in, int n) { bool must_swap = true; #ifdef __NetBSD__ /* NetBSD kernel delivers IDENTIFY data in host byte order (but all else is LE) */ // TODO: Handle NetBSD case in os_netbsd.cpp if (isbigendian()) must_swap = !must_swap; #endif char tmp[65]; n = n > 64 ? 64 : n; if (!must_swap) strncpy(tmp, (const char *)in, n); else swapbytes(tmp, (const char *)in, n); tmp[n] = '\0'; trim(out, tmp); } // returns -1 if command fails or the device is in Sleep mode, else // value of Sector Count register. Sector Count result values: // 00h device is in Standby mode. // 80h device is in Idle mode. // FFh device is in Active mode or Idle mode. int ataCheckPowerMode(ata_device * device) { unsigned char result; if ((smartcommandhandler(device, CHECK_POWER_MODE, 0, (char *)&result))) return -1; if (result!=0 && result!=0x80 && result!=0xff) pout("ataCheckPowerMode(): ATA CHECK POWER MODE returned unknown Sector Count Register value %02x\n", result); return (int)result; } // Issue a no-data ATA command with optional sector count register value bool ata_nodata_command(ata_device * device, unsigned char command, int sector_count /* = -1 */) { ata_cmd_in in; in.in_regs.command = command; if (sector_count >= 0) in.in_regs.sector_count = sector_count; return device->ata_pass_through(in); } // Issue SET FEATURES command with optional sector count register value bool ata_set_features(ata_device * device, unsigned char features, int sector_count /* = -1 */) { ata_cmd_in in; in.in_regs.command = ATA_SET_FEATURES; in.in_regs.features = features; if (sector_count >= 0) in.in_regs.sector_count = sector_count; return device->ata_pass_through(in); } // Reads current Device Identity info (512 bytes) into buf. Returns 0 // if all OK. Returns -1 if no ATA Device identity can be // established. Returns >0 if Device is ATA Packet Device (not SMART // capable). The value of the integer helps identify the type of // Packet device, which is useful so that the user can connect the // formal device number with whatever object is inside their computer. int ata_read_identity(ata_device * device, ata_identify_device * buf, bool fix_swapped_id, unsigned char * raw_buf /* = 0 */) { unsigned short *rawshort=(unsigned short *)buf; unsigned char *rawbyte =(unsigned char *)buf; // See if device responds either to IDENTIFY DEVICE or IDENTIFY // PACKET DEVICE bool packet = false; if ((smartcommandhandler(device, IDENTIFY, 0, (char *)buf))){ if (smartcommandhandler(device, PIDENTIFY, 0, (char *)buf)){ return -1; } packet = true; } unsigned i; if (fix_swapped_id) { // Swap ID strings for (i = 0; i < sizeof(buf->serial_no)-1; i += 2) swap2((char *)(buf->serial_no+i)); for (i = 0; i < sizeof(buf->fw_rev)-1; i += 2) swap2((char *)(buf->fw_rev+i)); for (i = 0; i < sizeof(buf->model)-1; i += 2) swap2((char *)(buf->model+i)); } // If requested, save raw data before endianness adjustments if (raw_buf) memcpy(raw_buf, buf, sizeof(*buf)); #ifndef __NetBSD__ // if machine is big-endian, swap byte order as needed // NetBSD kernel delivers IDENTIFY data in host byte order // TODO: Handle NetBSD case in os_netbsd.cpp if (isbigendian()){ // swap various capability words that are needed for (i=0; i<33; i++) swap2((char *)(buf->words047_079+i)); for (i=80; i<=87; i++) swap2((char *)(rawshort+i)); for (i=0; i<168; i++) swap2((char *)(buf->words088_255+i)); } #endif // If there is a checksum there, validate it if ((rawshort[255] & 0x00ff) == 0x00a5 && checksum(rawbyte)) checksumwarning("Drive Identity Structure"); // AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS) // T13/1699-D Revision 6a (Final Draft), September 6, 2008. // Sections 7.16.7 and 7.17.6: // // Word 0 of IDENTIFY DEVICE data: // Bit 15 = 0 : ATA device // // Word 0 of IDENTIFY PACKET DEVICE data: // Bits 15:14 = 10b : ATAPI device // Bits 15:14 = 11b : Reserved // Bits 12:8 : Device type (SPC-4, e.g 0x05 = CD/DVD) // CF+ and CompactFlash Specification Revision 4.0, May 24, 2006. // Section 6.2.1.6: // // Word 0 of IDENTIFY DEVICE data: // 848Ah = Signature for CompactFlash Storage Card // 044Ah = Alternate value turns on ATA device while preserving all retired bits // 0040h = Alternate value turns on ATA device while zeroing all retired bits // Assume ATA if IDENTIFY DEVICE returns CompactFlash Signature if (!packet && rawbyte[1] == 0x84 && rawbyte[0] == 0x8a) return 0; // If this is a PACKET DEVICE, return device type if (rawbyte[1] & 0x80) return 1+(rawbyte[1] & 0x1f); // Not a PACKET DEVICE return 0; } // Get World Wide Name (WWN) fields. // Return NAA field or -1 if WWN is unsupported. // Table 34 of T13/1699-D Revision 6a (ATA8-ACS), September 6, 2008. // (WWN was introduced in ATA/ATAPI-7 and is mandatory since ATA8-ACS Revision 3b) int ata_get_wwn(const ata_identify_device * id, unsigned & oui, uint64_t & unique_id) { // Don't use word 84 to be compatible with some older ATA-7 disks unsigned short word087 = id->csf_default; if ((word087 & 0xc100) != 0x4100) return -1; // word not valid or WWN support bit 8 not set unsigned short word108 = id->words088_255[108-88]; unsigned short word109 = id->words088_255[109-88]; unsigned short word110 = id->words088_255[110-88]; unsigned short word111 = id->words088_255[111-88]; oui = ((word108 & 0x0fff) << 12) | (word109 >> 4); unique_id = ((uint64_t)(word109 & 0xf) << 32) | (unsigned)((word110 << 16) | word111); return (word108 >> 12); } // Get nominal media rotation rate. // Returns: 0 = not reported, 1 = SSD, >1 = HDD rpm, < 0 = -(Unknown value) int ata_get_rotation_rate(const ata_identify_device * id) { // Table 37 of T13/1699-D (ATA8-ACS) Revision 6a, September 6, 2008 // Table A.31 of T13/2161-D (ACS-3) Revision 3b, August 25, 2012 unsigned short word217 = id->words088_255[217-88]; if (word217 == 0x0000 || word217 == 0xffff) return 0; else if (word217 == 0x0001) return 1; else if (word217 > 0x0400) return word217; else return -(int)word217; } // returns 1 if SMART supported, 0 if SMART unsupported, -1 if can't tell int ataSmartSupport(const ata_identify_device * drive) { unsigned short word82=drive->command_set_1; unsigned short word83=drive->command_set_2; // check if words 82/83 contain valid info if ((word83>>14) == 0x01) // return value of SMART support bit return word82 & 0x0001; // since we can're rely on word 82, we don't know if SMART supported return -1; } // returns 1 if SMART enabled, 0 if SMART disabled, -1 if can't tell int ataIsSmartEnabled(const ata_identify_device * drive) { unsigned short word85=drive->cfs_enable_1; unsigned short word87=drive->csf_default; // check if words 85/86/87 contain valid info if ((word87>>14) == 0x01) // return value of SMART enabled bit return word85 & 0x0001; // Since we can't rely word85, we don't know if SMART is enabled. return -1; } // Reads SMART attributes into *data int ataReadSmartValues(ata_device * device, struct ata_smart_values *data){ if (smartcommandhandler(device, READ_VALUES, 0, (char *)data)){ return -1; } // compute checksum if (checksum(data)) checksumwarning("SMART Attribute Data Structure"); // swap endian order if needed if (isbigendian()){ int i; swap2((char *)&(data->revnumber)); swap2((char *)&(data->total_time_to_complete_off_line)); swap2((char *)&(data->smart_capability)); swapx(&data->extend_test_completion_time_w); for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){ struct ata_smart_attribute *x=data->vendor_attributes+i; swap2((char *)&(x->flags)); } } return 0; } // This corrects some quantities that are byte reversed in the SMART // SELF TEST LOG static void fixsamsungselftestlog(ata_smart_selftestlog * data) { // bytes 508/509 (numbered from 0) swapped (swap of self-test index // with one byte of reserved. swap2((char *)&(data->mostrecenttest)); // LBA low register (here called 'selftestnumber", containing // information about the TYPE of the self-test) is byte swapped with // Self-test execution status byte. These are bytes N, N+1 in the // entries. for (int i = 0; i < 21; i++) swap2((char *)&(data->selftest_struct[i].selftestnumber)); return; } // Reads the Self Test Log (log #6) int ataReadSelfTestLog (ata_device * device, ata_smart_selftestlog * data, firmwarebug_defs firmwarebugs) { // get data from device if (smartcommandhandler(device, READ_LOG, 0x06, (char *)data)){ return -1; } // compute its checksum, and issue a warning if needed if (checksum(data)) checksumwarning("SMART Self-Test Log Structure"); // fix firmware bugs in self-test log if (firmwarebugs.is_set(BUG_SAMSUNG)) fixsamsungselftestlog(data); // swap endian order if needed if (isbigendian()){ int i; swap2((char*)&(data->revnumber)); for (i=0; i<21; i++){ struct ata_smart_selftestlog_struct *x=data->selftest_struct+i; swap2((char *)&(x->timestamp)); swap4((char *)&(x->lbafirstfailure)); } } return 0; } // Print checksum warning for multi sector log static void check_multi_sector_sum(const void * data, unsigned nsectors, const char * msg) { unsigned errs = 0; for (unsigned i = 0; i < nsectors; i++) { if (checksum((const unsigned char *)data + i*512)) errs++; } if (errs > 0) { if (nsectors == 1) checksumwarning(msg); else checksumwarning(strprintf("%s (%u/%u)", msg, errs, nsectors).c_str()); } } // Read SMART Extended Self-test Log bool ataReadExtSelfTestLog(ata_device * device, ata_smart_extselftestlog * log, unsigned nsectors) { if (!ataReadLogExt(device, 0x07, 0x00, 0, log, nsectors)) return false; check_multi_sector_sum(log, nsectors, "SMART Extended Self-test Log Structure"); if (isbigendian()) { swapx(&log->log_desc_index); for (unsigned i = 0; i < nsectors; i++) { for (unsigned j = 0; j < 19; j++) swapx(&log->log_descs[i].timestamp); } } return true; } // Read GP Log page(s) bool ataReadLogExt(ata_device * device, unsigned char logaddr, unsigned char features, unsigned page, void * data, unsigned nsectors) { ata_cmd_in in; in.in_regs.command = ATA_READ_LOG_EXT; in.in_regs.features = features; // log specific in.set_data_in_48bit(data, nsectors); in.in_regs.lba_low = logaddr; in.in_regs.lba_mid_16 = page; if (!device->ata_pass_through(in)) { // TODO: Debug output if (nsectors <= 1) { pout("ATA_READ_LOG_EXT (addr=0x%02x:0x%02x, page=%u, n=%u) failed: %s\n", logaddr, features, page, nsectors, device->get_errmsg()); return false; } // Recurse to retry with single sectors, // multi-sector reads may not be supported by ioctl. for (unsigned i = 0; i < nsectors; i++) { if (!ataReadLogExt(device, logaddr, features, page + i, (char *)data + 512*i, 1)) return false; } } return true; } // Read SMART Log page(s) bool ataReadSmartLog(ata_device * device, unsigned char logaddr, void * data, unsigned nsectors) { ata_cmd_in in; in.in_regs.command = ATA_SMART_CMD; in.in_regs.features = ATA_SMART_READ_LOG_SECTOR; in.set_data_in(data, nsectors); in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW; in.in_regs.lba_low = logaddr; if (!device->ata_pass_through(in)) { // TODO: Debug output pout("ATA_SMART_READ_LOG failed: %s\n", device->get_errmsg()); return false; } return true; } // Reads the SMART or GPL Log Directory (log #0) int ataReadLogDirectory(ata_device * device, ata_smart_log_directory * data, bool gpl) { if (!gpl) { // SMART Log directory if (smartcommandhandler(device, READ_LOG, 0x00, (char *)data)) return -1; } else { // GP Log directory if (!ataReadLogExt(device, 0x00, 0x00, 0, data, 1)) return -1; } // swap endian order if needed if (isbigendian()) swapx(&data->logversion); return 0; } // Reads the selective self-test log (log #9) int ataReadSelectiveSelfTestLog(ata_device * device, struct ata_selective_self_test_log *data){ // get data from device if (smartcommandhandler(device, READ_LOG, 0x09, (char *)data)){ return -1; } // compute its checksum, and issue a warning if needed if (checksum(data)) checksumwarning("SMART Selective Self-Test Log Structure"); // swap endian order if needed if (isbigendian()){ int i; swap2((char *)&(data->logversion)); for (i=0;i<5;i++){ swap8((char *)&(data->span[i].start)); swap8((char *)&(data->span[i].end)); } swap8((char *)&(data->currentlba)); swap2((char *)&(data->currentspan)); swap2((char *)&(data->flags)); swap2((char *)&(data->pendingtime)); } return 0; } // Writes the selective self-test log (log #9) int ataWriteSelectiveSelfTestLog(ata_device * device, ata_selective_selftest_args & args, const ata_smart_values * sv, uint64_t num_sectors, const ata_selective_selftest_args * prev_args) { // Disk size must be known if (!num_sectors) { pout("Disk size is unknown, unable to check selective self-test spans\n"); return -1; } // Read log struct ata_selective_self_test_log sstlog, *data=&sstlog; unsigned char *ptr=(unsigned char *)data; if (ataReadSelectiveSelfTestLog(device, data)) { pout("SMART Read Selective Self-test Log failed: %s\n", device->get_errmsg()); pout("Since Read failed, will not attempt to WRITE Selective Self-test Log\n"); return -1; } // Set log version data->logversion = 1; // Host is NOT allowed to write selective self-test log if a selective // self-test is in progress. if (0<data->currentspan && data->currentspan<6 && ((sv->self_test_exec_status)>>4)==15) { pout("SMART Selective or other Self-test in progress\n"); return -4; } // Set start/end values based on old spans for special -t select,... options int i; for (i = 0; i < args.num_spans; i++) { int mode = args.span[i].mode; uint64_t start = args.span[i].start; uint64_t end = args.span[i].end; if (mode == SEL_CONT) {// redo or next dependig on last test status switch (sv->self_test_exec_status >> 4) { case 1: case 2: // Aborted/Interrupted by host pout("Continue Selective Self-Test: Redo last span\n"); mode = SEL_REDO; break; default: // All others pout("Continue Selective Self-Test: Start next span\n"); mode = SEL_NEXT; break; } } if ( (mode == SEL_REDO || mode == SEL_NEXT) && prev_args && i < prev_args->num_spans && !data->span[i].start && !data->span[i].end) { // Some drives do not preserve the selective self-test log accross // power-cyles. If old span on drive is cleared use span provided // by caller. This is used by smartd (first span only). data->span[i].start = prev_args->span[i].start; data->span[i].end = prev_args->span[i].end; } switch (mode) { case SEL_RANGE: // -t select,START-END break; case SEL_REDO: // -t select,redo... => Redo current start = data->span[i].start; if (end > 0) { // -t select,redo+SIZE end--; end += start; // [oldstart, oldstart+SIZE) } else // -t select,redo end = data->span[i].end; // [oldstart, oldend] break; case SEL_NEXT: // -t select,next... => Do next if (data->span[i].end == 0) { start = end = 0; break; // skip empty spans } start = data->span[i].end + 1; if (start >= num_sectors) start = 0; // wrap around if (end > 0) { // -t select,next+SIZE end--; end += start; // (oldend, oldend+SIZE] } else { // -t select,next uint64_t oldsize = data->span[i].end - data->span[i].start + 1; end = start + oldsize - 1; // (oldend, oldend+oldsize] if (end >= num_sectors) { // Adjust size to allow round-robin testing without future size decrease uint64_t spans = (num_sectors + oldsize-1) / oldsize; uint64_t newsize = (num_sectors + spans-1) / spans; uint64_t newstart = num_sectors - newsize, newend = num_sectors - 1; pout("Span %d changed from %"PRIu64"-%"PRIu64" (%"PRIu64" sectors)\n", i, start, end, oldsize); pout(" to %"PRIu64"-%"PRIu64" (%"PRIu64" sectors) (%"PRIu64" spans)\n", newstart, newend, newsize, spans); start = newstart; end = newend; } } break; default: pout("ataWriteSelectiveSelfTestLog: Invalid mode %d\n", mode); return -1; } // Range check if (start < num_sectors && num_sectors <= end) { if (end != ~(uint64_t)0) // -t select,N-max pout("Size of self-test span %d decreased according to disk size\n", i); end = num_sectors - 1; } if (!(start <= end && end < num_sectors)) { pout("Invalid selective self-test span %d: %"PRIu64"-%"PRIu64" (%"PRIu64" sectors)\n", i, start, end, num_sectors); return -1; } // Return the actual mode and range to caller. args.span[i].mode = mode; args.span[i].start = start; args.span[i].end = end; } // Clear spans for (i=0; i<5; i++) memset(data->span+i, 0, sizeof(struct test_span)); // Set spans for testing for (i = 0; i < args.num_spans; i++){ data->span[i].start = args.span[i].start; data->span[i].end = args.span[i].end; } // host must initialize to zero before initiating selective self-test data->currentlba=0; data->currentspan=0; // Perform off-line scan after selective test? if (args.scan_after_select == 1) // NO data->flags &= ~SELECTIVE_FLAG_DOSCAN; else if (args.scan_after_select == 2) // YES data->flags |= SELECTIVE_FLAG_DOSCAN; // Must clear active and pending flags before writing data->flags &= ~(SELECTIVE_FLAG_ACTIVE); data->flags &= ~(SELECTIVE_FLAG_PENDING); // modify pending time? if (args.pending_time) data->pendingtime = (unsigned short)(args.pending_time-1); // Set checksum to zero, then compute checksum data->checksum=0; unsigned char cksum=0; for (i=0; i<512; i++) cksum+=ptr[i]; cksum=~cksum; cksum+=1; data->checksum=cksum; // swap endian order if needed if (isbigendian()){ swap2((char *)&(data->logversion)); for (int b = 0; b < 5; b++) { swap8((char *)&(data->span[b].start)); swap8((char *)&(data->span[b].end)); } swap8((char *)&(data->currentlba)); swap2((char *)&(data->currentspan)); swap2((char *)&(data->flags)); swap2((char *)&(data->pendingtime)); } // write new selective self-test log if (smartcommandhandler(device, WRITE_LOG, 0x09, (char *)data)){ pout("Write Selective Self-test Log failed: %s\n", device->get_errmsg()); return -3; } return 0; } // This corrects some quantities that are byte reversed in the SMART // ATA ERROR LOG. static void fixsamsungerrorlog(ata_smart_errorlog * data) { // FIXED IN SAMSUNG -25 FIRMWARE??? // Device error count in bytes 452-3 swap2((char *)&(data->ata_error_count)); // FIXED IN SAMSUNG -22a FIRMWARE // step through 5 error log data structures for (int i = 0; i < 5; i++){ // step through 5 command data structures for (int j = 0; j < 5; j++) // Command data structure 4-byte millisec timestamp. These are // bytes (N+8, N+9, N+10, N+11). swap4((char *)&(data->errorlog_struct[i].commands[j].timestamp)); // Error data structure two-byte hour life timestamp. These are // bytes (N+28, N+29). swap2((char *)&(data->errorlog_struct[i].error_struct.timestamp)); } return; } // NEEDED ONLY FOR SAMSUNG -22 (some) -23 AND -24?? FIRMWARE static void fixsamsungerrorlog2(ata_smart_errorlog * data) { // Device error count in bytes 452-3 swap2((char *)&(data->ata_error_count)); return; } // Reads the Summary SMART Error Log (log #1). The Comprehensive SMART // Error Log is #2, and the Extended Comprehensive SMART Error log is // #3 int ataReadErrorLog (ata_device * device, ata_smart_errorlog *data, firmwarebug_defs firmwarebugs) { // get data from device if (smartcommandhandler(device, READ_LOG, 0x01, (char *)data)){ return -1; } // compute its checksum, and issue a warning if needed if (checksum(data)) checksumwarning("SMART ATA Error Log Structure"); // Some disks have the byte order reversed in some SMART Summary // Error log entries if (firmwarebugs.is_set(BUG_SAMSUNG)) fixsamsungerrorlog(data); else if (firmwarebugs.is_set(BUG_SAMSUNG2)) fixsamsungerrorlog2(data); // swap endian order if needed if (isbigendian()){ int i,j; // Device error count in bytes 452-3 swap2((char *)&(data->ata_error_count)); // step through 5 error log data structures for (i=0; i<5; i++){ // step through 5 command data structures for (j=0; j<5; j++) // Command data structure 4-byte millisec timestamp swap4((char *)&(data->errorlog_struct[i].commands[j].timestamp)); // Error data structure life timestamp swap2((char *)&(data->errorlog_struct[i].error_struct.timestamp)); } } return 0; } // Fix LBA byte ordering of Extended Comprehensive Error Log // if little endian instead of ATA register ordering is provided template <class T> static inline void fix_exterrlog_lba_cmd(T & cmd) { T org = cmd; cmd.lba_mid_register_hi = org.lba_high_register; cmd.lba_low_register_hi = org.lba_mid_register_hi; cmd.lba_high_register = org.lba_mid_register; cmd.lba_mid_register = org.lba_low_register_hi; } static void fix_exterrlog_lba(ata_smart_exterrlog * log, unsigned nsectors) { for (unsigned i = 0; i < nsectors; i++) { for (int ei = 0; ei < 4; ei++) { ata_smart_exterrlog_error_log & entry = log[i].error_logs[ei]; fix_exterrlog_lba_cmd(entry.error); for (int ci = 0; ci < 5; ci++) fix_exterrlog_lba_cmd(entry.commands[ci]); } } } // Read Extended Comprehensive Error Log bool ataReadExtErrorLog(ata_device * device, ata_smart_exterrlog * log, unsigned nsectors, firmwarebug_defs firmwarebugs) { if (!ataReadLogExt(device, 0x03, 0x00, 0, log, nsectors)) return false; check_multi_sector_sum(log, nsectors, "SMART Extended Comprehensive Error Log Structure"); if (isbigendian()) { swapx(&log->device_error_count); swapx(&log->error_log_index); for (unsigned i = 0; i < nsectors; i++) { for (unsigned j = 0; j < 4; j++) swapx(&log->error_logs[i].commands[j].timestamp); swapx(&log->error_logs[i].error.timestamp); } } if (firmwarebugs.is_set(BUG_XERRORLBA)) fix_exterrlog_lba(log, nsectors); return true; } int ataReadSmartThresholds (ata_device * device, struct ata_smart_thresholds_pvt *data){ // get data from device if (smartcommandhandler(device, READ_THRESHOLDS, 0, (char *)data)){ return -1; } // compute its checksum, and issue a warning if needed if (checksum(data)) checksumwarning("SMART Attribute Thresholds Structure"); // swap endian order if needed if (isbigendian()) swap2((char *)&(data->revnumber)); return 0; } int ataEnableSmart (ata_device * device ){ if (smartcommandhandler(device, ENABLE, 0, NULL)){ return -1; } return 0; } int ataDisableSmart (ata_device * device ){ if (smartcommandhandler(device, DISABLE, 0, NULL)){ return -1; } return 0; } int ataEnableAutoSave(ata_device * device){ if (smartcommandhandler(device, AUTOSAVE, 241, NULL)){ return -1; } return 0; } int ataDisableAutoSave(ata_device * device){ if (smartcommandhandler(device, AUTOSAVE, 0, NULL)){ return -1; } return 0; } // In *ALL* ATA standards the Enable/Disable AutoOffline command is // marked "OBSOLETE". It is defined in SFF-8035i Revision 2, and most // vendors still support it for backwards compatibility. IBM documents // it for some drives. int ataEnableAutoOffline (ata_device * device){ /* timer hard coded to 4 hours */ if (smartcommandhandler(device, AUTO_OFFLINE, 248, NULL)){ return -1; } return 0; } // Another Obsolete Command. See comments directly above, associated // with the corresponding Enable command. int ataDisableAutoOffline (ata_device * device){ if (smartcommandhandler(device, AUTO_OFFLINE, 0, NULL)){ return -1; } return 0; } // If SMART is enabled, supported, and working, then this call is // guaranteed to return 1, else zero. Note that it should return 1 // regardless of whether the disk's SMART status is 'healthy' or // 'failing'. int ataDoesSmartWork(ata_device * device){ int retval=smartcommandhandler(device, STATUS, 0, NULL); if (-1 == retval) return 0; return 1; } // This function uses a different interface (DRIVE_TASK) than the // other commands in this file. int ataSmartStatus2(ata_device * device){ return smartcommandhandler(device, STATUS_CHECK, 0, NULL); } // This is the way to execute ALL tests: offline, short self-test, // extended self test, with and without captive mode, etc. // TODO: Move to ataprint.cpp ? int ataSmartTest(ata_device * device, int testtype, bool force, const ata_selective_selftest_args & selargs, const ata_smart_values * sv, uint64_t num_sectors) { char cmdmsg[128]; const char *type, *captive; int cap, retval, select=0; // Boolean, if set, says test is captive cap=testtype & CAPTIVE_MASK; // Set up strings that describe the type of test if (cap) captive="captive"; else captive="off-line"; if (testtype==OFFLINE_FULL_SCAN) type="off-line"; else if (testtype==SHORT_SELF_TEST || testtype==SHORT_CAPTIVE_SELF_TEST) type="Short self-test"; else if (testtype==EXTEND_SELF_TEST || testtype==EXTEND_CAPTIVE_SELF_TEST) type="Extended self-test"; else if (testtype==CONVEYANCE_SELF_TEST || testtype==CONVEYANCE_CAPTIVE_SELF_TEST) type="Conveyance self-test"; else if ((select=(testtype==SELECTIVE_SELF_TEST || testtype==SELECTIVE_CAPTIVE_SELF_TEST))) type="Selective self-test"; else type = 0; // Check whether another test is already running if (type && (sv->self_test_exec_status >> 4) == 0xf) { if (!force) { pout("Can't start self-test without aborting current test (%d0%% remaining),\n" "%srun 'smartctl -X' to abort test.\n", sv->self_test_exec_status & 0x0f, (!select ? "add '-t force' option to override, or " : "")); return -1; } } else force = false; // If doing a selective self-test, first use WRITE_LOG to write the // selective self-test log. ata_selective_selftest_args selargs_io = selargs; // filled with info about actual spans if (select && (retval = ataWriteSelectiveSelfTestLog(device, selargs_io, sv, num_sectors))) { if (retval==-4) pout("Can't start selective self-test without aborting current test: use '-X' option to smartctl.\n"); return retval; } // Print ouf message that we are sending the command to test if (testtype==ABORT_SELF_TEST) snprintf(cmdmsg, sizeof(cmdmsg), "Abort SMART off-line mode self-test routine"); else if (!type) snprintf(cmdmsg, sizeof(cmdmsg), "SMART EXECUTE OFF-LINE IMMEDIATE subcommand 0x%02x", testtype); else snprintf(cmdmsg, sizeof(cmdmsg), "Execute SMART %s routine immediately in %s mode", type, captive); pout("Sending command: \"%s\".\n",cmdmsg); if (select) { int i; pout("SPAN STARTING_LBA ENDING_LBA\n"); for (i = 0; i < selargs_io.num_spans; i++) pout(" %d %20"PRId64" %20"PRId64"\n", i, selargs_io.span[i].start, selargs_io.span[i].end); } // Now send the command to test if (smartcommandhandler(device, IMMEDIATE_OFFLINE, testtype, NULL)) { if (!(cap && device->get_errno() == EIO)) { pout("Command \"%s\" failed: %s\n", cmdmsg, device->get_errmsg()); return -1; } } // Since the command succeeded, tell user if (testtype==ABORT_SELF_TEST) pout("Self-testing aborted!\n"); else { pout("Drive command \"%s\" successful.\n", cmdmsg); if (type) pout("Testing has begun%s.\n", (force ? " (previous test aborted)" : "")); } return 0; } /* Test Time Functions */ int TestTime(const ata_smart_values *data, int testtype) { switch (testtype){ case OFFLINE_FULL_SCAN: return (int) data->total_time_to_complete_off_line; case SHORT_SELF_TEST: case SHORT_CAPTIVE_SELF_TEST: return (int) data->short_test_completion_time; case EXTEND_SELF_TEST: case EXTEND_CAPTIVE_SELF_TEST: if (data->extend_test_completion_time_b == 0xff && data->extend_test_completion_time_w != 0x0000 && data->extend_test_completion_time_w != 0xffff) return data->extend_test_completion_time_w; // ATA-8 else return data->extend_test_completion_time_b; case CONVEYANCE_SELF_TEST: case CONVEYANCE_CAPTIVE_SELF_TEST: return (int) data->conveyance_test_completion_time; default: return 0; } } // This function tells you both about the ATA error log and the // self-test error log capability (introduced in ATA-5). The bit is // poorly documented in the ATA/ATAPI standard. Starting with ATA-6, // SMART error logging is also indicated in bit 0 of DEVICE IDENTIFY // word 84 and 87. Top two bits must match the pattern 01. BEFORE // ATA-6 these top two bits still had to match the pattern 01, but the // remaining bits were reserved (==0). int isSmartErrorLogCapable (const ata_smart_values * data, const ata_identify_device * identity) { unsigned short word84=identity->command_set_extension; unsigned short word87=identity->csf_default; int isata6=identity->major_rev_num & (0x01<<6); int isata7=identity->major_rev_num & (0x01<<7); if ((isata6 || isata7) && (word84>>14) == 0x01 && (word84 & 0x01)) return 1; if ((isata6 || isata7) && (word87>>14) == 0x01 && (word87 & 0x01)) return 1; // otherwise we'll use the poorly documented capability bit return data->errorlog_capability & 0x01; } // See previous function. If the error log exists then the self-test // log should (must?) also exist. int isSmartTestLogCapable (const ata_smart_values * data, const ata_identify_device *identity) { unsigned short word84=identity->command_set_extension; unsigned short word87=identity->csf_default; int isata6=identity->major_rev_num & (0x01<<6); int isata7=identity->major_rev_num & (0x01<<7); if ((isata6 || isata7) && (word84>>14) == 0x01 && (word84 & 0x02)) return 1; if ((isata6 || isata7) && (word87>>14) == 0x01 && (word87 & 0x02)) return 1; // otherwise we'll use the poorly documented capability bit return data->errorlog_capability & 0x01; } int isGeneralPurposeLoggingCapable(const ata_identify_device *identity) { unsigned short word84=identity->command_set_extension; unsigned short word87=identity->csf_default; // If bit 14 of word 84 is set to one and bit 15 of word 84 is // cleared to zero, the contents of word 84 contains valid support // information. If not, support information is not valid in this // word. if ((word84>>14) == 0x01) // If bit 5 of word 84 is set to one, the device supports the // General Purpose Logging feature set. return (word84 & (0x01 << 5)); // If bit 14 of word 87 is set to one and bit 15 of word 87 is // cleared to zero, the contents of words (87:85) contain valid // information. If not, information is not valid in these words. if ((word87>>14) == 0x01) // If bit 5 of word 87 is set to one, the device supports // the General Purpose Logging feature set. return (word87 & (0x01 << 5)); // not capable return 0; } // SMART self-test capability is also indicated in bit 1 of DEVICE // IDENTIFY word 87 (if top two bits of word 87 match pattern 01). // However this was only introduced in ATA-6 (but self-test log was in // ATA-5). int isSupportExecuteOfflineImmediate(const ata_smart_values *data) { return data->offline_data_collection_capability & 0x01; } // Note in the ATA-5 standard, the following bit is listed as "Vendor // Specific". So it may not be reliable. The only use of this that I // have found is in IBM drives, where it is well-documented. See for // example page 170, section 13.32.1.18 of the IBM Travelstar 40GNX // hard disk drive specifications page 164 Revision 1.1 22 Apr 2002. int isSupportAutomaticTimer(const ata_smart_values * data) { return data->offline_data_collection_capability & 0x02; } int isSupportOfflineAbort(const ata_smart_values *data) { return data->offline_data_collection_capability & 0x04; } int isSupportOfflineSurfaceScan(const ata_smart_values * data) { return data->offline_data_collection_capability & 0x08; } int isSupportSelfTest (const ata_smart_values * data) { return data->offline_data_collection_capability & 0x10; } int isSupportConveyanceSelfTest(const ata_smart_values * data) { return data->offline_data_collection_capability & 0x20; } int isSupportSelectiveSelfTest(const ata_smart_values * data) { return data->offline_data_collection_capability & 0x40; } // Get attribute state ata_attr_state ata_get_attr_state(const ata_smart_attribute & attr, int attridx, const ata_smart_threshold_entry * thresholds, const ata_vendor_attr_defs & defs, unsigned char * threshval /* = 0 */) { if (!attr.id) return ATTRSTATE_NON_EXISTING; // Normalized values (current,worst,threshold) not valid // if specified by '-v' option. // (Some SSD disks uses these bytes to store raw value). if (defs[attr.id].flags & ATTRFLAG_NO_NORMVAL) return ATTRSTATE_NO_NORMVAL; // Normally threshold is at same index as attribute int i = attridx; if (thresholds[i].id != attr.id) { // Find threshold id in table for (i = 0; thresholds[i].id != attr.id; ) { if (++i >= NUMBER_ATA_SMART_ATTRIBUTES) // Threshold id missing or thresholds cannot be read return ATTRSTATE_NO_THRESHOLD; } } unsigned char threshold = thresholds[i].threshold; // Return threshold if requested if (threshval) *threshval = threshold; // Don't report a failed attribute if its threshold is 0. // ATA-3 (X3T13/2008D Revision 7b) declares 0x00 as the "always passing" // threshold (Later ATA versions declare all thresholds as "obsolete"). // In practice, threshold value 0 is often used for usage attributes. if (!threshold) return ATTRSTATE_OK; // Failed now if current value is below threshold if (attr.current <= threshold) return ATTRSTATE_FAILED_NOW; // Failed in the past if worst value is below threshold if (!(defs[attr.id].flags & ATTRFLAG_NO_WORSTVAL) && attr.worst <= threshold) return ATTRSTATE_FAILED_PAST; return ATTRSTATE_OK; } // Get default raw value print format static ata_attr_raw_format get_default_raw_format(unsigned char id) { switch (id) { case 3: // Spin-up time return RAWFMT_RAW16_OPT_AVG16; case 5: // Reallocated sector count case 196: // Reallocated event count return RAWFMT_RAW16_OPT_RAW16; case 9: // Power on hours return RAWFMT_RAW24_OPT_RAW8; case 190: // Temperature case 194: return RAWFMT_TEMPMINMAX; default: return RAWFMT_RAW48; } } // Get attribute raw value. uint64_t ata_get_attr_raw_value(const ata_smart_attribute & attr, const ata_vendor_attr_defs & defs) { const ata_vendor_attr_defs::entry & def = defs[attr.id]; // Use default byteorder if not specified const char * byteorder = def.byteorder; if (!*byteorder) { switch (def.raw_format) { case RAWFMT_RAW64: case RAWFMT_HEX64: byteorder = "543210wv"; break; case RAWFMT_RAW56: case RAWFMT_HEX56: case RAWFMT_RAW24_DIV_RAW32: case RAWFMT_MSEC24_HOUR32: byteorder = "r543210"; break; default: byteorder = "543210"; break; } } // Build 64-bit value from selected bytes uint64_t rawvalue = 0; for (int i = 0; byteorder[i]; i++) { unsigned char b; switch (byteorder[i]) { case '0': b = attr.raw[0]; break; case '1': b = attr.raw[1]; break; case '2': b = attr.raw[2]; break; case '3': b = attr.raw[3]; break; case '4': b = attr.raw[4]; break; case '5': b = attr.raw[5]; break; case 'r': b = attr.reserv; break; case 'v': b = attr.current; break; case 'w': b = attr.worst; break; default : b = 0; break; } rawvalue <<= 8; rawvalue |= b; } return rawvalue; } // Format attribute raw value. std::string ata_format_attr_raw_value(const ata_smart_attribute & attr, const ata_vendor_attr_defs & defs) { // Get 48 bit or 64 bit raw value uint64_t rawvalue = ata_get_attr_raw_value(attr, defs); // Split into bytes and words unsigned char raw[6]; raw[0] = (unsigned char) rawvalue; raw[1] = (unsigned char)(rawvalue >> 8); raw[2] = (unsigned char)(rawvalue >> 16); raw[3] = (unsigned char)(rawvalue >> 24); raw[4] = (unsigned char)(rawvalue >> 32); raw[5] = (unsigned char)(rawvalue >> 40); unsigned word[3]; word[0] = raw[0] | (raw[1] << 8); word[1] = raw[2] | (raw[3] << 8); word[2] = raw[4] | (raw[5] << 8); // Get print format ata_attr_raw_format format = defs[attr.id].raw_format; if (format == RAWFMT_DEFAULT) format = get_default_raw_format(attr.id); // Print std::string s; switch (format) { case RAWFMT_RAW8: s = strprintf("%d %d %d %d %d %d", raw[5], raw[4], raw[3], raw[2], raw[1], raw[0]); break; case RAWFMT_RAW16: s = strprintf("%u %u %u", word[2], word[1], word[0]); break; case RAWFMT_RAW48: case RAWFMT_RAW56: case RAWFMT_RAW64: s = strprintf("%"PRIu64, rawvalue); break; case RAWFMT_HEX48: s = strprintf("0x%012"PRIx64, rawvalue); break; case RAWFMT_HEX56: s = strprintf("0x%014"PRIx64, rawvalue); break; case RAWFMT_HEX64: s = strprintf("0x%016"PRIx64, rawvalue); break; case RAWFMT_RAW16_OPT_RAW16: s = strprintf("%u", word[0]); if (word[1] || word[2]) s += strprintf(" (%u %u)", word[2], word[1]); break; case RAWFMT_RAW16_OPT_AVG16: s = strprintf("%u", word[0]); if (word[1]) s += strprintf(" (Average %u)", word[1]); break; case RAWFMT_RAW24_OPT_RAW8: s = strprintf("%u", (unsigned)(rawvalue & 0x00ffffffULL)); if (raw[3] || raw[4] || raw[5]) s += strprintf(" (%d %d %d)", raw[5], raw[4], raw[3]); break; case RAWFMT_RAW24_DIV_RAW24: s = strprintf("%u/%u", (unsigned)(rawvalue >> 24), (unsigned)(rawvalue & 0x00ffffffULL)); break; case RAWFMT_RAW24_DIV_RAW32: s = strprintf("%u/%u", (unsigned)(rawvalue >> 32), (unsigned)(rawvalue & 0xffffffffULL)); break; case RAWFMT_MIN2HOUR: { // minutes int64_t temp = word[0]+(word[1]<<16); int64_t tmp1 = temp/60; int64_t tmp2 = temp%60; s = strprintf("%"PRIu64"h+%02"PRIu64"m", tmp1, tmp2); if (word[2]) s += strprintf(" (%u)", word[2]); } break; case RAWFMT_SEC2HOUR: { // seconds int64_t hours = rawvalue/3600; int64_t minutes = (rawvalue-3600*hours)/60; int64_t seconds = rawvalue%60; s = strprintf("%"PRIu64"h+%02"PRIu64"m+%02"PRIu64"s", hours, minutes, seconds); } break; case RAWFMT_HALFMIN2HOUR: { // 30-second counter int64_t hours = rawvalue/120; int64_t minutes = (rawvalue-120*hours)/2; s += strprintf("%"PRIu64"h+%02"PRIu64"m", hours, minutes); } break; case RAWFMT_MSEC24_HOUR32: { // hours + milliseconds unsigned hours = (unsigned)(rawvalue & 0xffffffffULL); unsigned milliseconds = (unsigned)(rawvalue >> 32); unsigned seconds = milliseconds / 1000; s = strprintf("%uh+%02um+%02u.%03us", hours, seconds / 60, seconds % 60, milliseconds % 1000); } break; case RAWFMT_TEMPMINMAX: // Temperature { // Search for possible min/max values // 00 HH 00 LL 00 TT (Hitachi/IBM) // 00 00 HH LL 00 TT (Maxtor, Samsung) // 00 00 00 HH LL TT (WDC) unsigned char lo = 0, hi = 0; int cnt = 0; for (int i = 1; i < 6; i++) { if (raw[i]) switch (cnt++) { case 0: lo = raw[i]; break; case 1: if (raw[i] < lo) { hi = lo; lo = raw[i]; } else hi = raw[i]; break; } } unsigned char t = raw[0]; if (cnt == 0) s = strprintf("%d", t); else if (cnt == 2 && 0 < lo && lo <= t && t <= hi && hi < 128) s = strprintf("%d (Min/Max %d/%d)", t, lo, hi); else s = strprintf("%d (%d %d %d %d %d)", t, raw[5], raw[4], raw[3], raw[2], raw[1]); } break; case RAWFMT_TEMP10X: // ten times temperature in Celsius s = strprintf("%d.%d", word[0]/10, word[0]%10); break; default: s = "?"; // Should not happen break; } return s; } // Attribute names shouldn't be longer than 23 chars, otherwise they break the // output of smartctl. static const char * get_default_attr_name(unsigned char id, int rpm) { bool hdd = (rpm > 1), ssd = (rpm == 1); static const char Unknown_HDD_Attribute[] = "Unknown_HDD_Attribute"; static const char Unknown_SSD_Attribute[] = "Unknown_SSD_Attribute"; switch (id) { case 1: return "Raw_Read_Error_Rate"; case 2: return "Throughput_Performance"; case 3: return "Spin_Up_Time"; case 4: return "Start_Stop_Count"; case 5: return "Reallocated_Sector_Ct"; case 6: if (ssd) return Unknown_SSD_Attribute; return "Read_Channel_Margin"; case 7: if (ssd) return Unknown_SSD_Attribute; return "Seek_Error_Rate"; case 8: if (ssd) return Unknown_SSD_Attribute; return "Seek_Time_Performance"; case 9: return "Power_On_Hours"; case 10: if (ssd) return Unknown_SSD_Attribute; return "Spin_Retry_Count"; case 11: if (ssd) return Unknown_SSD_Attribute; return "Calibration_Retry_Count"; case 12: return "Power_Cycle_Count"; case 13: return "Read_Soft_Error_Rate"; case 175: if (hdd) return Unknown_HDD_Attribute; return "Program_Fail_Count_Chip"; case 176: if (hdd) return Unknown_HDD_Attribute; return "Erase_Fail_Count_Chip"; case 177: if (hdd) return Unknown_HDD_Attribute; return "Wear_Leveling_Count"; case 178: if (hdd) return Unknown_HDD_Attribute; return "Used_Rsvd_Blk_Cnt_Chip"; case 179: if (hdd) return Unknown_HDD_Attribute; return "Used_Rsvd_Blk_Cnt_Tot"; case 180: if (hdd) return Unknown_HDD_Attribute; return "Unused_Rsvd_Blk_Cnt_Tot"; case 181: return "Program_Fail_Cnt_Total"; case 182: if (hdd) return Unknown_HDD_Attribute; return "Erase_Fail_Count_Total"; case 183: return "Runtime_Bad_Block"; case 184: return "End-to-End_Error"; case 187: return "Reported_Uncorrect"; case 188: return "Command_Timeout"; case 189: if (ssd) return Unknown_SSD_Attribute; return "High_Fly_Writes"; case 190: // Western Digital uses this for temperature. // It's identical to Attribute 194 except that it // has a failure threshold set to correspond to the // max allowed operating temperature of the drive, which // is typically 55C. So if this attribute has failed // in the past, it indicates that the drive temp exceeded // 55C sometime in the past. return "Airflow_Temperature_Cel"; case 191: if (ssd) return Unknown_SSD_Attribute; return "G-Sense_Error_Rate"; case 192: return "Power-Off_Retract_Count"; case 193: if (ssd) return Unknown_SSD_Attribute; return "Load_Cycle_Count"; case 194: return "Temperature_Celsius"; case 195: // Fujitsu: "ECC_On_The_Fly_Count"; return "Hardware_ECC_Recovered"; case 196: return "Reallocated_Event_Count"; case 197: return "Current_Pending_Sector"; case 198: return "Offline_Uncorrectable"; case 199: return "UDMA_CRC_Error_Count"; case 200: if (ssd) return Unknown_SSD_Attribute; // Western Digital return "Multi_Zone_Error_Rate"; case 201: if (ssd) return Unknown_SSD_Attribute; return "Soft_Read_Error_Rate"; case 202: if (ssd) return Unknown_SSD_Attribute; // Fujitsu: "TA_Increase_Count" return "Data_Address_Mark_Errs"; case 203: // Fujitsu return "Run_Out_Cancel"; // Maxtor: ECC Errors case 204: // Fujitsu: "Shock_Count_Write_Opern" return "Soft_ECC_Correction"; case 205: // Fujitsu: "Shock_Rate_Write_Opern" return "Thermal_Asperity_Rate"; case 206: // Fujitsu if (ssd) return Unknown_SSD_Attribute; return "Flying_Height"; case 207: // Maxtor if (ssd) return Unknown_SSD_Attribute; return "Spin_High_Current"; case 208: // Maxtor if (ssd) return Unknown_SSD_Attribute; return "Spin_Buzz"; case 209: // Maxtor if (ssd) return Unknown_SSD_Attribute; return "Offline_Seek_Performnce"; case 220: if (ssd) return Unknown_SSD_Attribute; return "Disk_Shift"; case 221: if (ssd) return Unknown_SSD_Attribute; return "G-Sense_Error_Rate"; case 222: if (ssd) return Unknown_SSD_Attribute; return "Loaded_Hours"; case 223: if (ssd) return Unknown_SSD_Attribute; return "Load_Retry_Count"; case 224: if (ssd) return Unknown_SSD_Attribute; return "Load_Friction"; case 225: if (ssd) return Unknown_SSD_Attribute; return "Load_Cycle_Count"; case 226: if (ssd) return Unknown_SSD_Attribute; return "Load-in_Time"; case 227: if (ssd) return Unknown_SSD_Attribute; return "Torq-amp_Count"; case 228: return "Power-off_Retract_Count"; case 230: // seen in IBM DTPA-353750 if (ssd) return Unknown_SSD_Attribute; return "Head_Amplitude"; case 231: return "Temperature_Celsius"; case 232: // seen in Intel X25-E SSD return "Available_Reservd_Space"; case 233: // seen in Intel X25-E SSD if (hdd) return Unknown_HDD_Attribute; return "Media_Wearout_Indicator"; case 240: if (ssd) return Unknown_SSD_Attribute; return "Head_Flying_Hours"; case 241: return "Total_LBAs_Written"; case 242: return "Total_LBAs_Read"; case 250: return "Read_Error_Retry_Rate"; case 254: if (ssd) return Unknown_SSD_Attribute; return "Free_Fall_Sensor"; default: return "Unknown_Attribute"; } } // Get attribute name std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs & defs, int rpm /* = 0 */) { if (!defs[id].name.empty()) return defs[id].name; else return get_default_attr_name(id, rpm); } // Find attribute index for attribute id, -1 if not found. int ata_find_attr_index(unsigned char id, const ata_smart_values & smartval) { if (!id) return -1; for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) { if (smartval.vendor_attributes[i].id == id) return i; } return -1; } // Return Temperature Attribute raw value selected according to possible // non-default interpretations. If the Attribute does not exist, return 0 unsigned char ata_return_temperature_value(const ata_smart_values * data, const ata_vendor_attr_defs & defs) { for (int i = 0; i < 4; i++) { static const unsigned char ids[4] = {194, 190, 9, 220}; unsigned char id = ids[i]; const ata_attr_raw_format format = defs[id].raw_format; if (!( ((id == 194 || id == 190) && format == RAWFMT_DEFAULT) || format == RAWFMT_TEMPMINMAX || format == RAWFMT_TEMP10X)) continue; int idx = ata_find_attr_index(id, *data); if (idx < 0) continue; uint64_t raw = ata_get_attr_raw_value(data->vendor_attributes[idx], defs); unsigned temp; // ignore possible min/max values in high words if (format == RAWFMT_TEMP10X) // -v N,temp10x temp = ((unsigned short)raw + 5) / 10; else temp = (unsigned char)raw; if (!(0 < temp && temp < 128)) continue; return temp; } // No valid attribute found return 0; } // Read SCT Status int ataReadSCTStatus(ata_device * device, ata_sct_status_response * sts) { // read SCT status via SMART log 0xe0 memset(sts, 0, sizeof(*sts)); if (smartcommandhandler(device, READ_LOG, 0xe0, (char *)sts)){ pout("Read SCT Status failed: %s\n", device->get_errmsg()); return -1; } // swap endian order if needed if (isbigendian()){ swapx(&sts->format_version); swapx(&sts->sct_version); swapx(&sts->sct_spec); swapx(&sts->ext_status_code); swapx(&sts->action_code); swapx(&sts->function_code); swapx(&sts->over_limit_count); swapx(&sts->under_limit_count); } // Check format version if (!(sts->format_version == 2 || sts->format_version == 3)) { pout("Unknown SCT Status format version %u, should be 2 or 3.\n", sts->format_version); return -1; } return 0; } // Read SCT Temperature History Table and Status int ataReadSCTTempHist(ata_device * device, ata_sct_temperature_history_table * tmh, ata_sct_status_response * sts) { // Check initial status if (ataReadSCTStatus(device, sts)) return -1; // Do nothing if other SCT command is executing if (sts->ext_status_code == 0xffff) { pout("Another SCT command is executing, abort Read Data Table\n" "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n", sts->ext_status_code, sts->action_code, sts->function_code); return -1; } ata_sct_data_table_command cmd; memset(&cmd, 0, sizeof(cmd)); // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK) cmd.action_code = 5; // Data table command cmd.function_code = 1; // Read table cmd.table_id = 2; // Temperature History Table // swap endian order if needed if (isbigendian()) { swapx(&cmd.action_code); swapx(&cmd.function_code); swapx(&cmd.table_id); } // write command via SMART log page 0xe0 if (smartcommandhandler(device, WRITE_LOG, 0xe0, (char *)&cmd)){ pout("Write SCT Data Table failed: %s\n", device->get_errmsg()); return -1; } // read SCT data via SMART log page 0xe1 memset(tmh, 0, sizeof(*tmh)); if (smartcommandhandler(device, READ_LOG, 0xe1, (char *)tmh)){ pout("Read SCT Data Table failed: %s\n", device->get_errmsg()); return -1; } // re-read and check SCT status if (ataReadSCTStatus(device, sts)) return -1; if (!(sts->ext_status_code == 0 && sts->action_code == 5 && sts->function_code == 1)) { pout("Unexpected SCT status 0x%04x (action_code=%u, function_code=%u)\n", sts->ext_status_code, sts->action_code, sts->function_code); return -1; } // swap endian order if needed if (isbigendian()){ swapx(&tmh->format_version); swapx(&tmh->sampling_period); swapx(&tmh->interval); swapx(&tmh->cb_index); swapx(&tmh->cb_size); } return 0; } // Get/Set Write Cache Reordering int ataGetSetSCTWriteCacheReordering(ata_device * device, bool enable, bool persistent, bool set) { // Check initial status ata_sct_status_response sts; if (ataReadSCTStatus(device, &sts)) return -1; // Do nothing if other SCT command is executing if (sts.ext_status_code == 0xffff) { pout("Another SCT command is executing, abort Feature Control\n" "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n", sts.ext_status_code, sts.action_code, sts.function_code); return -1; } ata_sct_feature_control_command cmd; memset(&cmd, 0, sizeof(cmd)); // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK) cmd.action_code = 4; // Feature Control command cmd.function_code = (set ? 1 : 2); // 1=Set, 2=Get cmd.feature_code = 2; // Enable/Disable Write Cache Reordering cmd.state = (enable ? 1 : 2); // 1 enable, 2 disable cmd.option_flags = (persistent ? 0x01 : 0x00); // swap endian order if needed if (isbigendian()) { swapx(&cmd.action_code); swapx(&cmd.function_code); swapx(&cmd.feature_code); swapx(&cmd.state); swapx(&cmd.option_flags); } // write command via SMART log page 0xe0 // TODO: Debug output ata_cmd_in in; in.in_regs.command = ATA_SMART_CMD; in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW; in.in_regs.features = ATA_SMART_WRITE_LOG_SECTOR; in.in_regs.lba_low = 0xe0; in.set_data_out(&cmd, 1); if (!set) // Time limit returned in ATA registers in.out_needed.sector_count = in.out_needed.lba_low = true; ata_cmd_out out; if (!device->ata_pass_through(in, out)) { pout("Write SCT (%cet) XXX Error Recovery Control Command failed: %s\n", (!set ? 'G' : 'S'), device->get_errmsg()); return -1; } int state = out.out_regs.sector_count | (out.out_regs.lba_low << 8); // re-read and check SCT status if (ataReadSCTStatus(device, &sts)) return -1; if (!(sts.ext_status_code == 0 && sts.action_code == 4 && sts.function_code == (set ? 1 : 2))) { pout("Unexpected SCT status 0x%04x (action_code=%u, function_code=%u)\n", sts.ext_status_code, sts.action_code, sts.function_code); return -1; } return state; } // Set SCT Temperature Logging Interval int ataSetSCTTempInterval(ata_device * device, unsigned interval, bool persistent) { // Check initial status ata_sct_status_response sts; if (ataReadSCTStatus(device, &sts)) return -1; // Do nothing if other SCT command is executing if (sts.ext_status_code == 0xffff) { pout("Another SCT command is executing, abort Feature Control\n" "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n", sts.ext_status_code, sts.action_code, sts.function_code); return -1; } ata_sct_feature_control_command cmd; memset(&cmd, 0, sizeof(cmd)); // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK) cmd.action_code = 4; // Feature Control command cmd.function_code = 1; // Set state cmd.feature_code = 3; // Temperature logging interval cmd.state = interval; cmd.option_flags = (persistent ? 0x01 : 0x00); // swap endian order if needed if (isbigendian()) { swapx(&cmd.action_code); swapx(&cmd.function_code); swapx(&cmd.feature_code); swapx(&cmd.state); swapx(&cmd.option_flags); } // write command via SMART log page 0xe0 if (smartcommandhandler(device, WRITE_LOG, 0xe0, (char *)&cmd)){ pout("Write SCT Feature Control Command failed: %s\n", device->get_errmsg()); return -1; } // re-read and check SCT status if (ataReadSCTStatus(device, &sts)) return -1; if (!(sts.ext_status_code == 0 && sts.action_code == 4 && sts.function_code == 1)) { pout("Unexpected SCT status 0x%04x (action_code=%u, function_code=%u)\n", sts.ext_status_code, sts.action_code, sts.function_code); return -1; } return 0; } // Get/Set SCT Error Recovery Control static int ataGetSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, bool set, unsigned short & time_limit) { // Check initial status ata_sct_status_response sts; if (ataReadSCTStatus(device, &sts)) return -1; // Do nothing if other SCT command is executing if (sts.ext_status_code == 0xffff) { pout("Another SCT command is executing, abort Error Recovery Control\n" "(SCT ext_status_code 0x%04x, action_code=%u, function_code=%u)\n", sts.ext_status_code, sts.action_code, sts.function_code); return -1; } ata_sct_error_recovery_control_command cmd; memset(&cmd, 0, sizeof(cmd)); // CAUTION: DO NOT CHANGE THIS VALUE (SOME ACTION CODES MAY ERASE DISK) cmd.action_code = 3; // Error Recovery Control command cmd.function_code = (set ? 1 : 2); // 1=Set timer, 2=Get timer cmd.selection_code = type; // 1=Read timer, 2=Write timer if (set) cmd.time_limit = time_limit; // swap endian order if needed if (isbigendian()) { swapx(&cmd.action_code); swapx(&cmd.function_code); swapx(&cmd.selection_code); swapx(&cmd.time_limit); } // write command via SMART log page 0xe0 // TODO: Debug output ata_cmd_in in; in.in_regs.command = ATA_SMART_CMD; in.in_regs.lba_high = SMART_CYL_HI; in.in_regs.lba_mid = SMART_CYL_LOW; in.in_regs.features = ATA_SMART_WRITE_LOG_SECTOR; in.in_regs.lba_low = 0xe0; in.set_data_out(&cmd, 1); if (!set) // Time limit returned in ATA registers in.out_needed.sector_count = in.out_needed.lba_low = true; ata_cmd_out out; if (!device->ata_pass_through(in, out)) { pout("Write SCT (%cet) Error Recovery Control Command failed: %s\n", (!set ? 'G' : 'S'), device->get_errmsg()); return -1; } // re-read and check SCT status if (ataReadSCTStatus(device, &sts)) return -1; if (!(sts.ext_status_code == 0 && sts.action_code == 3 && sts.function_code == (set ? 1 : 2))) { pout("Unexpected SCT status 0x%04x (action_code=%u, function_code=%u)\n", sts.ext_status_code, sts.action_code, sts.function_code); return -1; } if (!set) { // Check whether registers are properly returned by ioctl() if (!(out.out_regs.sector_count.is_set() && out.out_regs.lba_low.is_set())) { // TODO: Output register support should be checked within each ata_pass_through() // implementation before command is issued. pout("SMART WRITE LOG does not return COUNT and LBA_LOW register\n"); return -1; } if ( out.out_regs.sector_count == in.in_regs.sector_count && out.out_regs.lba_low == in.in_regs.lba_low ) { // 0xe001 (5734.5s) - this is most likely a broken ATA pass-through implementation pout("SMART WRITE LOG returns COUNT and LBA_LOW register unchanged\n"); return -1; } // Return value to caller time_limit = out.out_regs.sector_count | (out.out_regs.lba_low << 8); } return 0; } // Get SCT Error Recovery Control int ataGetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short & time_limit) { return ataGetSetSCTErrorRecoveryControltime(device, type, false/*get*/, time_limit); } // Set SCT Error Recovery Control int ataSetSCTErrorRecoveryControltime(ata_device * device, unsigned type, unsigned short time_limit) { return ataGetSetSCTErrorRecoveryControltime(device, type, true/*set*/, time_limit); } // Print one self-test log entry. // Returns: // -1: self-test failed // 1: extended self-test completed without error // 0: otherwise int ataPrintSmartSelfTestEntry(unsigned testnum, unsigned char test_type, unsigned char test_status, unsigned short timestamp, uint64_t failing_lba, bool print_error_only, bool & print_header) { // Check status and type for return value int retval = 0; switch (test_status >> 4) { case 0x0: if ((test_type & 0x0f) == 0x02) retval = 1; // extended self-test completed without error break; case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: retval = -1; // self-test failed break; } if (retval >= 0 && print_error_only) return retval; std::string msgtest; switch (test_type) { case 0x00: msgtest = "Offline"; break; case 0x01: msgtest = "Short offline"; break; case 0x02: msgtest = "Extended offline"; break; case 0x03: msgtest = "Conveyance offline"; break; case 0x04: msgtest = "Selective offline"; break; case 0x7f: msgtest = "Abort offline test"; break; case 0x81: msgtest = "Short captive"; break; case 0x82: msgtest = "Extended captive"; break; case 0x83: msgtest = "Conveyance captive"; break; case 0x84: msgtest = "Selective captive"; break; default: if ((0x40 <= test_type && test_type <= 0x7e) || 0x90 <= test_type) msgtest = strprintf("Vendor (0x%02x)", test_type); else msgtest = strprintf("Reserved (0x%02x)", test_type); } std::string msgstat; switch (test_status >> 4) { case 0x0: msgstat = "Completed without error"; break; case 0x1: msgstat = "Aborted by host"; break; case 0x2: msgstat = "Interrupted (host reset)"; break; case 0x3: msgstat = "Fatal or unknown error"; break; case 0x4: msgstat = "Completed: unknown failure"; break; case 0x5: msgstat = "Completed: electrical failure"; break; case 0x6: msgstat = "Completed: servo/seek failure"; break; case 0x7: msgstat = "Completed: read failure"; break; case 0x8: msgstat = "Completed: handling damage??"; break; case 0xf: msgstat = "Self-test routine in progress"; break; default: msgstat = strprintf("Unknown status (0x%x)", test_status >> 4); } // Print header once if (print_header) { print_header = false; pout("Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error\n"); } char msglba[32]; if (retval < 0 && failing_lba < 0xffffffffffffULL) snprintf(msglba, sizeof(msglba), "%"PRIu64, failing_lba); else { msglba[0] = '-'; msglba[1] = 0; } pout("#%2u %-19s %-29s %1d0%% %8u %s\n", testnum, msgtest.c_str(), msgstat.c_str(), test_status & 0x0f, timestamp, msglba); return retval; } // Print Smart self-test log, used by smartctl and smartd. // return value is: // bottom 8 bits: number of entries found where self-test showed an error // remaining bits: if nonzero, power on hours of last self-test where error was found int ataPrintSmartSelfTestlog(const ata_smart_selftestlog * data, bool allentries, firmwarebug_defs firmwarebugs) { if (allentries) pout("SMART Self-test log structure revision number %d\n",(int)data->revnumber); if (data->revnumber != 0x0001 && allentries && !firmwarebugs.is_set(BUG_SAMSUNG)) pout("Warning: ATA Specification requires self-test log structure revision number = 1\n"); if (data->mostrecenttest==0){ if (allentries) pout("No self-tests have been logged. [To run self-tests, use: smartctl -t]\n\n"); return 0; } bool noheaderprinted = true; int errcnt = 0, hours = 0, igncnt = 0; int testno = 0, ext_ok_testno = -1; // print log for (int i = 20; i >= 0; i--) { // log is a circular buffer int j = (i+data->mostrecenttest)%21; const ata_smart_selftestlog_struct * log = data->selftest_struct+j; if (nonempty(log, sizeof(*log))) { // count entry based on non-empty structures -- needed for // Seagate only -- other vendors don't have blank entries 'in // the middle' testno++; // T13/1321D revision 1c: (Data structure Rev #1) //The failing LBA shall be the LBA of the uncorrectable sector //that caused the test to fail. If the device encountered more //than one uncorrectable sector during the test, this field //shall indicate the LBA of the first uncorrectable sector //encountered. If the test passed or the test failed for some //reason other than an uncorrectable sector, the value of this //field is undefined. // This is true in ALL ATA-5 specs uint64_t lba48 = (log->lbafirstfailure < 0xffffffff ? log->lbafirstfailure : 0xffffffffffffULL); // Print entry int state = ataPrintSmartSelfTestEntry(testno, log->selftestnumber, log->selfteststatus, log->timestamp, lba48, !allentries, noheaderprinted); if (state < 0) { // Self-test showed an error if (ext_ok_testno < 0) { errcnt++; // keep track of time of most recent error if (!hours) hours = log->timestamp; } else // Newer successful extended self-test exits igncnt++; } else if (state > 0 && ext_ok_testno < 0) { // Latest successful extended self-test ext_ok_testno = testno; } } } if (igncnt) pout("%d of %d failed self-tests are outdated by newer successful extended offline self-test #%2d\n", igncnt, igncnt+errcnt, ext_ok_testno); if (!allentries && !noheaderprinted) pout("\n"); return ((hours << 8) | errcnt); } ///////////////////////////////////////////////////////////////////////////// // Pseudo-device to parse "smartctl -r ataioctl,2 ..." output and simulate // an ATA device with same behaviour namespace { class parsed_ata_device : public /*implements*/ ata_device_with_command_set { public: parsed_ata_device(smart_interface * intf, const char * dev_name); virtual ~parsed_ata_device() throw(); virtual bool is_open() const; virtual bool open(); virtual bool close(); virtual bool ata_identify_is_cached() const; protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); private: // Table of parsed commands, return value, data struct parsed_ata_command { smart_command_set command; int select; int retval, errval; char * data; }; enum { max_num_commands = 32 }; parsed_ata_command m_command_table[max_num_commands]; int m_num_commands; int m_next_replay_command; bool m_replay_out_of_sync; bool m_ata_identify_is_cached; }; static const char * nextline(const char * s, int & lineno) { for (s += strcspn(s, "\r\n"); *s == '\r' || *s == '\n'; s++) { if (*s == '\r' && s[1] == '\n') s++; lineno++; } return s; } static int name2command(const char * s) { for (int i = 0; i < (int)(sizeof(commandstrings)/sizeof(commandstrings[0])); i++) { if (!strcmp(s, commandstrings[i])) return i; } return -1; } static bool matchcpy(char * dest, size_t size, const char * src, const regmatch_t & srcmatch) { if (srcmatch.rm_so < 0) return false; size_t n = srcmatch.rm_eo - srcmatch.rm_so; if (n >= size) n = size-1; memcpy(dest, src + srcmatch.rm_so, n); dest[n] = 0; return true; } static inline int matchtoi(const char * src, const regmatch_t & srcmatch, int defval) { if (srcmatch.rm_so < 0) return defval; return atoi(src + srcmatch.rm_so); } parsed_ata_device::parsed_ata_device(smart_interface * intf, const char * dev_name) : smart_device(intf, dev_name, "ata", ""), m_num_commands(0), m_next_replay_command(0), m_replay_out_of_sync(false), m_ata_identify_is_cached(false) { memset(m_command_table, 0, sizeof(m_command_table)); } parsed_ata_device::~parsed_ata_device() throw() { close(); } bool parsed_ata_device::is_open() const { return (m_num_commands > 0); } // Parse stdin and build command table bool parsed_ata_device::open() { const char * pathname = get_dev_name(); if (strcmp(pathname, "-")) return set_err(EINVAL); pathname = "<stdin>"; // Fill buffer char buffer[64*1024]; int size = 0; while (size < (int)sizeof(buffer)) { int nr = fread(buffer, 1, sizeof(buffer), stdin); if (nr <= 0) break; size += nr; } if (size <= 0) return set_err(ENOENT, "%s: Unexpected EOF", pathname); if (size >= (int)sizeof(buffer)) return set_err(EIO, "%s: Buffer overflow", pathname); buffer[size] = 0; // Regex to match output from "-r ataioctl,2" static const char pattern[] = "^" "(" // (1 "REPORT-IOCTL: DeviceF?D?=[^ ]+ Command=([A-Z ]*[A-Z])" // (2) "(" // (3 "( InputParameter=([0-9]+))?" // (4 (5)) "|" "( returned (-?[0-9]+)( errno=([0-9]+)[^\r\n]*)?)" // (6 (7) (8 (9))) ")" // ) "[\r\n]" // EOL match necessary to match optional parts above "|" "===== \\[([A-Z ]*[A-Z])\\] DATA START " // (10) "|" " *(En|Dis)abled status cached by OS, " // (11) ")"; // ) // Compile regex const regular_expression regex(pattern, REG_EXTENDED); // Parse buffer const char * errmsg = 0; int i = -1, state = 0, lineno = 1; for (const char * line = buffer; *line; line = nextline(line, lineno)) { // Match line if (!(line[0] == 'R' || line[0] == '=' || line[0] == ' ')) continue; const int nmatch = 1+11; regmatch_t match[nmatch]; if (!regex.execute(line, nmatch, match)) continue; char cmdname[40]; if (matchcpy(cmdname, sizeof(cmdname), line, match[2])) { // "REPORT-IOCTL:... Command=%s ..." int nc = name2command(cmdname); if (nc < 0) { errmsg = "Unknown ATA command name"; break; } if (match[7].rm_so < 0) { // "returned %d" // Start of command if (!(state == 0 || state == 2)) { errmsg = "Missing REPORT-IOCTL result"; break; } if (++i >= max_num_commands) { errmsg = "Too many ATA commands"; break; } m_command_table[i].command = (smart_command_set)nc; m_command_table[i].select = matchtoi(line, match[5], 0); // "InputParameter=%d" state = 1; } else { // End of command if (!(state == 1 && (int)m_command_table[i].command == nc)) { errmsg = "Missing REPORT-IOCTL start"; break; } m_command_table[i].retval = matchtoi(line, match[7], -1); // "returned %d" m_command_table[i].errval = matchtoi(line, match[9], 0); // "errno=%d" state = 2; } } else if (matchcpy(cmdname, sizeof(cmdname), line, match[10])) { // "===== [%s] DATA START " // Start of sector hexdump int nc = name2command(cmdname); if (!(state == (nc == WRITE_LOG ? 1 : 2) && (int)m_command_table[i].command == nc)) { errmsg = "Unexpected DATA START"; break; } line = nextline(line, lineno); char * data = (char *)malloc(512); unsigned j; for (j = 0; j < 32; j++) { unsigned b[16]; unsigned u1, u2; int n1 = -1; if (!(sscanf(line, "%3u-%3u: " "%2x %2x %2x %2x %2x %2x %2x %2x " "%2x %2x %2x %2x %2x %2x %2x %2x%n", &u1, &u2, b+ 0, b+ 1, b+ 2, b+ 3, b+ 4, b+ 5, b+ 6, b+ 7, b+ 8, b+ 9, b+10, b+11, b+12, b+13, b+14, b+15, &n1) == 18 && n1 >= 56 && u1 == j*16 && u2 == j*16+15)) break; for (unsigned k = 0; k < 16; k++) data[j*16+k] = b[k]; line = nextline(line, lineno); } if (j < 32) { free(data); errmsg = "Incomplete sector hex dump"; break; } m_command_table[i].data = data; if (nc != WRITE_LOG) state = 0; } else if (match[11].rm_so > 0) { // "(En|Dis)abled status cached by OS" m_ata_identify_is_cached = true; } } if (!(state == 0 || state == 2)) errmsg = "Missing REPORT-IOCTL result"; if (!errmsg && i < 0) errmsg = "No information found"; m_num_commands = i+1; m_next_replay_command = 0; m_replay_out_of_sync = false; if (errmsg) { close(); return set_err(EIO, "%s(%d): Syntax error: %s", pathname, lineno, errmsg); } return true; } // Report warnings and free command table bool parsed_ata_device::close() { if (m_replay_out_of_sync) pout("REPLAY-IOCTL: Warning: commands replayed out of sync\n"); else if (m_next_replay_command != 0) pout("REPLAY-IOCTL: Warning: %d command(s) not replayed\n", m_num_commands-m_next_replay_command); for (int i = 0; i < m_num_commands; i++) { if (m_command_table[i].data) { free(m_command_table[i].data); m_command_table[i].data = 0; } } m_num_commands = 0; m_next_replay_command = 0; m_replay_out_of_sync = false; return true; } bool parsed_ata_device::ata_identify_is_cached() const { return m_ata_identify_is_cached; } // Simulate ATA command from command table int parsed_ata_device::ata_command_interface(smart_command_set command, int select, char * data) { // Find command, try round-robin if out of sync int i = m_next_replay_command; for (int j = 0; ; j++) { if (j >= m_num_commands) { pout("REPLAY-IOCTL: Warning: Command not found\n"); errno = ENOSYS; return -1; } if (m_command_table[i].command == command && m_command_table[i].select == select) break; if (!m_replay_out_of_sync) { m_replay_out_of_sync = true; pout("REPLAY-IOCTL: Warning: Command #%d is out of sync\n", i+1); } if (++i >= m_num_commands) i = 0; } m_next_replay_command = i; if (++m_next_replay_command >= m_num_commands) m_next_replay_command = 0; // Return command data switch (command) { case IDENTIFY: case PIDENTIFY: case READ_VALUES: case READ_THRESHOLDS: case READ_LOG: if (m_command_table[i].data) memcpy(data, m_command_table[i].data, 512); break; case WRITE_LOG: if (!(m_command_table[i].data && !memcmp(data, m_command_table[i].data, 512))) pout("REPLAY-IOCTL: Warning: WRITE LOG data does not match\n"); break; case CHECK_POWER_MODE: data[0] = (char)0xff; default: break; } if (m_command_table[i].errval) errno = m_command_table[i].errval; return m_command_table[i].retval; } } // namespace ata_device * get_parsed_ata_device(smart_interface * intf, const char * dev_name) { return new parsed_ata_device(intf, dev_name); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/Doxyfile�������������������������������������������������������������0000644�0000000�0000000�00000021326�11232362607�016575� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Doxyfile 1.5.5 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = smartmontools PROJECT_NUMBER = OUTPUT_DIRECTORY = doc CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = YES INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = INPUT_ENCODING = UTF-8 FILE_PATTERNS = dev*.h \ dev*.cpp \ scsiata.cpp RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = NO REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = YES DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/drivedb.h������������������������������������������������������������0000644�0000000�0000000�00000332003�12174314244�016654� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * drivedb.h - smartmontools drive database file * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-11 Philip Williams, Bruce Allen * Copyright (C) 2008-13 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ /* * Structure used to store drive database entries: * * struct drive_settings { * const char * modelfamily; * const char * modelregexp; * const char * firmwareregexp; * const char * warningmsg; * const char * presets; * }; * * The elements are used in the following ways: * * modelfamily Informal string about the model family/series of a * device. Set to "" if no info (apart from device id) * known. The entry is ignored if this string starts with * a dollar sign. Must not start with "USB:", see below. * modelregexp POSIX extended regular expression to match the model of * a device. This should never be "". * firmwareregexp POSIX extended regular expression to match a devices's * firmware. This is optional and should be "" if it is not * to be used. If it is nonempty then it will be used to * narrow the set of devices matched by modelregexp. * warningmsg A message that may be displayed for matching drives. For * example, to inform the user that they may need to apply a * firmware patch. * presets String with vendor-specific attribute ('-v') and firmware * bug fix ('-F') options. Same syntax as in smartctl command * line. The user's own settings override these. * * The regular expressions for drive model and firmware must match the full * string. The effect of "^FULLSTRING$" is identical to "FULLSTRING". * The form ".*SUBSTRING.*" can be used if substring match is desired. * * The table will be searched from the start to end or until the first match, * so the order in the table is important for distinct entries that could match * the same drive. * * * Format for USB ID entries: * * modelfamily String with format "USB: DEVICE; BRIDGE" where * DEVICE is the name of the device and BRIDGE is * the name of the USB bridge. Both may be empty * if no info known. * modelregexp POSIX extended regular expression to match the USB * vendor:product ID in hex notation ("0x1234:0xabcd"). * This should never be "". * firmwareregexp POSIX extended regular expression to match the USB * bcdDevice info. Only compared during search if other * entries with same USB vendor:product ID exist. * warningmsg Not used yet. * presets String with one device type ('-d') option. * */ /* const drive_settings builtin_knowndrives[] = { */ { "$Id: drivedb.h 3840 2013-07-25 21:29:08Z chrfranke $", "-", "-", "This is a dummy entry to hold the SVN-Id of drivedb.h", "" /* Default settings: "-v 1,raw48,Raw_Read_Error_Rate " "-v 2,raw48,Throughput_Performance " "-v 3,raw16(avg16),Spin_Up_Time " "-v 4,raw48,Start_Stop_Count " "-v 5,raw16(raw16),Reallocated_Sector_Ct " "-v 6,raw48,Read_Channel_Margin " // HDD only "-v 7,raw48,Seek_Error_Rate " // HDD only "-v 8,raw48,Seek_Time_Performance " // HDD only "-v 9,raw24(raw8),Power_On_Hours " "-v 10,raw48,Spin_Retry_Count " // HDD only "-v 11,raw48,Calibration_Retry_Count " // HDD only "-v 12,raw48,Power_Cycle_Count " "-v 13,raw48,Read_Soft_Error_Rate " // 14-174 Unknown_Attribute "-v 175,raw48,Program_Fail_Count_Chip " // SSD only "-v 176,raw48,Erase_Fail_Count_Chip " // SSD only "-v 177,raw48,Wear_Leveling_Count " // SSD only "-v 178,raw48,Used_Rsvd_Blk_Cnt_Chip " // SSD only "-v 179,raw48,Used_Rsvd_Blk_Cnt_Tot " // SSD only "-v 180,raw48,Unused_Rsvd_Blk_Cnt_Tot " // SSD only "-v 181,raw48,Program_Fail_Cnt_Total " "-v 182,raw48,Erase_Fail_Count_Total " // SSD only "-v 183,raw48,Runtime_Bad_Block " "-v 184,raw48,End-to-End_Error " // 185-186 Unknown_Attribute "-v 187,raw48,Reported_Uncorrect " "-v 188,raw48,Command_Timeout " "-v 189,raw48,High_Fly_Writes " // HDD only "-v 190,tempminmax,Airflow_Temperature_Cel " "-v 191,raw48,G-Sense_Error_Rate " // HDD only "-v 192,raw48,Power-Off_Retract_Count " "-v 193,raw48,Load_Cycle_Count " // HDD only "-v 194,tempminmax,Temperature_Celsius " "-v 195,raw48,Hardware_ECC_Recovered " "-v 196,raw16(raw16),Reallocated_Event_Count " "-v 197,raw48,Current_Pending_Sector " "-v 198,raw48,Offline_Uncorrectable " "-v 199,raw48,UDMA_CRC_Error_Count " "-v 200,raw48,Multi_Zone_Error_Rate " // HDD only "-v 201,raw48,Soft_Read_Error_Rate " // HDD only "-v 202,raw48,Data_Address_Mark_Errs " // HDD only "-v 203,raw48,Run_Out_Cancel " "-v 204,raw48,Soft_ECC_Correction " "-v 205,raw48,Thermal_Asperity_Rate " "-v 206,raw48,Flying_Height " // HDD only "-v 207,raw48,Spin_High_Current " // HDD only "-v 208,raw48,Spin_Buzz " // HDD only "-v 209,raw48,Offline_Seek_Performnce " // HDD only // 210-219 Unknown_Attribute "-v 220,raw48,Disk_Shift " // HDD only "-v 221,raw48,G-Sense_Error_Rate " // HDD only "-v 222,raw48,Loaded_Hours " // HDD only "-v 223,raw48,Load_Retry_Count " // HDD only "-v 224,raw48,Load_Friction " // HDD only "-v 225,raw48,Load_Cycle_Count " // HDD only "-v 226,raw48,Load-in_Time " // HDD only "-v 227,raw48,Torq-amp_Count " // HDD only "-v 228,raw48,Power-off_Retract_Count " // 229 Unknown_Attribute "-v 230,raw48,Head_Amplitude " // HDD only "-v 231,raw48,Temperature_Celsius " "-v 232,raw48,Available_Reservd_Space " "-v 233,raw48,Media_Wearout_Indicator " // SSD only // 234-239 Unknown_Attribute "-v 240,raw48,Head_Flying_Hours " // HDD only "-v 241,raw48,Total_LBAs_Written " "-v 242,raw48,Total_LBAs_Read " // 243-249 Unknown_Attribute "-v 250,raw48,Read_Error_Retry_Rate " // 251-253 Unknown_Attribute "-v 254,raw48,Free_Fall_Sensor " // HDD only */ }, { "Apple SSD SM128", // Samsung? "APPLE SSD SM128", "", "", "" }, { "Apacer SDM4", "2GB SATA Flash Drive", // tested with APSDM002G15AN-CT/SFI2101D "SFI2101D", "", "-v 160,raw48,Initial_Bad_Block_Count " "-v 161,raw48,Bad_Block_Count " "-v 162,raw48,Spare_Block_Count " "-v 163,raw48,Max_Erase_Count " "-v 164,raw48,Min_Erase_Count " // could be wrong "-v 165,raw48,Average_Erase_Count " // could be wrong }, { "Asus-Phison SSD", "ASUS-PHISON SSD", "", "", "" }, { "Crucial/Micron RealSSD C300/M500", // Marvell 88SS91xx "C300-CTFDDA[AC](064|128|256)MAG|" // Marvell 88SS9174 BJP2, tested with C300-CTFDDAC128MAG/0002, // C300-CTFDDAC064MAG/0006 "Crucial_CT(120|240|480)M500SSD3", // Marvell 88SS9187 BLD2, tested with Crucial_CT120M500SSD3/MU02 "", "", //"-v 1,raw48,Raw_Read_Error_Rate " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Grown_Failing_Block_Ct " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 173,raw48,Wear_Leveling_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " "-v 181,raw16,Non4k_Aligned_Access " "-v 183,raw48,SATA_Iface_Downshift " //"-v 184,raw48,End-to-End_Error " //"-v 187,raw48,Reported_Uncorrect " //"-v 188,raw48,Command_Timeout " "-v 189,raw48,Factory_Bad_Block_Ct " //"-v 194,tempminmax,Temperature_Celsius " //"-v 195,raw48,Hardware_ECC_Recovered " //"-v 196,raw16(raw16),Reallocated_Event_Count " //"-v 197,raw48,Current_Pending_Sector " //"-v 198,raw48,Offline_Uncorrectable " //"-v 199,raw48,UDMA_CRC_Error_Count " "-v 202,raw48,Perc_Rated_Life_Used " "-v 206,raw48,Write_Error_Rate" }, { "Crucial/Micron RealSSD m4/C400/P400", // Marvell 9176, fixed firmware "C400-MTFDDA[ACK](064|128|256|512)MAM|" "M4-CT(064|128|256|512)M4SSD[23]|" // tested with M4-CT512M4SSD2/0309 "MTFDDAK(064|128|256|512|050|100|200|400)MA[RN]-1[JKS]1AA.*", // tested with // MTFDDAK256MAR-1K1AA/MA52 "030[9-Z]|03[1-Z].|0[4-Z]..|[1-Z]....*", // >= "0309" "", //"-v 1,raw48,Raw_Read_Error_Rate " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Grown_Failing_Block_Ct " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 173,raw48,Wear_Leveling_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " "-v 181,raw16,Non4k_Aligned_Access " "-v 183,raw48,SATA_Iface_Downshift " //"-v 184,raw48,End-to-End_Error " //"-v 187,raw48,Reported_Uncorrect " //"-v 188,raw48,Command_Timeout " "-v 189,raw48,Factory_Bad_Block_Ct " //"-v 194,tempminmax,Temperature_Celsius " //"-v 195,raw48,Hardware_ECC_Recovered " //"-v 196,raw16(raw16),Reallocated_Event_Count " //"-v 197,raw48,Current_Pending_Sector " //"-v 198,raw48,Offline_Uncorrectable " //"-v 199,raw48,UDMA_CRC_Error_Count " "-v 202,raw48,Perc_Rated_Life_Used " "-v 206,raw48,Write_Error_Rate" }, { "Crucial/Micron RealSSD m4/C400", // Marvell 9176, buggy or unknown firmware "C400-MTFDDA[ACK](064|128|256|512)MAM|" // tested with C400-MTFDDAC256MAM/0002 "M4-CT(064|128|256|512)M4SSD[23]", // tested with M4-CT064M4SSD2/0002, // M4-CT064M4SSD2/0009, M4-CT256M4SSD3/000F "", "This drive may hang after 5184 hours of power-on time:\n" "http://www.tomshardware.com/news/Crucial-m4-Firmware-BSOD,14544.html\n" "See the following web pages for firmware updates:\n" "http://www.crucial.com/support/firmware.aspx\n" "http://www.micron.com/products/solid-state-storage/client-ssd#software", "-v 170,raw48,Grown_Failing_Block_Ct " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 173,raw48,Wear_Leveling_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " "-v 181,raw16,Non4k_Aligned_Access " "-v 183,raw48,SATA_Iface_Downshift " "-v 189,raw48,Factory_Bad_Block_Ct " "-v 202,raw48,Perc_Rated_Life_Used " "-v 206,raw48,Write_Error_Rate" }, { "SandForce Driven SSDs", "SandForce 1st Ed\\.|" // Demo Drive, tested with firmware 320A13F0 "ADATA SSD S(396|510|599) .?..GB|" // tested with ADATA SSD S510 60GB/320ABBF0, // ADATA SSD S599 256GB/3.1.0, 64GB/3.4.6 "ADATA SP900|" // Premier Pro, SF-2281, tested with ADATA SP900/5.0.6 "Corsair CSSD-F(40|60|80|115|120|160|240)GBP?2.*|" // Corsair Force, tested with // Corsair CSSD-F40GB2/1.1, Corsair CSSD-F115GB2-A/2.1a "Corsair Force (3 SSD|GS|GT)|" // SF-2281, tested with // Corsair Force 3 SSD/1.3.2, GT/1.3.3, GS/5.03 "FM-25S2S-(60|120|240)GBP2|" // G.SKILL Phoenix Pro, SF-1200, tested with // FM-25S2S-240GBP2/4.2 "FTM(06|12|24|48)CT25H|" // Supertalent TeraDrive CT, tested with // FTM24CT25H/STTMP2P1 "KINGSTON SH10[03]S3(90|120|240|480)G|" // HyperX (3K), SF-2281, tested with // SH100S3240G/320ABBF0, SH103S3120G/505ABBF0 "KINGSTON SKC300S37A(60|120|240|480)G|" // SF-2281, tested with SKC300S37A120G/KC4ABBF0 "KINGSTON SVP200S3(7A)?(60|90|120|240|480)G|" // V+ 200, SF-2281, tested with // SVP200S37A480G/502ABBF0, SVP200S390G/332ABBF0 "KINGSTON SMS200S3(30|60|120)G|" // mSATA, SF-2241, tested with SMS200S3120G/KC3ABBF0 "KINGSTON SMS450S3(32|64|128)G|" // mSATA, SF-2281, tested with SMS450S3128G/503ABBF0 "KINGSTON (SV300|SKC100|SE100)S3.*G|" // other SF-2281 "MKNSSDCR(45|60|90|120|180|240|480)GB(-DX)?|" // Mushkin Chronos (deluxe), SF-2281, // tested with MKNSSDCR120GB "Mushkin MKNSSDCL(40|60|80|90|115|120|180|240|480)GB-DX2?|" // Mushkin Callisto deluxe, // SF-1200/1222, Mushkin MKNSSDCL60GB-DX/361A13F0 "OCZ[ -](AGILITY2([ -]EX)?|COLOSSUS2|ONYX2|VERTEX(2|-LE))( [123]\\..*)?|" // SF-1200, // tested with OCZ-VERTEX2/1.11, OCZ-VERTEX2 3.5/1.11 "OCZ-NOCTI|" // mSATA, SF-2100, tested with OCZ-NOCTI/2.15 "OCZ-REVODRIVE3?( X2)?|" // PCIe, SF-1200/2281, tested with // OCZ-REVODRIVE( X2)?/1.20, OCZ-REVODRIVE3 X2/2.11 "OCZ[ -](VELO|VERTEX2[ -](EX|PRO))( [123]\\..*)?|" // SF-1500, tested with // OCZ VERTEX2-PRO/1.10 (Bogus thresholds for attribute 232 and 235) "D2[CR]STK251...-....|" // OCZ Deneva 2 C/R, SF-22xx/25xx, // tested with D2CSTK251M11-0240/2.08, D2CSTK251A10-0240/2.15 "OCZ-(AGILITY3|SOLID3|VERTEX3( MI)?)|" // SF-2200, tested with OCZ-VERTEX3/2.02, // OCZ-AGILITY3/2.11, OCZ-SOLID3/2.15, OCZ-VERTEX3 MI/2.15 "OCZ Z-DRIVE R4 [CR]M8[48]|" // PCIe, SF-2282/2582, tested with OCZ Z-DRIVE R4 CM84/2.13 // (Bogus attributes under Linux) "TALOS2|" // OCZ Talos 2 C/R, SAS (works with -d sat), 2*SF-2282, tested with TALOS2/3.20E "(APOC|DENC|DENEVA|FTNC|GFGC|MANG|MMOC|NIMC|TMSC).*|" // other OCZ SF-1200, // tested with DENCSTE251M11-0120/1.33, DENEVA PCI-E/1.33 "(DENR|DRSAK|EC188|NIMR|PSIR|TRSAK).*|" // other OCZ SF-1500 "OWC Mercury Electra [36]G SSD|" // tested with // OWC Mercury Electra 6G SSD/502ABBF0 "OWC Mercury Extreme Pro (RE )?SSD|" // tested with // OWC Mercury Extreme Pro SSD/360A13F0 "OWC Mercury EXTREME Pro 6G SSD|" // tested with // OWC Mercury EXTREME Pro 6G SSD/507ABBF0 "Patriot Pyro|" // tested with Patriot Pyro/332ABBF0 "SanDisk SDSSDX(60|120|240|480)GG25|" // SanDisk Extreme, SF-2281, tested with // SDSSDX240GG25/R201 "SuperSSpeed S301 [0-9]*GB|" // SF-2281, tested with SuperSSpeed S301 128GB/503 "(TX32|TX31C1|VN0.?..GCNMK).*|" // Smart Storage Systems XceedSTOR "(TX22D1|TX21B1).*|" // Smart Storage Systems XceedIOPS2 "TX52D1.*|" // Smart Storage Systems Xcel-200 "TS(64|128|256|512)GSSD320|" // Transcend SSD320, SF-2281, tested with TS128GSSD320 "UGB(88P|99S)GC...H[BF].", // Unigen, tested with // UGB88PGC100HF2/MP Rev2, UGB99SGC100HB3/RC Rev3 "", "", "-v 1,raw24/raw32,Raw_Read_Error_Rate " "-v 5,raw48,Retired_Block_Count " "-v 9,msec24hour32,Power_On_Hours_and_Msec " //"-v 12,raw48,Power_Cycle_Count " "-v 13,raw24/raw32,Soft_Read_Error_Rate " "-v 100,raw48,Gigabytes_Erased " "-v 170,raw48,Reserve_Block_Count " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " "-v 177,raw48,Wear_Range_Delta " "-v 181,raw48,Program_Fail_Count " "-v 182,raw48,Erase_Fail_Count " "-v 184,raw48,IO_Error_Detect_Code_Ct " //"-v 187,raw48,Reported_Uncorrect " "-v 189,tempminmax,Airflow_Temperature_Cel " //"-v 194,tempminmax,Temperature_Celsius " "-v 195,raw24/raw32,ECC_Uncorr_Error_Count " //"-v 196,raw16(raw16),Reallocated_Event_Count " "-v 198,raw24/raw32:210zr54,Uncorrectable_Sector_Ct " // KINGSTON SE100S3100G/510ABBF0 "-v 199,raw48,SATA_CRC_Error_Count " "-v 201,raw24/raw32,Unc_Soft_Read_Err_Rate " "-v 204,raw24/raw32,Soft_ECC_Correct_Rate " "-v 230,raw48,Life_Curve_Status " "-v 231,raw48,SSD_Life_Left " //"-v 232,raw48,Available_Reservd_Space " "-v 233,raw48,SandForce_Internal " "-v 234,raw48,SandForce_Internal " "-v 235,raw48,SuperCap_Health " "-v 241,raw48,Lifetime_Writes_GiB " "-v 242,raw48,Lifetime_Reads_GiB" }, { "Indilinx Barefoot based SSDs", "Corsair CSSD-V(32|60|64|128|256)GB2|" // Corsair Nova, tested with Corsair CSSD-V32GB2/2.2 "CRUCIAL_CT(64|128|256)M225|" // tested with CRUCIAL_CT64M225/1571 "G.SKILL FALCON (64|128|256)GB SSD|" // tested with G.SKILL FALCON 128GB SSD/2030 "OCZ[ -](AGILITY|ONYX|VERTEX( 1199|-TURBO)?)|" // tested with // OCZ-ONYX/1.6, OCZ-VERTEX 1199/00.P97, OCZ-VERTEX/1.30, OCZ VERTEX-TURBO/1.5 "Patriot[ -]Torqx.*|" "RENICE Z2|" // tested with RENICE Z2/2030 "STT_FT[MD](28|32|56|64)GX25H|" // Super Talent Ultradrive GX, tested with STT_FTM64GX25H/1916 "TS(18|25)M(64|128)MLC(16|32|64|128|256|512)GSSD|" // ASAX Leopard Hunt II, tested with TS25M64MLC64GSSD/0.1 "FM-25S2I-(64|128)GBFII|" // G.Skill FALCON II, tested with FM-25S2I-64GBFII "TS(60|120)GSSD25D-M", // Transcend Ultra SSD (SATA II), see also Ticket #80 "", "", "-v 1,raw64 " // Raw_Read_Error_Rate "-v 9,raw64 " // Power_On_Hours "-v 12,raw64 " // Power_Cycle_Count "-v 184,raw64,Initial_Bad_Block_Count " "-v 195,raw64,Program_Failure_Blk_Ct " "-v 196,raw64,Erase_Failure_Blk_Ct " "-v 197,raw64,Read_Failure_Blk_Ct " "-v 198,raw64,Read_Sectors_Tot_Ct " "-v 199,raw64,Write_Sectors_Tot_Ct " "-v 200,raw64,Read_Commands_Tot_Ct " "-v 201,raw64,Write_Commands_Tot_Ct " "-v 202,raw64,Error_Bits_Flash_Tot_Ct " "-v 203,raw64,Corr_Read_Errors_Tot_Ct " "-v 204,raw64,Bad_Block_Full_Flag " "-v 205,raw64,Max_PE_Count_Spec " "-v 206,raw64,Min_Erase_Count " "-v 207,raw64,Max_Erase_Count " "-v 208,raw64,Average_Erase_Count " "-v 209,raw64,Remaining_Lifetime_Perc " "-v 210,raw64,Indilinx_Internal " "-v 211,raw64,SATA_Error_Ct_CRC " "-v 212,raw64,SATA_Error_Ct_Handshake " "-v 213,raw64,Indilinx_Internal" }, { "Indilinx Barefoot_2/Everest/Martini based SSDs", "OCZ VERTEX[ -]PLUS|" // tested with OCZ VERTEX-PLUS/3.55, OCZ VERTEX PLUS/3.55 "OCZ-VERTEX PLUS R2|" // Barefoot 2, tested with OCZ-VERTEX PLUS R2/1.2 "OCZ-PETROL|" // Everest 1, tested with OCZ-PETROL/3.12 "OCZ-AGILITY4|" // Everest 2, tested with OCZ-AGILITY4/1.5.2 "OCZ-VERTEX4", // Everest 2, tested with OCZ-VERTEX4/1.5 "", "", "" //"-v 1,raw48,Raw_Read_Error_Rate " //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 232,raw48,Lifetime_Writes " // LBA? //"-v 233,raw48,Media_Wearout_Indicator" }, { "Indilinx Barefoot 3 based SSDs", "OCZ-VECTOR", // tested with OCZ-VECTOR/1.03 "", "", "" "-v 5,raw48,Runtime_Bad_Block " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 171,raw48,Avail_OP_Block_Count " "-v 174,raw48,Pwr_Cycle_Ct_Unplanned " "-v 187,raw48,Total_Unc_NAND_Reads " "-v 195,raw48,Total_Prog_Failures " "-v 196,raw48,Total_Erase_Failures " "-v 197,raw48,Total_Unc_Read_Failures " "-v 198,raw48,Host_Reads_GiB " "-v 199,raw48,Host_Writes_GiB " "-v 208,raw48,Average_Erase_Count " "-v 210,raw48,SATA_CRC_Error_Count " "-v 233,raw48,Remaining_Lifetime_Perc " "-v 249,raw48,Total_NAND_Prog_Ct_GiB" }, { "InnoDisk InnoLite SATADOM D150QV-L SSDs", // tested with InnoLite SATADOM D150QV-L/120319 "InnoLite SATADOM D150QV-L", "", "", //"-v 1,raw48,Raw_Read_Error_Rate " //"-v 2,raw48,Throughput_Performance " //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 7,raw48,Seek_Error_Rate " // from InnoDisk iSMART Linux tool, useless for SSD //"-v 8,raw48,Seek_Time_Performance " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 10,raw48,Spin_Retry_Count " //"-v 12,raw48,Power_Cycle_Count " "-v 168,raw48,SATA_PHY_Error_Count " "-v 170,raw48,Bad_Block_Count " "-v 173,raw48,Erase_Count " "-v 175,raw48,Bad_Cluster_Table_Count " "-v 192,raw48,Unexpect_Power_Loss_Ct " //"-v 194,tempminmax,Temperature_Celsius " //"-v 197,raw48,Current_Pending_Sector " "-v 229,hex48,Flash_ID " "-v 235,raw48,Later_Bad_Block " "-v 236,raw48,Unstable_Power_Count " "-v 240,raw48,Write_Head" }, { "Intel X25-E SSDs", "SSDSA2SH(032|064)G1.* INTEL", // G1 = first generation "", "", //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Intel_Internal " "-v 227,raw48,Intel_Internal " "-v 228,raw48,Intel_Internal " //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator" }, { "Intel X18-M/X25-M G1 SSDs", "INTEL SSDSA[12]MH(080|160)G1.*", // G1 = first generation, 50nm "", "", //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Intel_Internal " "-v 227,raw48,Intel_Internal " "-v 228,raw48,Intel_Internal " //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator" }, { "Intel X18-M/X25-M/X25-V G2 SSDs", // fixed firmware // tested with INTEL SSDSA2M(080|160)G2GC/2CV102J8 (X25-M) "INTEL SSDSA[12]M(040|080|120|160)G2.*", // G2 = second generation, 34nm "2CV102(J[89A-Z]|[K-Z].)", // >= "2CV102J8" "", //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " //"-v 184,raw48,End-to-End_Error " // G2 only "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " // Timed Workload Media Wear Indicator (percent*1024) "-v 227,raw48,Workld_Host_Reads_Perc " // Timed Workload Host Reads Percentage "-v 228,raw48,Workload_Minutes " // 226,227,228 can be reset by 'smartctl -t vendor,0x40' //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator" }, { "Intel X18-M/X25-M/X25-V G2 SSDs", // buggy or unknown firmware // tested with INTEL SSDSA2M040G2GC/2CV102HD (X25-V) "INTEL SSDSA[12]M(040|080|120|160)G2.*", "", "This drive may require a firmware update to\n" "fix possible drive hangs when reading SMART self-test log:\n" "http://downloadcenter.intel.com/Detail_Desc.aspx?DwnldID=18363", "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " "-v 227,raw48,Workld_Host_Reads_Perc " "-v 228,raw48,Workload_Minutes" }, { "Intel 313 Series SSDs", // tested with INTEL SSDSA2VP020G3/9CV10379 "INTEL SSDSA2VP(020|024)G3", "", "", //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Reserve_Block_Count " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 183,raw48,SATA_Downshift_Count " //"-v 184,raw48,End-to-End_Error " //"-v 187,raw48,Reported_Uncorrect " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " // Timed Workload Media Wear Indicator (percent*1024) "-v 227,raw48,Workld_Host_Reads_Perc " // Timed Workload Host Reads Percentage "-v 228,raw48,Workload_Minutes " // 226,227,228 can be reset by 'smartctl -t vendor,0x40' //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator " "-v 241,raw48,Host_Writes_32MiB " "-v 242,raw48,Host_Reads_32MiB" }, { "Intel 320 Series SSDs", // tested with INTEL SSDSA2CT040G3/4PC10362, // INTEL SSDSA2CW160G3/4PC10362, INTEL SSDSA2BT040G3/4PC10362, INTEL SSDSA2BW120G3A/4PC10362 "INTEL SSDSA[12][BC][WT](040|080|120|160|300|600)G3A?", "", "", "-F nologdir " //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Reserve_Block_Count " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " //"-v 184,raw48,End-to-End_Error " //"-v 187,raw48,Reported_Uncorrect " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " // Timed Workload Media Wear Indicator (percent*1024) "-v 227,raw48,Workld_Host_Reads_Perc " // Timed Workload Host Reads Percentage "-v 228,raw48,Workload_Minutes " // 226,227,228 can be reset by 'smartctl -t vendor,0x40' //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator " "-v 241,raw48,Host_Writes_32MiB " "-v 242,raw48,Host_Reads_32MiB" }, { "Intel 710 Series SSDs", // tested with INTEL SSDSA2BZ[12]00G3/6PB10362 "INTEL SSDSA2BZ(100|200|300)G3", "", "", "-F nologdir " //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Reserve_Block_Count " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " // Missing in 710 specification from September 2011 "-v 183,raw48,SATA_Downshift_Count " //"-v 184,raw48,End-to-End_Error " //"-v 187,raw48,Reported_Uncorrect " //"-v 190,tempminmax,Airflow_Temperature_Cel " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " // Timed Workload Media Wear Indicator (percent*1024) "-v 227,raw48,Workld_Host_Reads_Perc " // Timed Workload Host Reads Percentage "-v 228,raw48,Workload_Minutes " // 226,227,228 can be reset by 'smartctl -t vendor,0x40' //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator " "-v 241,raw48,Host_Writes_32MiB " "-v 242,raw48,Host_Reads_32MiB" }, { "Intel 510 Series SSDs", "INTEL SSDSC2MH(120|250)A2", "", "", //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator" }, { "Intel 520 Series SSDs", // tested with INTEL SSDSC2CW120A3/400i, SSDSC2BW480A3F/400i "INTEL SSDSC2[BC]W(060|120|180|240|480)A3F?", "", "", //"-v 5,raw16(raw16),Reallocated_Sector_Ct " "-v 9,msec24hour32,Power_On_Hours_and_Msec " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Available_Reservd_Space " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " //"-v 184,raw48,End-to-End_Error " "-v 187,raw48,Uncorrectable_Error_Cnt " //"-v 192,raw48,Power-Off_Retract_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " "-v 227,raw48,Workld_Host_Reads_Perc " "-v 228,raw48,Workload_Minutes " //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator " "-v 241,raw48,Host_Writes_32MiB " "-v 242,raw48,Host_Reads_32MiB " "-v 249,raw48,NAND_Writes_1GiB" }, { "Intel 330/335 Series SSDs", // tested with INTEL SSDSC2CT180A3/300i, SSDSC2CT240A3/300i, // INTEL SSDSC2CT240A4/335t "INTEL SSDSC2CT(060|120|180|240)A[34]", // A4 = 335 Series "", "", //"-v 5,raw16(raw16),Reallocated_Sector_Ct " "-v 9,msec24hour32,Power_On_Hours_and_Msec " //"-v 12,raw48,Power_Cycle_Count " //"-v 181,raw48,Program_Fail_Cnt_Total " // ] Missing in 330 specification from April 2012 //"-v 182,raw48,Erase_Fail_Count_Total " // ] //"-v 192,raw48,Power-Off_Retract_Count " "-v 225,raw48,Host_Writes_32MiB " //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator " "-v 241,raw48,Host_Writes_32MiB " "-v 242,raw48,Host_Reads_32MiB " "-v 249,raw48,NAND_Writes_1GiB" }, { "Intel DC S3700 Series SSDs", // tested with INTEL SSDSC2BA200G3/5DV10250 "INTEL SSDSC(1N|2B)A(100|200|400|800)G3", "", "", //"-v 3,raw16(avg16),Spin_Up_Time " //"-v 4,raw48,Start_Stop_Count " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 170,raw48,Available_Reservd_Space " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 174,raw48,Unsafe_Shutdown_Count " "-v 175,raw48,Power_Loss_Cap_Test " "-v 183,raw48,SATA_Downshift_Count " //"-v 184,raw48,End-to-End_Error " //"-v 187,raw48,Reported_Uncorrect " "-v 190,tempminmax,Temperature_Case " "-v 192,raw48,Unsafe_Shutdown_Count " "-v 194,tempminmax,Temperature_Internal " //"-v 197,raw48,Current_Pending_Sector " "-v 199,raw48,CRC_Error_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " // Timed Workload Media Wear Indicator (percent*1024) "-v 227,raw48,Workld_Host_Reads_Perc " // Timed Workload Host Reads Percentage "-v 228,raw48,Workload_Minutes " // 226,227,228 can be reset by 'smartctl -t vendor,0x40' //"-v 232,raw48,Available_Reservd_Space " //"-v 233,raw48,Media_Wearout_Indicator " "-v 234,raw48,Thermal_Throttle " "-v 241,raw48,Host_Writes_32MiB " "-v 242,raw48,Host_Reads_32MiB" }, { "Kingston branded X25-V SSDs", // fixed firmware "KINGSTON SSDNow 40GB", "2CV102(J[89A-Z]|[K-Z].)", // >= "2CV102J8" "", "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " "-v 227,raw48,Workld_Host_Reads_Perc " "-v 228,raw48,Workload_Minutes" }, { "Kingston branded X25-V SSDs", // buggy or unknown firmware "KINGSTON SSDNow 40GB", "", "This drive may require a firmware update to\n" "fix possible drive hangs when reading SMART self-test log.\n" "To update Kingston branded drives, a modified Intel update\n" "tool must be used. Search for \"kingston 40gb firmware\".", "-v 192,raw48,Unsafe_Shutdown_Count " "-v 225,raw48,Host_Writes_32MiB " "-v 226,raw48,Workld_Media_Wear_Indic " "-v 227,raw48,Workld_Host_Reads_Perc " "-v 228,raw48,Workload_Minutes" }, { "JMicron based SSDs", // JMicron JMF60x "Kingston SSDNow V Series [0-9]*GB|" // tested with Kingston SSDNow V Series 64GB/B090522a "TS(2|4|8|16|32|64|128|192)GSSD25S?-(M|S)", // Transcend IDE and SATA, tested with TS32GSSD25-M/V090331 "[BV].*", // other Transcend SSD versions will be catched by subsequent entry "", //"-v 9,raw24(raw8),Power_On_Hours " // raw value always 0? //"-v 12,raw48,Power_Cycle_Count " //"-v 194,tempminmax,Temperature_Celsius " // raw value always 0? "-v 229,hex64:w012345r,Halt_System/Flash_ID " // Halt, Flash[7] "-v 232,hex64:w012345r,Firmware_Version_Info " // "YYMMDD", #Channels, #Banks "-v 233,hex48:w01234,ECC_Fail_Record " // Fail number, Row[3], Channel, Bank "-v 234,raw24/raw24:w01234,Avg/Max_Erase_Count " "-v 235,raw24/raw24:w01z23,Good/Sys_Block_Count" }, { "JMicron based SSDs", // JMicron JMF61x "ADATA S596 Turbo|" // tested with ADATA S596 Turbo 256GB SATA SSD (JMicron JMF616) "APPLE SSD TS.*|" // Toshiba?, tested with APPLE SSD TS064C/CJAA0201 "KINGSTON SNV425S2(64|128)GB|" // SSDNow V Series (2. Generation, JMF618), // tested with KINGSTON SNV425S264GB/C091126a "KINGSTON SSDNOW 30GB|" // tested with KINGSTON SSDNOW 30GB/AJXA0202 "KINGSTON SS100S2(8|16)G|" // SSDNow S100 Series, tested with KINGSTON SS100S28G/D100309a "KINGSTON SVP?100S2B?(64|96|128|256|512)G|" // SSDNow V100/V+100 Series, // tested with KINGSTON SVP100S296G/CJR10202, KINGSTON SV100S2256G/D110225a "KINGSTON SV200S3(64|128|256)G|" // SSDNow V200 Series, tested with KINGSTON SV200S3128G/E120506a "TOSHIBA THNS128GG4BBAA|" // Toshiba / Super Talent UltraDrive DX, // tested with Toshiba 128GB 2.5" SSD (built in MacBooks) "TOSHIBA THNSNC128GMLJ|" // tested with THNSNC128GMLJ/CJTA0202 (built in Toshiba Protege/Dynabook) "TS(8|16|32|64|128|192|256|512)GSSD25S?-(MD?|S)", // Transcend IDE and SATA (JMF612), tested with // TS256GSSD25S-M/101028, TS32GSSD25-M/20101227 "", "", //"-v 1,raw48,Raw_Read_Error_Rate " //"-v 2,raw48,Throughput_Performance " "-v 3,raw48,Unknown_Attribute " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " "-v 7,raw48,Unknown_Attribute " "-v 8,raw48,Unknown_Attribute " //"-v 9,raw24(raw8),Power_On_Hours " "-v 10,raw48,Unknown_Attribute " //"-v 12,raw48,Power_Cycle_Count " //"-v 167,raw48,Unknown_Attribute " "-v 168,raw48,SATA_Phy_Error_Count " //"-v 169,raw48,Unknown_Attribute " "-v 170,raw16,Bad_Block_Count " "-v 173,raw16,Erase_Count " "-v 175,raw48,Bad_Cluster_Table_Count " "-v 192,raw48,Unexpect_Power_Loss_Ct " //"-v 194,tempminmax,Temperature_Celsius " //"-v 197,raw48,Current_Pending_Sector " "-v 240,raw48,Unknown_Attribute" }, { "Plextor M3 (Pro) Series SSDs", // Marvell 9174, tested with PLEXTOR PX-128M3/1.01, // PLEXTOR PX-128M3P/1.04, PLEXTOR PX-256M3/1.05 // (1.04/5 Firmware self-test log lifetime unit is bogus, possibly 1/256 hours) "PLEXTOR PX-(64|128|256|512)M3P?", "", "", //"-v 1,raw48,Raw_Read_Error_Rate " //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " //"-v 177,raw48,Wear_Leveling_Count " //"-v 178,raw48,Used_Rsvd_Blk_Cnt_Chip " //"-v 181,raw48,Program_Fail_Cnt_Total " //"-v 182,raw48,Erase_Fail_Count_Total " //"-v 187,raw48,Reported_Uncorrect " //"-v 192,raw48,Power-Off_Retract_Count " //"-v 196,raw16(raw16),Reallocated_Event_Count " //"-v 198,raw48,Offline_Uncorrectable " //"-v 199,raw48,UDMA_CRC_Error_Count " //"-v 232,raw48,Available_Reservd_Space " "" }, { "Samsung based SSDs", "SAMSUNG SSD PM800 .*GB|" // SAMSUNG PM800 SSDs, tested with SAMSUNG SSD PM800 TH 64GB/VBM25D1Q "SAMSUNG SSD PM810 .*GB|" // SAMSUNG PM810 (470 series) SSDs, tested with SAMSUNG SSD PM810 2.5" 128GB/AXM06D1Q "SAMSUNG 470 Series SSD|" // tested with SAMSUNG 470 Series SSD 64GB/AXM09B1Q "SAMSUNG SSD 830 Series|" // tested with SAMSUNG SSD 830 Series 64GB/CXM03B1Q "Samsung SSD 840 (PRO )?Series|" // tested with Samsung SSD 840 PRO Series 128GB/DXM04B0Q, // Samsung SSD 840 Series/DXT06B0Q "SAMSUNG MZ7WD((120|240)HAFV|480HAGM|960HAGP)-00003", // SM843T Series, tested with // SAMSUNG MZ7WD120HAFV-00003/DXM85W3Q "", "", //"-v 5,raw16(raw16),Reallocated_Sector_Ct " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " //"-v 175,raw48,Program_Fail_Count_Chip " //"-v 176,raw48,Erase_Fail_Count_Chip " //"-v 177,raw48,Wear_Leveling_Count " //"-v 178,raw48,Used_Rsvd_Blk_Cnt_Chip " //"-v 179,raw48,Used_Rsvd_Blk_Cnt_Tot " //"-v 180,raw48,Unused_Rsvd_Blk_Cnt_Tot " //"-v 181,raw48,Program_Fail_Cnt_Total " //"-v 182,raw48,Erase_Fail_Count_Total " //"-v 183,raw48,Runtime_Bad_Block " //"-v 184,raw48,End-to-End_Error " // SM843T Series "-v 187,raw48,Uncorrectable_Error_Cnt " //"-v 190,tempminmax,Airflow_Temperature_Cel " // seems to be some sort of temperature value for 470 Series? //"-v 194,tempminmax,Temperature_Celsius " "-v 195,raw48,ECC_Error_Rate " //"-v 198,raw48,Offline_Uncorrectable " "-v 199,raw48,CRC_Error_Count " "-v 201,raw48,Supercap_Status " "-v 202,raw48,Exception_Mode_Status " "-v 235,raw48,POR_Recovery_Count " // 830/840 Series //"-v 241,raw48,Total_LBAs_Written" }, { "Smart Storage Systems Xcel-10 SSDs", // based on http://www.smartm.com/files/salesLiterature/storage/xcel10.pdf "SMART A25FD-(32|64|128)GI32N", // tested with SMART A25FD-128GI32N/B9F23D4K "", "", // attributes info from http://www.adtron.com/pdf/SMART_Attributes_Xcel-10_810800014_RevB.pdf "-v 1,raw48,Not_Supported " "-v 2,raw48,Not_Supported " //"-v 9,raw24(raw8),Power_On_Hours " //"-v 12,raw48,Power_Cycle_Count " "-v 191,raw48,Not_Supported " //"-v 192,raw48,Power-Off_Retract_Count " "-v 197,raw48,ECC_Error_Count " //"-v 198,raw48,Offline_Uncorrectable " //"-v 199,raw48,UDMA_CRC_Error_Count " "-v 251,raw48,Min_Spares_Remain_Perc " // percentage of the total number of spare blocks available "-v 252,raw48,Added_Bad_Flash_Blk_Ct " // number of bad flash blocks "-v 254,raw48,Total_Erase_Blocks_Ct" // number of times the drive has erased any erase block }, { "Smart Storage Systems XceedSecure2 SSDs", "(SMART|Adtron) ([AIS]25FBS|S35FCS).*", "", "", "-v 9,sec2hour,Power_On_Hours " "-v 194,hex64,Proprietary_194" }, { "Smart Storage Systems XceedUltraX/Adtron A25FBX SSDs", "(SMART|Adtron) (A|I)25FBX.*", "", "", "-v 9,hex64,Proprietary_9 " "-v 194,hex48,Proprietary_194" }, { "Smart Storage Systems Adtron A25FB 2xN SSDs", "(SMART|Adtron) A25FB.*2.N", "", "", "-v 110,hex64,Proprietary_HWC " "-v 111,hex64,Proprietary_MP " "-v 112,hex64,Proprietary_RtR " "-v 113,hex64,Proprietary_RR " "-v 120,hex64,Proprietary_HFAll " "-v 121,hex64,Proprietary_HF1st " "-v 122,hex64,Proprietary_HF2nd " "-v 123,hex64,Proprietary_HF3rd " "-v 125,hex64,Proprietary_SFAll " "-v 126,hex64,Proprietary_SF1st " "-v 127,hex64,Proprietary_SF2nd " "-v 128,hex64,Proprietary_SF3rd " "-v 194,raw24/raw32:zvzzzw,Fractional_Temperature" }, { "Smart Storage Systems Adtron A25FB 3xN SSDs", "(SMART|Adtron) A25FB-.*3.N", "", "", "-v 9,sec2hour,Power_On_Hours " "-v 113,hex48,Proprietary_RR " "-v 130,raw48:54321,Minimum_Spares_All_Zs" //"-v 194,tempminmax,Temperature_Celsius" }, { "STEC Mach2 CompactFlash Cards", // tested with STEC M2P CF 1.0.0/K1385MS "STEC M2P CF 1.0.0", "", "", "-v 100,raw48,Erase_Program_Cycles " "-v 103,raw48,Remaining_Energy_Storg " "-v 170,raw48,Reserved_Block_Count " "-v 171,raw48,Program_Fail_Count " "-v 172,raw48,Erase_Fail_Count " "-v 173,raw48,Wear_Leveling_Count " "-v 174,raw48,Unexpect_Power_Loss_Ct " "-v 211,raw48,Unknown_Attribute " // ] Missing in specification "-v 212,raw48,Unknown_Attribute" // ] from September 2012 }, { "Transcend CompactFlash Cards", // tested with TRANSCEND/20080820, // TS4GCF133/20100709, TS16GCF133/20100709, TS16GCF150/20110407 "TRANSCEND|TS(4|8|16)GCF(133|150)", "", "", "-v 7,raw48,Unknown_Attribute " "-v 8,raw48,Unknown_Attribute" }, { "Marvell SSD SD88SA024BA0 (SUN branded)", "MARVELL SD88SA024BA0 SUN24G 0902M0054V", "", "", "" }, { "HP 1TB SATA disk GB1000EAFJL", "GB1000EAFJL", "", "", "" }, { "HP 500GB SATA disk MM0500EANCR", "MM0500EANCR", "", "", "" }, { "HP 250GB SATA disk VB0250EAVER", "VB0250EAVER", "", "", "" }, { "IBM Deskstar 60GXP", // ER60A46A firmware "(IBM-|Hitachi )?IC35L0[12346]0AVER07.*", "ER60A46A", "", "" }, { "IBM Deskstar 60GXP", // All other firmware "(IBM-|Hitachi )?IC35L0[12346]0AVER07.*", "", "IBM Deskstar 60GXP drives may need upgraded SMART firmware.\n" "Please see http://haque.net/dtla_update/", "" }, { "IBM Deskstar 40GV & 75GXP (A5AA/A6AA firmware)", "(IBM-)?DTLA-30[57]0[123467][05].*", "T[WX][123468AG][OF]A[56]AA", "", "" }, { "IBM Deskstar 40GV & 75GXP (all other firmware)", "(IBM-)?DTLA-30[57]0[123467][05].*", "", "IBM Deskstar 40GV and 75GXP drives may need upgraded SMART firmware.\n" "Please see http://haque.net/dtla_update/", "" }, { "", // ExcelStor J240, J340, J360, J680, J880 and J8160 "ExcelStor Technology J(24|34|36|68|88|816)0", "", "", "" }, { "", // Fujitsu M1623TAU "FUJITSU M1623TAU", "", "", "-v 9,seconds" }, { "Fujitsu MHG", "FUJITSU MHG2...ATU?.*", "", "", "-v 9,seconds" }, { "Fujitsu MHH", "FUJITSU MHH2...ATU?.*", "", "", "-v 9,seconds" }, { "Fujitsu MHJ", "FUJITSU MHJ2...ATU?.*", "", "", "-v 9,seconds" }, { "Fujitsu MHK", "FUJITSU MHK2...ATU?.*", "", "", "-v 9,seconds" }, { "", // Fujitsu MHL2300AT "FUJITSU MHL2300AT", "", "This drive's firmware has a harmless Drive Identity Structure\n" "checksum error bug.", "-v 9,seconds" }, { "", // MHM2200AT, MHM2150AT, MHM2100AT, MHM2060AT "FUJITSU MHM2(20|15|10|06)0AT", "", "This drive's firmware has a harmless Drive Identity Structure\n" "checksum error bug.", "-v 9,seconds" }, { "Fujitsu MHN", "FUJITSU MHN2...AT", "", "", "-v 9,seconds" }, { "", // Fujitsu MHR2020AT "FUJITSU MHR2020AT", "", "", "-v 9,seconds" }, { "", // Fujitsu MHR2040AT "FUJITSU MHR2040AT", "", // Tested on 40BA "", "-v 9,seconds -v 192,emergencyretractcyclect " "-v 198,offlinescanuncsectorct -v 200,writeerrorcount" }, { "Fujitsu MHS AT", "FUJITSU MHS20[6432]0AT( .)?", "", "", "-v 9,seconds -v 192,emergencyretractcyclect " "-v 198,offlinescanuncsectorct -v 200,writeerrorcount " "-v 201,detectedtacount" }, { "Fujitsu MHT", // tested with FUJITSU MHT2030AC/909B "FUJITSU MHT2...(AC|AH|AS|AT|BH)U?.*", "", "", "-v 9,seconds" }, { "Fujitsu MHU", "FUJITSU MHU2...ATU?.*", "", "", "-v 9,seconds" }, { "Fujitsu MHV", "FUJITSU MHV2...(AH|AS|AT|BH|BS|BT).*", "", "", "-v 9,seconds" }, { "Fujitsu MPA..MPG", "FUJITSU MP[A-G]3...A[HTEV]U?.*", "", "", "-v 9,seconds" }, { "Fujitsu MHY BH", "FUJITSU MHY2(04|06|08|10|12|16|20|25)0BH.*", "", "", "-v 240,raw48,Transfer_Error_Rate" }, { "Fujitsu MHW AC", // tested with FUJITSU MHW2060AC/00900004 "FUJITSU MHW20(40|60)AC", "", "", "" }, { "Fujitsu MHW BH", "FUJITSU MHW2(04|06|08|10|12|16)0BH.*", "", "", "" }, { "Fujitsu MHW BJ", "FUJITSU MHW2(08|12|16)0BJ.*", "", "", "" }, { "Fujitsu MHZ BH", "FUJITSU MHZ2(04|08|12|16|20|25|32)0BH.*", "", "", "" }, { "Fujitsu MHZ BJ", "FUJITSU MHZ2(08|12|16|20|25|32)0BJ.*", "", "", "-v 9,minutes" }, { "Fujitsu MHZ BS", "FUJITSU MHZ2(12|25)0BS.*", "", "", "" }, { "Fujitsu MHZ BK", "FUJITSU MHZ2(08|12|16|25)0BK.*", "", "", "" }, { "Fujitsu MJA BH", "FUJITSU MJA2(08|12|16|25|32|40|50)0BH.*", "", "", "" }, { "", // Samsung SV4012H (known firmware) "SAMSUNG SV4012H", "RM100-08", "", "-v 9,halfminutes -F samsung" }, { "", // Samsung SV4012H (all other firmware) "SAMSUNG SV4012H", "", "May need -F samsung disabled; see manual for details.", "-v 9,halfminutes -F samsung" }, { "", // Samsung SV0412H (known firmware) "SAMSUNG SV0412H", "SK100-01", "", "-v 9,halfminutes -v 194,10xCelsius -F samsung" }, { "", // Samsung SV0412H (all other firmware) "SAMSUNG SV0412H", "", "May need -F samsung disabled; see manual for details.", "-v 9,halfminutes -v 194,10xCelsius -F samsung" }, { "", // Samsung SV1204H (known firmware) "SAMSUNG SV1204H", "RK100-1[3-5]", "", "-v 9,halfminutes -v 194,10xCelsius -F samsung" }, { "", // Samsung SV1204H (all other firmware) "SAMSUNG SV1204H", "", "May need -F samsung disabled; see manual for details.", "-v 9,halfminutes -v 194,10xCelsius -F samsung" }, { "", // SAMSUNG SV0322A tested with FW JK200-35 "SAMSUNG SV0322A", "", "", "" }, { "SAMSUNG SpinPoint V80", // tested with SV1604N/TR100-23 "SAMSUNG SV(0211|0401|0612|0802|1203|1604)N", "", "", "-v 9,halfminutes -F samsung2" }, { "", // SAMSUNG SP40A2H with RR100-07 firmware "SAMSUNG SP40A2H", "RR100-07", "", "-v 9,halfminutes -F samsung" }, { "", // SAMSUNG SP80A4H with RT100-06 firmware "SAMSUNG SP80A4H", "RT100-06", "", "-v 9,halfminutes -F samsung" }, { "", // SAMSUNG SP8004H with QW100-61 firmware "SAMSUNG SP8004H", "QW100-61", "", "-v 9,halfminutes -F samsung" }, { "SAMSUNG SpinPoint F1 DT", // tested with HD103UJ/1AA01113 "SAMSUNG HD(083G|16[12]G|25[12]H|32[12]H|50[12]I|642J|75[23]L|10[23]U)J", "", "", "" }, { "SAMSUNG SpinPoint F1 EG", // tested with HD103UI/1AA01113 "SAMSUNG HD(252H|322H|502I|642J|753L|103U)I", "", "", "" }, { "SAMSUNG SpinPoint F1 RE", // tested with HE103UJ/1AA01113 "SAMSUNG HE(252H|322H|502I|642J|753L|103U)J", "", "", "" }, { "SAMSUNG SpinPoint F2 EG", // tested with HD154UI/1AG01118 "SAMSUNG HD(502H|10[23]S|15[34]U)I", "", "", "" }, { "SAMSUNG SpinPoint F3", // tested with HD502HJ/1AJ100E4 "SAMSUNG HD(502H|754J|103S)J", "", "", "" }, { "Seagate Barracuda SpinPoint F3", // tested with ST1000DM005 HD103SJ/1AJ100E5 "ST[0-9DM]* HD(502H|754J|103S)J", "", "", "" }, { "SAMSUNG SpinPoint F3 EG", // tested with HD503HI/1AJ100E4, HD153WI/1AN10002 "SAMSUNG HD(253G|(324|503)H|754J|105S|(153|203)W)I", "", "", "" }, { "SAMSUNG SpinPoint F3 RE", // tested with HE103SJ/1AJ30001 "SAMSUNG HE(502H|754J|103S)J", "", "", "" }, { "SAMSUNG SpinPoint F4 EG (AF)",// tested with HD204UI/1AQ10001(buggy|fixed) "SAMSUNG HD(155|204)UI", "", // 1AQ10001 "Using smartmontools or hdparm with this\n" "drive may result in data loss due to a firmware bug.\n" "****** THIS DRIVE MAY OR MAY NOT BE AFFECTED! ******\n" "Buggy and fixed firmware report same version number!\n" "See the following web pages for details:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/223571en\n" "http://sourceforge.net/apps/trac/smartmontools/wiki/SamsungF4EGBadBlocks", "" }, { "SAMSUNG SpinPoint S250", // tested with HD200HJ/KF100-06 "SAMSUNG HD(162|200|250)HJ", "", "", "" }, { "SAMSUNG SpinPoint T133", // tested with HD300LJ/ZT100-12, HD400LJ/ZZ100-14, HD401LJ/ZZ100-15 "SAMSUNG HD(250KD|(30[01]|320|40[01])L[DJ])", "", "", "" }, { "SAMSUNG SpinPoint T166", // tested with HD501LJ/CR100-1[01] "SAMSUNG HD(080G|160H|32[01]K|403L|50[01]L)J", "", "", "-v 197,increasing" // at least HD501LJ/CR100-11 }, { "SAMSUNG SpinPoint P120", // VF100-37 firmware, tested with SP2514N/VF100-37 "SAMSUNG SP(16[01]3|2[05][01]4)[CN]", "VF100-37", "", "-F samsung3" }, { "SAMSUNG SpinPoint P120", // other firmware, tested with SP2504C/VT100-33 "SAMSUNG SP(16[01]3|2[05][01]4)[CN]", "", "May need -F samsung3 enabled; see manual for details.", "" }, { "SAMSUNG SpinPoint P80 SD", // tested with HD160JJ/ZM100-33 "SAMSUNG HD(080H|120I|160J)J", "", "", "" }, { "SAMSUNG SpinPoint P80", // BH100-35 firmware, tested with SP0842N/BH100-35 "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]", "BH100-35", "", "-F samsung3" }, { "SAMSUNG SpinPoint P80", // firmware *-35 or later "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]", ".*-3[5-9]", "May need -F samsung3 enabled; see manual for details.", "" }, { "SAMSUNG SpinPoint P80", // firmware *-25...34, tested with // SP0401N/TJ100-30, SP1614C/SW100-25 and -34 "SAMSUNG SP(04[05]1|08[0124]2|12[0145]3|16[0145]4)[CN]", ".*-(2[5-9]|3[0-4])", "", "-v 9,halfminutes -v 198,increasing" }, { "SAMSUNG SpinPoint P80", // firmware *-23...24, tested with // SP0802N/TK100-23, // SP1213N/TL100-23, // SP1604N/TM100-23 and -24 "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]", ".*-2[34]", "", "-v 9,halfminutes -F samsung2" }, { "SAMSUNG SpinPoint P80", // unknown firmware "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]", "", "May need -F samsung2 or -F samsung3 enabled; see manual for details.", "" }, { "SAMSUNG SpinPoint M40/60/80", // tested with HM120IC/AN100-16, HM160JI/AD100-16 "SAMSUNG HM(0[468]0H|120I|1[026]0J)[CI]", "", "", "-v 9,halfminutes" }, { "SAMSUNG SpinPoint M5", // tested with HM160HI/HH100-12 "SAMSUNG HM(((061|080)G|(121|160)H|250J)I|160HC)", "", "", "" }, { "SAMSUNG SpinPoint M6", // tested with HM320JI/2SS00_01 M6 "SAMSUNG HM(251J|320[HJ]|[45]00L)I", "", "", "" }, { "SAMSUNG SpinPoint M7", // tested with HM500JI/2AC101C4 "SAMSUNG HM(250H|320I|[45]00J)I", "", "", "" }, { "SAMSUNG SpinPoint M7E (AF)", // tested with HM321HI/2AJ10001, HM641JI/2AJ10001 "SAMSUNG HM(161G|(251|321)H|501I|641J)I", "", "", "" }, { "SAMSUNG SpinPoint M7U (USB)", // tested with HM252HX/2AC101C4 "SAMSUNG HM(162H|252H|322I|502J)X", "", "", "" }, { "SAMSUNG SpinPoint M8 (AF)", // tested with HN-M101MBB/2AR10001 "SAMSUNG HN-M(250|320|500|640|750|101)MBB", "", "", "" }, { "Seagate Momentus SpinPoint M8 (AF)", // tested with // ST750LM022 HN-M750MBB/2AR10001, ST320LM001 HN-M320MBB/2AR10002 "ST(250|320|500|640|750|1000)LM0[012][124] HN-M[0-9]*MBB", "", "", "" }, { "SAMSUNG SpinPoint M8U (USB)", // tested with HN-M500XBB/2AR10001 "SAMSUNG HN-M(320|500|750|101)XBB", "", "", "" }, { "Seagate Samsung SpinPoint M8U (USB)", // tested with ST1000LM025 HN-M101ABB/2AR10001 "ST(250|320|500|640|750|1000)LM0[012][3459] HN-M[0-9]*ABB", "", "", "" }, { "SAMSUNG SpinPoint MP5", // tested with HM250HJ/2AK10001 "SAMSUNG HM(250H|320H|500J|640J)J", "", "", "" }, { "SAMSUNG SpinPoint MT2", // tested with HM100UI/2AM10001 "SAMSUNG HM100UI", "", "", "" }, { "SAMSUNG HM100UX (S2 Portable)", // tested with HM100UX/2AM10001 "SAMSUNG HM100UX", "", "", "" }, { "SAMSUNG SpinPoint M", // tested with MP0402H/UC100-11 "SAMSUNG MP0(302|402|603|804)H", "", "", "-v 9,halfminutes" }, { "SAMSUNG SpinPoint N3U-3 (USB, 4KiB LLS)", // tested with HS25YJZ/3AU10-01 "SAMSUNG HS(122H|2[05]YJ)Z", "", "", "" }, { "Maxtor Fireball 541DX", "Maxtor 2B0(0[468]|1[05]|20)H1", "", "", "-v 9,minutes -v 194,unknown" }, { "Maxtor Fireball 3", "Maxtor 2F0[234]0[JL]0", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 1280 ATA", // no self-test log, ATA2-Fast "Maxtor 8(1280A2|2160A4|2560A4|3840A6|4000A6|5120A8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 2160 Ultra ATA", "Maxtor 8(2160D2|3228D3|3240D3|4320D4|6480D6|8400D8|8455D8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 2880 Ultra ATA", "Maxtor 9(0510D4|0576D4|0648D5|0720D5|0840D6|0845D6|0864D6|1008D7|1080D8|1152D8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 3400 Ultra ATA", "Maxtor 9(1(360|350|202)D8|1190D7|10[12]0D6|0840D5|06[48]0D4|0510D3|1(350|202)E8|1010E6|0840E5|0640E4)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax D540X-4G", "Maxtor 4G(120J6|160J[68])", "", "", "-v 9,minutes -v 194,unknown" }, { "Maxtor DiamondMax D540X-4K", "MAXTOR 4K(020H1|040H2|060H3|080H4)", "", "", "" }, { "Maxtor DiamondMax Plus D740X", "MAXTOR 6L0(20[JL]1|40[JL]2|60[JL]3|80[JL]4)", "", "", "" }, { "Maxtor DiamondMax Plus 5120 Ultra ATA 33", "Maxtor 9(0512D2|0680D3|0750D3|0913D4|1024D4|1360D6|1536D6|1792D7|2048D8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax Plus 6800 Ultra ATA 66", "Maxtor 9(2732U8|2390U7|204[09]U6|1707U5|1366U4|1024U3|0845U3|0683U2)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax D540X-4D", "Maxtor 4D0(20H1|40H2|60H3|80H4)", "", "", "-v 9,minutes -v 194,unknown" }, { "Maxtor DiamondMax 16", "Maxtor 4(R0[68]0[JL]0|R1[26]0L0|A160J0|R120L4)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 4320 Ultra ATA", "Maxtor (91728D8|91512D7|91303D6|91080D5|90845D4|90645D3|90648D[34]|90432D2)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 17 VL", "Maxtor 9(0431U1|0641U2|0871U2|1301U3|1741U4)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 20 VL", "Maxtor (94091U8|93071U6|92561U5|92041U4|91731U4|91531U3|91361U3|91021U2|90841U2|90651U2)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax VL 30", // U: ATA66, H: ATA100 "Maxtor (33073U4|32049U3|31536U2|30768U1|33073H4|32305H3|31536H2|30768H1)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 36", "Maxtor (93652U8|92739U6|91826U4|91369U3|90913U2|90845U2|90435U1)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 40 ATA 66", "Maxtor 9(0684U2|1024U2|1362U3|1536U3|2049U4|2562U5|3073U6|4098U8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax Plus 40 (Ultra ATA 66 and Ultra ATA 100)", "Maxtor (54098[UH]8|53073[UH]6|52732[UH]6|52049[UH]4|51536[UH]3|51369[UH]3|51024[UH]2)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 40 VL Ultra ATA 100", "Maxtor 3(1024H1|1535H2|2049H2|3073H3|4098H4)( B)?", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax Plus 45 Ulta ATA 100", "Maxtor 5(4610H6|4098H6|3073H4|2049H3|1536H2|1369H2|1023H2)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 60 ATA 66", "Maxtor 9(1023U2|1536U2|2049U3|2305U3|3073U4|4610U6|6147U8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 60 ATA 100", "Maxtor 9(1023H2|1536H2|2049H3|2305H3|3073H4|4098H6|4610H6|6147H8)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax Plus 60", "Maxtor 5T0(60H6|40H4|30H3|20H2|10H1)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 80", "Maxtor (98196H8|96147H6)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 536DX", "Maxtor 4W(100H6|080H6|060H4|040H3|030H2)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax Plus 8", "Maxtor 6(E0[234]|K04)0L0", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 10 (ATA/133 and SATA/150)", "Maxtor 6(B(30|25|20|16|12|10|08)0[MPRS]|L(080[MLP]|(100|120)[MP]|160[MP]|200[MPRS]|250[RS]|300[RS]))0", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 10 (SATA/300)", "Maxtor 6V(080E|160E|200E|250F|300F|320F)0", "", "", "" }, { "Maxtor DiamondMax Plus 9", "Maxtor 6Y((060|080|120|160)L0|(060|080|120|160|200|250)P0|(060|080|120|160|200|250)M0)", "", "", "-v 9,minutes" }, { "Maxtor DiamondMax 11", "Maxtor 6H[45]00[FR]0", "", "", "" }, { "Maxtor DiamondMax 17", "Maxtor 6G(080L|160[PE])0", "", "", "" }, { "Seagate Maxtor DiamondMax 20", "MAXTOR STM3(40|80|160)[28]1[12]0?AS?", "", "", "" }, { "Seagate Maxtor DiamondMax 21", // tested with MAXTOR STM3250310AS/3.AAF "MAXTOR STM3(80[28]15|160215|250310|(250|320)820|320620|500630)AS?", "", "", "" }, { "Seagate Maxtor DiamondMax 22", // fixed firmware "(MAXTOR )?STM3(500320|750330|1000340)AS?", "MX1A", // http://knowledge.seagate.com/articles/en_US/FAQ/207969en "", "" }, { "Seagate Maxtor DiamondMax 22", // fixed firmware "(MAXTOR )?STM3(160813|320614|640323|1000334)AS?", "MX1B", // http://knowledge.seagate.com/articles/en_US/FAQ/207975en "", "" }, { "Seagate Maxtor DiamondMax 22", // buggy firmware "(MAXTOR )?STM3(500320|750330|1000340)AS?", "MX15", "There are known problems with these drives,\n" "AND THIS FIRMWARE VERSION IS AFFECTED,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207969en", "" }, { "Seagate Maxtor DiamondMax 22", // unknown firmware "(MAXTOR )?STM3(160813|32061[34]|500320|640323|750330|10003(34|40))AS?", "", "There are known problems with these drives,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207969en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207975en", "" }, { "Seagate Maxtor DiamondMax 23", // new firmware "STM3((160|250)31|(320|500)41|(750|1000)52)8AS?", "CC3[D-Z]", "", "" }, { "Seagate Maxtor DiamondMax 23", // unknown firmware "STM3((160|250)31|(320|500)41|(750|1000)52)8AS?", "", "A firmware update for this drive may be available,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/213911en", "" }, { "Maxtor MaXLine Plus II", "Maxtor 7Y250[PM]0", "", "", "-v 9,minutes" }, { "Maxtor MaXLine II", "Maxtor [45]A(25|30|32)0[JN]0", "", "", "-v 9,minutes" }, { "Maxtor MaXLine III (ATA/133 and SATA/150)", "Maxtor 7L(25|30)0[SR]0", "", "", "-v 9,minutes" }, { "Maxtor MaXLine III (SATA/300)", "Maxtor 7V(25|30)0F0", "", "", "" }, { "Maxtor MaXLine Pro 500", // There is also a 7H500R0 model, but I "Maxtor 7H500F0", // haven't added it because I suspect "", // it might need vendoropts_9_minutes "", "" // and nobody has submitted a report yet }, { "", // HITACHI_DK14FA-20B "HITACHI_DK14FA-20B", "", "", "-v 9,minutes -v 193,loadunload" }, { "HITACHI Travelstar DK23XX/DK23XXB", "HITACHI_DK23..-..B?", "", "", "-v 9,minutes -v 193,loadunload" }, { "Hitachi Endurastar J4K20/N4K20 (formerly DK23FA-20J)", "(HITACHI_DK23FA-20J|HTA422020F9AT[JN]0)", "", "", "-v 9,minutes -v 193,loadunload" }, { "Hitachi Endurastar J4K30/N4K30", "HE[JN]4230[23]0F9AT00", "", "", "-v 9,minutes -v 193,loadunload" }, { "Hitachi Travelstar C4K60", // 1.8" slim drive "HTC4260[23]0G5CE00|HTC4260[56]0G8CE00", "", "", "-v 9,minutes -v 193,loadunload" }, { "IBM Travelstar 4GT", "IBM-DTCA-2(324|409)0", "", "", "" }, { "IBM Travelstar 6GN", "IBM-DBCA-20(324|486|648)0", "", "", "" }, { "IBM Travelstar 25GS, 18GT, and 12GN", "IBM-DARA-2(25|18|15|12|09|06)000", "", "", "" }, { "IBM Travelstar 14GS", "IBM-DCYA-214000", "", "", "" }, { "IBM Travelstar 4LP", "IBM-DTNA-2(180|216)0", "", "", "" }, { "IBM Travelstar 48GH, 30GN, and 15GN", "(IBM-|Hitachi )?IC25(T048ATDA05|N0(30|20|15|12|10|07|06|05)ATDA04)-.", "", "", "" }, { "IBM Travelstar 32GH, 30GT, and 20GN", "IBM-DJSA-2(32|30|20|10|05)", "", "", "" }, { "IBM Travelstar 4GN", "IBM-DKLA-2(216|324|432)0", "", "", "" }, { "IBM/Hitachi Travelstar 60GH and 40GN", "(IBM-|Hitachi )?IC25(T060ATC[SX]05|N0[4321]0ATC[SX]04)-.", "", "", "" }, { "IBM/Hitachi Travelstar 40GNX", "(IBM-|Hitachi )?IC25N0[42]0ATC[SX]05-.", "", "", "" }, { "Hitachi Travelstar 80GN", "(Hitachi )?IC25N0[23468]0ATMR04-.", "", "", "" }, { "Hitachi Travelstar 4K40", "(Hitachi )?HTS4240[234]0M9AT00", "", "", "" }, { "Hitachi Travelstar 4K120", "(Hitachi )?(HTS4212(60|80|10|12)H9AT00|HTS421260G9AT00)", "", "", "" }, { "Hitachi Travelstar 5K80", "(Hitachi )?HTS5480[8642]0M9AT00", "", "", "" }, { "Hitachi Travelstar 5K100", "(Hitachi )?HTS5410[1864]0G9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar E5K100", "(Hitachi )?HTE541040G9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar 5K120", "(Hitachi )?HTS5412(60|80|10|12)H9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar 5K160", "(Hitachi |HITACHI )?HTS5416([468]0|1[26])J9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar E5K160", "(Hitachi )?HTE5416(12|16|60|80)J9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar 5K250", "(Hitachi |HITACHI )?HTS5425(80|12|16|20|25)K9(A3|SA)00", "", "", "" }, { "Hitachi Travelstar 5K320", // tested with HITACHI HTS543232L9SA00/FB4ZC4EC, // Hitachi HTS543212L9SA02/FBBAC52F "(Hitachi |HITACHI )?HT(S|E)5432(80|12|16|25|32)L9(A3(00)?|SA0[012])", "", "", "" }, { "Hitachi Travelstar 5K500.B", "(Hitachi )?HT[ES]5450(12|16|25|32|40|50)B9A30[01]", "", "", "" }, { "Hitachi/HGST Travelstar Z5K500", // tested with HGST HTS545050A7E380/GG2OAC90 "HGST HT[ES]5450(25|32|50)A7E38[01]", "", "", "" }, { "Hitachi/HGST Travelstar 5K750", // tested with Hitachi HTS547575A9E384/JE4OA60A, // APPLE HDD HTS547550A9E384/JE3AD70F "(Hitachi|APPLE HDD) HT[ES]5475(50|64|75)A9E38[14]", "", "", "" }, { "Hitachi Travelstar 7K60", "(Hitachi )?HTS726060M9AT00", "", "", "" }, { "Hitachi Travelstar E7K60", "(Hitachi )?HTE7260[46]0M9AT00", "", "", "" }, { "Hitachi Travelstar 7K100", "(Hitachi )?HTS7210[168]0G9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar E7K100", "(Hitachi )?HTE7210[168]0G9(AT|SA)00", "", "", "" }, { "Hitachi Travelstar 7K200", // tested with HITACHI HTS722016K9SA00/DCDZC75A "(Hitachi |HITACHI )?HTS7220(80|10|12|16|20)K9(A3|SA)00", "", "", "" }, { "Hitachi Travelstar 7K320", // tested with // HTS723225L9A360/FCDOC30F, HTS723216L9A362/FC2OC39F "(Hitachi )?HT[ES]7232(80|12|16|25|32)L9(A300|A36[02]|SA61)", "", "", "" }, { "Hitachi Travelstar Z7K320", // tested with HITACHI HTS723232A7A364/EC2ZB70B "(HITACHI )?HT[ES]7232(16|25|32)A7A36[145]", "", "", "" }, { "Hitachi Travelstar 7K500", "(Hitachi )?HT[ES]7250(12|16|25|32|50)A9A36[2-5]", "", "", "" }, { "Hitachi/HGST Travelstar Z7K500", // tested with HITACHI HTS725050A7E630/GH2ZB390, // HGST HTS725050A7E630/GH2OA420 "(HITACHI|HGST) HT[ES]7250(25|32|50)A7E63[015]", "", "", "" }, { "Hitachi/HGST Travelstar 7K750", // tested with Hitachi HTS727550A9E364/JF3OA0E0, // Hitachi HTS727575A9E364/JF4OA0D0 "(Hitachi|HGST) HT[ES]7275(50|64|75)A9E36[14]", "", "", "" }, { "HGST Travelstar 7K1000", // tested with HGST HTS721010A9E630/JB0OA3B0 "HGST HTS721010A9E630", "", "", "" }, { "IBM Deskstar 14GXP and 16GP", "IBM-DTTA-3(7101|7129|7144|5032|5043|5064|5084|5101|5129|5168)0", "", "", "" }, { "IBM Deskstar 25GP and 22GXP", "IBM-DJNA-3(5(101|152|203|250)|7(091|135|180|220))0", "", "", "" }, { "IBM Deskstar 37GP and 34GXP", "IBM-DPTA-3(5(375|300|225|150)|7(342|273|205|136))0", "", "", "" }, { "IBM/Hitachi Deskstar 120GXP", "(IBM-)?IC35L((020|040|060|080|120)AVVA|0[24]0AVVN)07-[01]", "", "", "" }, { "IBM/Hitachi Deskstar GXP-180", "(IBM-)?IC35L(030|060|090|120|180)AVV207-[01]", "", "", "" }, { "Hitachi Deskstar 5K3000", // tested with HDS5C3030ALA630/MEAOA5C0, // Hitachi HDS5C3020BLE630/MZ4OAAB0 (OEM, Toshiba Canvio Desktop) "(Hitachi )?HDS5C30(15|20|30)(ALA|BLE)63[02].*", "", "", "" }, { "Hitachi Deskstar 5K4000", // tested with HDS5C4040ALE630/MPAOA250 "(Hitachi )?HDS5C40(30|40)ALE63[01].*", "", "", "" }, { "Hitachi Deskstar 7K80", "(Hitachi )?HDS7280([48]0PLAT20|(40)?PLA320|80PLA380).*", "", "", "" }, { "Hitachi Deskstar 7K160", "(Hitachi )?HDS7216(80|16)PLA[3T]80.*", "", "", "" }, { "Hitachi Deskstar 7K250", "(Hitachi )?HDS7225((40|80|12|16)VLAT20|(12|16|25)VLAT80|(80|12|16|25)VLSA80)", "", "", "" }, { "Hitachi Deskstar 7K250 (SUN branded)", "HITACHI HDS7225SBSUN250G.*", "", "", "" }, { "Hitachi Deskstar T7K250", "(Hitachi )?HDT7225((25|20|16)DLA(T80|380))", "", "", "" }, { "Hitachi Deskstar 7K400", "(Hitachi )?HDS724040KL(AT|SA)80", "", "", "" }, { "Hitachi Deskstar 7K500", "(Hitachi )?HDS725050KLA(360|T80)", "", "", "" }, { "Hitachi Deskstar P7K500", "(Hitachi )?HDP7250(16|25|32|40|50)GLA(36|38|T8)0", "", "", "" }, { "Hitachi Deskstar T7K500", "(Hitachi )?HDT7250(25|32|40|50)VLA(360|380|T80)", "", "", "" }, { "Hitachi Deskstar 7K1000", "(Hitachi )?HDS7210(50|75|10)KLA330", "", "", "" }, { "Hitachi Deskstar 7K1000.B", "(Hitachi )?HDT7210((16|25)SLA380|(32|50|64|75|10)SLA360)", "", "", "" }, { "Hitachi Deskstar 7K1000.C", // tested with Hitachi HDS721010CLA330/JP4OA3MA "(Hitachi )?HDS7210((16|25)CLA382|(32|50)CLA362|(64|75|10)CLA33[02])", "", "", "" }, { "Hitachi Deskstar 7K1000.D", // tested with HDS721010DLE630/MS2OA5Q0 "Hitachi HDS7210(25|32|50|75|10)DLE630", "", "", "" }, { "Hitachi Deskstar E7K1000", // tested with HDE721010SLA330/ST6OA31B "Hitachi HDE7210(50|75|10)SLA330", "", "", "" }, { "Hitachi Deskstar 7K2000", "Hitachi HDS722020ALA330", "", "", "" }, { "Hitachi Deskstar 7K3000", // tested with HDS723030ALA640/MKAOA3B0 "Hitachi HDS7230((15|20)BLA642|30ALA640)", "", "", "" }, { "Hitachi/HGST Deskstar 7K4000", // tested with Hitachi HDS724040ALE640/MJAOA250 "Hitachi HDS724040ALE640", "", "", "" }, { "Hitachi Ultrastar A7K1000", // tested with // HUA721010KLA330 44X2459 42C0424IBM/GKAOAB4A "(Hitachi )?HUA7210(50|75|10)KLA330.*", "", "", "" }, { "Hitachi Ultrastar A7K2000", // tested with // HUA722010CLA330 43W7629 42C0401IBM "(Hitachi )?HUA7220(50|10|20)[AC]LA33[01].*", "", "", "" }, { "Hitachi Ultrastar 7K3000", // tested with HUA723030ALA640/MKAOA580 "Hitachi HUA7230(20|30)ALA640", "", "", "" }, { "Hitachi Ultrastar 7K4000", // tested with Hitachi HUS724040ALE640/MJAOA3B0 "Hitachi HUS7240(20|30|40)ALE640", "", "", "" }, { "Toshiba 2.5\" HDD (10-20 GB)", "TOSHIBA MK(101[67]GAP|15[67]GAP|20(1[678]GAP|(18|23)GAS))", "", "", "" }, { "Toshiba 2.5\" HDD (30-60 GB)", "TOSHIBA MK((6034|4032)GSX|(6034|4032)GAX|(6026|4026|4019|3019)GAXB?|(6025|6021|4025|4021|4018|3025|3021|3018)GAS|(4036|3029)GACE?|(4018|3017)GAP)", "", "", "" }, { "Toshiba 2.5\" HDD (80 GB and above)", "TOSHIBA MK(80(25GAS|26GAX|32GAX|32GSX)|10(31GAS|32GAX)|12(33GAS|34G[AS]X)|2035GSS)", "", "", "" }, { "Toshiba 2.5\" HDD MK..37GSX", // tested with TOSHIBA MK1637GSX/DL032C "TOSHIBA MK(12|16)37GSX", "", "", "" }, { "Toshiba 2.5\" HDD MK..46GSX", // tested with TOSHIBA MK1246GSX/LB213M "TOSHIBA MK(80|12|16|25)46GSX", "", "", "" }, { "Toshiba 2.5\" HDD MK..50GACY", // tested with TOSHIBA MK8050GACY/TF105A "TOSHIBA MK8050GACY", "", "", "" }, { "Toshiba 2.5\" HDD MK..52GSX", "TOSHIBA MK(80|12|16|25|32)52GSX", "", "", "" }, { "Toshiba 2.5\" HDD MK..55GSX", // tested with TOSHIBA MK5055GSX/FG001A, MK3255GSXF/FH115B "TOSHIBA MK(12|16|25|32|40|50)55GSXF?", "", "", "" }, { "Toshiba 2.5\" HDD MK..56GSY", // tested with TOSHIBA MK2556GSYF/LJ001D "TOSHIBA MK(16|25|32|50)56GSYF?", "", "", "-v 9,minutes" }, { "Toshiba 2.5\" HDD MK..59GSXP (AF)", "TOSHIBA MK(32|50|64|75)59GSXP?", "", "", "" }, { "Toshiba 2.5\" HDD MK..59GSM (AF)", "TOSHIBA MK(75|10)59GSM", "", "", "" }, { "Toshiba 2.5\" HDD MK..61GSY[N]", // tested with TOSHIBA MK5061GSY/MC102E, MK5061GSYN/MH000A "TOSHIBA MK(16|25|32|50|64)61GSYN?", "", "", "" }, { "Toshiba 2.5\" HDD MK..65GSX", // tested with TOSHIBA MK5065GSX/GJ003A, MK3265GSXN/GH012H, // MK5065GSXF/GP006B "TOSHIBA MK(16|25|32|50|64)65GSX[FN]?", "", "", "" }, { "Toshiba 2.5\" HDD MK..76GSX", // tested with TOSHIBA MK3276GSX/GS002D "TOSHIBA MK(16|25|32|50|64)76GSX", "", "", "-v 9,minutes" }, { "Toshiba 2.5\" HDD MQ01ABD...", // tested with TOSHIBA MQ01ABD100/AX001U "TOSHIBA MQ01ABD(025|032|050|064|075|100)", "", "", "" }, { "Toshiba 3.5\" HDD MK.002TSKB", // tested with TOSHIBA MK1002TSKB/MT1A "TOSHIBA MK(10|20)02TSKB", "", "", "" }, { "Toshiba 3.5\" HDD DT01ACA...", // tested with TOSHIBA DT01ACA100/MS2OA750, // TOSHIBA DT01ACA200/MX4OABB0, TOSHIBA DT01ACA300/MX6OABB0 "TOSHIBA DT01ACA(025|032|050|075|100|150|200|300)", "", "", "" }, { "Toshiba 1.8\" HDD", "TOSHIBA MK[23468]00[4-9]GA[HL]", "", "", "" }, { "Toshiba 1.8\" HDD MK..29GSG", "TOSHIBA MK(12|16|25)29GSG", "", "", "" }, { "", // TOSHIBA MK6022GAX "TOSHIBA MK6022GAX", "", "", "" }, { "", // TOSHIBA MK6409MAV "TOSHIBA MK6409MAV", "", "", "" }, { "Toshiba MKx019GAXB (SUN branded)", "TOS MK[34]019GAXB SUN[34]0G", "", "", "" }, { "Seagate Momentus", "ST9(20|28|40|48)11A", "", "", "" }, { "Seagate Momentus 42", "ST9(2014|3015|4019)A", "", "", "" }, { "Seagate Momentus 4200.2", // tested with ST960812A/3.05 "ST9(100822|808210|60812|50212|402113|30219)A", "", "", "" }, { "Seagate Momentus 5400.2", "ST9(808211|6082[12]|408114|308110|120821|10082[34]|8823|6812|4813|3811)AS?", "", "", "" }, { "Seagate Momentus 5400.3", "ST9(4081[45]|6081[35]|8081[15]|100828|120822|160821)AS?", "", "", "" }, { "Seagate Momentus 5400.3 ED", "ST9(4081[45]|6081[35]|8081[15]|100828|120822|160821)AB", "", "", "" }, { "Seagate Momentus 5400.4", "ST9(120817|(160|200|250)827)AS", "", "", "" }, { "Seagate Momentus 5400.5", "ST9((80|120|160)310|(250|320)320)AS", "", "", "" }, { "Seagate Momentus 5400.6", "ST9(80313|160(301|314)|(12|25)0315|250317|(320|500)325|500327|640320)ASG?", "", "", "" }, { "Seagate Momentus 5400.7", "ST9(160316|(250|320)310|(500|640)320)AS", "", "", "" }, { "Seagate Momentus 5400.7 (AF)", // tested with ST9640322AS/0001BSM2 // (device reports 4KiB LPS with 1 sector offset) "ST9(320312|400321|640322|750423)AS", "", "", "" }, { "Seagate Momentus 5400 PSD", // Hybrid drives "ST9(808212|(120|160)8220)AS", "", "", "" }, { "Seagate Momentus 7200.1", "ST9(10021|80825|6023|4015)AS?", "", "", "" }, { "Seagate Momentus 7200.2", "ST9(80813|100821|120823|160823|200420)ASG?", "", "", "" }, { "Seagate Momentus 7200.3", "ST9((80|120|160)411|(250|320)421)ASG?", "", "", "" }, { "Seagate Momentus 7200.4", "ST9(160412|250410|320423|500420)ASG?", "", "", "" }, { "Seagate Momentus 7200 FDE.2", "ST9((160413|25041[12]|320426|50042[12])AS|(16041[489]|2504[16]4|32042[67]|500426)ASG)", "", "", "" }, { "Seagate Momentus 7200.5", // tested with ST9750420AS/0001SDM5, ST9750420AS/0002SDM1 "ST9(50042[34]|64042[012]|75042[02])ASG?", "", "", "" }, { "Seagate Momentus XT", // fixed firmware "ST9(2505610|3205620|5005620)AS", "SD2[68]", // http://knowledge.seagate.com/articles/en_US/FAQ/215451en "", "" }, { "Seagate Momentus XT", // buggy firmware, tested with ST92505610AS/SD24 "ST9(2505610|3205620|5005620)AS", "SD2[45]", "These drives may corrupt large files,\n" "AND THIS FIRMWARE VERSION IS AFFECTED,\n" "see the following web pages for details:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/215451en\n" "http://forums.seagate.com/t5/Momentus-XT-Momentus-Momentus/Momentus-XT-corrupting-large-files-Linux/td-p/109008\n" "http://superuser.com/questions/313447/seagate-momentus-xt-corrupting-files-linux-and-mac", "" }, { "Seagate Momentus XT", // unknown firmware "ST9(2505610|3205620|5005620)AS", "", "These drives may corrupt large files,\n" "see the following web pages for details:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/215451en\n" "http://forums.seagate.com/t5/Momentus-XT-Momentus-Momentus/Momentus-XT-corrupting-large-files-Linux/td-p/109008\n" "http://superuser.com/questions/313447/seagate-momentus-xt-corrupting-files-linux-and-mac", "" }, { "Seagate Momentus XT (AF)", // tested with ST750LX003-1AC154/SM12 "ST750LX003-.*", "", "", "" }, { "Seagate Momentus Thin", // tested with ST320LT007-9ZV142/0004LVM1 "ST(160|250|320)LT0(07|09|11|14)-.*", "", "", "" }, { "Seagate Laptop SSHD", // tested with ST500LM000-1EJ162/SM11 "ST(500|1000)LM0(00|14)-.*", "", "", "" }, { "Seagate Medalist 1010, 1720, 1721, 2120, 3230 and 4340", // ATA2, with -t permissive "ST3(1010|1720|1721|2120|3230|4340)A", "", "", "" }, { "Seagate Medalist 2110, 3221, 4321, 6531, and 8641", "ST3(2110|3221|4321|6531|8641)A", "", "", "" }, { "Seagate U4", "ST3(2112|4311|6421|8421)A", "", "", "" }, { "Seagate U5", "ST3(40823|30621|20413|15311|10211)A", "", "", "" }, { "Seagate U6", "ST3(8002|6002|4081|3061|2041)0A", "", "", "" }, { "Seagate U7", "ST3(30012|40012|60012|80022|120020)A", "", "", "" }, { "Seagate U8", "ST3(4313|6811|8410|4313|13021|17221)A", "", "", "" }, { "Seagate U9", // tested with ST3160022ACE/9.51 "ST3(80012|120025|160022)A(CE)?", "", "", "" }, { "Seagate U10", "ST3(20423|15323|10212)A", "", "", "" }, { "Seagate UX", "ST3(10014A(CE)?|20014A)", "", "", "" }, { "Seagate Barracuda ATA", "ST3(2804|2724|2043|1362|1022|681)0A", "", "", "" }, { "Seagate Barracuda ATA II", "ST3(3063|2042|1532|1021)0A", "", "", "" }, { "Seagate Barracuda ATA III", "ST3(40824|30620|20414|15310|10215)A", "", "", "" }, { "Seagate Barracuda ATA IV", "ST3(20011|30011|40016|60021|80021)A", "", "", "" }, { "Seagate Barracuda ATA V", "ST3(12002(3A|4A|9A|3AS)|800(23A|15A|23AS)|60(015A|210A)|40017A)", "", "", "" }, { "Seagate Barracuda 5400.1", "ST340015A", "", "", "" }, { "Seagate Barracuda 7200.7 and 7200.7 Plus", // tested with "ST380819AS 39M3701 39M0171 IBM"/3.03 "ST3(200021A|200822AS?|16002[13]AS?|12002[26]AS?|1[26]082[78]AS|8001[13]AS?|8081[79]AS|60014A|40111AS|40014AS?)( .* IBM)?", "", "", "" }, { "Seagate Barracuda 7200.8", "ST3(400[68]32|300[68]31|250[68]23|200826)AS?", "", "", "" }, { "Seagate Barracuda 7200.9", "ST3(402111?|80[28]110?|120[28]1[0134]|160[28]1[012]|200827|250[68]24|300[68]22|(320|400)[68]33|500[68](32|41))AS?.*", "", "", "" }, { "Seagate Barracuda 7200.10", "ST3((80|160)[28]15|200820|250[34]10|(250|300|320|400)[68]20|360320|500[68]30|750[68]40)AS?", "", "", "" }, { "Seagate Barracuda 7200.11", // unaffected firmware "ST3(160813|320[68]13|500[368]20|640[36]23|640[35]30|750[36]30|1000(333|[36]40)|1500341)AS?", "CC.?.?", // http://knowledge.seagate.com/articles/en_US/FAQ/207957en "", "" }, { "Seagate Barracuda 7200.11", // fixed firmware "ST3(500[368]20|750[36]30|1000340)AS?", "SD1A", // http://knowledge.seagate.com/articles/en_US/FAQ/207951en "", "" }, { "Seagate Barracuda 7200.11", // fixed firmware "ST3(160813|320[68]13|640[36]23|1000333|1500341)AS?", "SD[12]B", // http://knowledge.seagate.com/articles/en_US/FAQ/207957en "", "" }, { "Seagate Barracuda 7200.11", // buggy or fixed firmware "ST3(500[368]20|640[35]30|750[36]30|1000340)AS?", "(AD14|SD1[5-9]|SD81)", "There are known problems with these drives,\n" "THIS DRIVE MAY OR MAY NOT BE AFFECTED,\n" "see the following web pages for details:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207951en\n" "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=632758", "" }, { "Seagate Barracuda 7200.11", // unknown firmware "ST3(160813|320[68]13|500[368]20|640[36]23|640[35]30|750[36]30|1000(333|[36]40)|1500341)AS?", "", "There are known problems with these drives,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207951en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207957en", "" }, { "Seagate Barracuda 7200.12", // new firmware "ST3(160318|250318|320418|50041[08]|750528|1000528)AS", "CC4[9A-Z]", "", "" }, { "Seagate Barracuda 7200.12", // unknown firmware "ST3(160318|250318|320418|50041[08]|750528|1000528)AS", "", "A firmware update for this drive may be available,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/213891en", "" }, { "Seagate Barracuda 7200.12", // tested with ST3250312AS/JC45, ST31000524AS/JC45, // ST3500413AS/JC4B, ST3750525AS/JC4B "ST3(160318|25031[128]|320418|50041[038]|750(518|52[358])|100052[348])AS", "", "", "" }, { "Seagate Barracuda XT", // tested with ST32000641AS/CC13, // ST4000DX000-1C5160/CC42 "ST(3(2000641|3000651)AS|4000DX000-.*)", "", "", "" }, { "Seagate Barracuda 7200.14 (AF)", // new firmware, tested with // ST3000DM001-9YN166/CC4H, ST3000DM001-9YN166/CC9E "ST(1000|1500|2000|2500|3000)DM00[1-3]-.*", "CC(4[H-Z]|[5-9A-Z]..*)", // >= "CC4H" "", "-v 188,raw16 -v 240,msec24hour32" // tested with ST3000DM001-9YN166/CC4H }, { "Seagate Barracuda 7200.14 (AF)", // old firmware, tested with // ST1000DM003-9YN162/CC46 "ST(1000|1500|2000|2500|3000)DM00[1-3]-.*", "CC4[679CG]", "A firmware update for this drive is available,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/223651en", "-v 188,raw16 -v 240,msec24hour32" }, { "Seagate Barracuda 7200.14 (AF)", // unknown firmware "ST(1000|1500|2000|2500|3000)DM00[1-3]-.*", "", "A firmware update for this drive may be available,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/223651en", "-v 188,raw16 -v 240,msec24hour32" }, { "Seagate Barracuda 7200.14 (AF)", // < 1TB, tested with ST250DM000-1BC141 "ST(250|320|500|750)DM00[0-3]-.*", "", "", "-v 188,raw16 -v 240,msec24hour32" }, { "Seagate Desktop HDD.15", // tested with ST4000DM000-1CD168/CC43 "ST4000DM000-.*", "", "", "-v 188,raw16 -v 240,msec24hour32" }, { "Seagate Barracuda LP", // new firmware "ST3(500412|1000520|1500541|2000542)AS", "CC3[5-9A-Z]", "", "" // -F xerrorlba ? }, { "Seagate Barracuda LP", // unknown firmware "ST3(500412|1000520|1500541|2000542)AS", "", "A firmware update for this drive may be available,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/213915en", "-F xerrorlba" // tested with ST31000520AS/CC32 }, { "Seagate Barracuda Green (AF)", // new firmware "ST((10|15|20)00DL00[123])-.*", "CC3[2-9A-Z]", "", "" }, { "Seagate Barracuda Green (AF)", // unknown firmware "ST((10|15|20)00DL00[123])-.*", "", "A firmware update for this drive may be available,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/218171en", "" }, { "Seagate Barracuda ES", "ST3(250[68]2|32062|40062|50063|75064)0NS", "", "", "" }, { "Seagate Barracuda ES.2", // fixed firmware "ST3(25031|50032|75033|100034)0NS", "SN[01]6|" // http://knowledge.seagate.com/articles/en_US/FAQ/207963en "MA(0[^7]|[^0].)", // http://dellfirmware.seagate.com/dell_firmware/DellFirmwareRequest.jsp "", "-F xerrorlba" // tested with ST31000340NS/SN06 }, { "Seagate Barracuda ES.2", // buggy firmware (Dell) "ST3(25031|50032|75033|100034)0NS", "MA07", "There are known problems with these drives,\n" "AND THIS FIRMWARE VERSION IS AFFECTED,\n" "see the following Seagate web page:\n" "http://dellfirmware.seagate.com/dell_firmware/DellFirmwareRequest.jsp", "" }, { "Seagate Barracuda ES.2", // unknown firmware "ST3(25031|50032|75033|100034)0NS", "", "There are known problems with these drives,\n" "see the following Seagate web pages:\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207931en\n" "http://knowledge.seagate.com/articles/en_US/FAQ/207963en", "" }, { "Seagate Constellation (SATA)", // tested with ST9500530NS/SN03 "ST9(160511|500530)NS", "", "", "" }, { "Seagate Constellation ES (SATA)", // tested with ST31000524NS/SN11 "ST3(50051|100052|200064)4NS", "", "", "" }, { "Seagate Constellation ES (SATA 6Gb/s)", // tested with ST1000NM0011/SN02 "ST(5|10|20)00NM0011", "", "", "" }, { "Seagate Constellation ES.2 (SATA 6Gb/s)", // tested with ST32000645NS/0004, ST33000650NS "ST3(2000645|300065[012])NS", "", "", "" }, { "Seagate Constellation ES.3", // tested with ST1000NM0033-9ZM173/0001, ST4000NM0033-9ZM170/SN03 "ST[1234]000NM00[35]3-.*", "", "", "" }, { "Seagate Pipeline HD 5900.1", "ST3(160310|320[34]10|500(321|422))CS", "", "", "" }, { "Seagate Pipeline HD 5900.2", // tested with ST31000322CS/SC13 "ST3(160316|250[34]12|320(311|413)|500(312|414)|1000(322|424))CS", "", "", "" }, { "Seagate Medalist 17240, 13030, 10231, 8420, and 4310", "ST3(17240|13030|10231|8420|4310)A", "", "", "" }, { "Seagate Medalist 17242, 13032, 10232, 8422, and 4312", "ST3(1724|1303|1023|842|431)2A", "", "", "" }, { "Seagate NL35", "ST3(250623|250823|400632|400832|250824|250624|400633|400833|500641|500841)NS", "", "", "" }, { "Seagate SV35.2", "ST3(160815|250820|320620|500630|750640)[AS]V", "", "", "" }, { "Seagate SV35.5", // tested with ST31000525SV/CV12 "ST3(250311|500410|1000525)SV", "", "", "" }, { "Seagate SV35", // tested with ST2000VX000-9YW164/CV12 "ST([123]000VX00[20]|31000526SV|3500411SV)(-.*)?", "", "", "" }, { "Seagate DB35", // tested with ST3250823ACE/3.03 "ST3(200826|250823|300831|400832)ACE", "", "", "" }, { "Seagate DB35.2", // tested with ST3160212SCE/3.ACB "ST3(802110|120213|160212|200827|250824|300822|400833|500841)[AS]CE", "", "", "" }, { "Seagate DB35.3", "ST3(750640SCE|((80|160)215|(250|320|400)820|500830|750840)[AS]CE)", "", "", "" }, { "Seagate LD25.2", // tested with ST940210AS/3.ALC "ST9(40|80)210AS?", "", "", "" }, { "Seagate ST1.2 CompactFlash", // tested with ST68022CF/3.01 "ST6[468]022CF", "", "", "" }, { "Western Digital Protege", /* Western Digital drives with this comment all appear to use Attribute 9 in * a non-standard manner. These entries may need to be updated when it * is understood exactly how Attribute 9 should be interpreted. * UPDATE: this is probably explained by the WD firmware bug described in the * smartmontools FAQ */ "WDC WD([2468]00E|1[26]00A)B-.*", "", "", "" }, { "Western Digital Caviar", /* Western Digital drives with this comment all appear to use Attribute 9 in * a non-standard manner. These entries may need to be updated when it * is understood exactly how Attribute 9 should be interpreted. * UPDATE: this is probably explained by the WD firmware bug described in the * smartmontools FAQ */ "WDC WD(2|3|4|6|8|10|12|16|18|20|25)00BB-.*", "", "", "" }, { "Western Digital Caviar WDxxxAB", /* Western Digital drives with this comment all appear to use Attribute 9 in * a non-standard manner. These entries may need to be updated when it * is understood exactly how Attribute 9 should be interpreted. * UPDATE: this is probably explained by the WD firmware bug described in the * smartmontools FAQ */ "WDC WD(3|4|6|8|25)00AB-.*", "", "", "" }, { "Western Digital Caviar WDxxxAA", /* Western Digital drives with this comment all appear to use Attribute 9 in * a non-standard manner. These entries may need to be updated when it * is understood exactly how Attribute 9 should be interpreted. * UPDATE: this is probably explained by the WD firmware bug described in the * smartmontools FAQ */ "WDC WD...?AA(-.*)?", "", "", "" }, { "Western Digital Caviar WDxxxBA", /* Western Digital drives with this comment all appear to use Attribute 9 in * a non-standard manner. These entries may need to be updated when it * is understood exactly how Attribute 9 should be interpreted. * UPDATE: this is probably explained by the WD firmware bug described in the * smartmontools FAQ */ "WDC WD...BA", "", "", "" }, { "Western Digital Caviar AC", // add only 5400rpm/7200rpm (ata33 and faster) "WDC AC((116|121|125|225|132|232)|([1-4][4-9][0-9])|([1-4][0-9][0-9][0-9]))00[A-Z]?.*", "", "", "" }, { "Western Digital Caviar SE", /* Western Digital drives with this comment all appear to use Attribute 9 in * a non-standard manner. These entries may need to be updated when it * is understood exactly how Attribute 9 should be interpreted. * UPDATE: this is probably explained by the WD firmware bug described in the * smartmontools FAQ * UPDATE 2: this does not apply to more recent models, at least WD3200AAJB */ "WDC WD(4|6|8|10|12|16|18|20|25|30|32|40|50)00(JB|PB)-.*", "", "", "" }, { "Western Digital Caviar Blue EIDE", // WD Caviar SE EIDE /* not completely accurate: at least also WD800JB, WD(4|8|20|25)00BB sold as Caviar Blue */ "WDC WD(16|25|32|40|50)00AAJB-.*", "", "", "" }, { "Western Digital Caviar Blue EIDE", // WD Caviar SE16 EIDE "WDC WD(25|32|40|50)00AAKB-.*", "", "", "" }, { "Western Digital RE EIDE", "WDC WD(12|16|25|32)00SB-.*", "", "", "" }, { "Western Digital Caviar Serial ATA", "WDC WD(4|8|20|32)00BD-.*", "", "", "" }, { "Western Digital Caviar SE Serial ATA", // tested with WDC WD3000JD-98KLB0/08.05J08 "WDC WD(4|8|12|16|20|25|30|32|40)00(JD|KD|PD)-.*", "", "", "" }, { "Western Digital Caviar SE Serial ATA", "WDC WD(8|12|16|20|25|30|32|40|50)00JS-.*", "", "", "" }, { "Western Digital Caviar SE16 Serial ATA", "WDC WD(16|20|25|32|40|50|75)00KS-.*", "", "", "" }, { "Western Digital Caviar Blue Serial ATA", // WD Caviar SE Serial ATA /* not completely accurate: at least also WD800BD, (4|8)00JD sold as Caviar Blue */ "WDC WD((8|12|16|25|32)00AABS|(8|12|16|25|32|40|50)00AAJS)-.*", "", "", "" }, { "Western Digital Caviar Blue (SATA)", // WD Caviar SE16 Serial ATA // tested with WD1602ABKS-18N8A0/DELL/02.03B04 "WDC WD((16|20|25|32|40|50|64|75)00AAKS|1602ABKS|10EALS)-.*", "", "", "" }, { "Western Digital Caviar Blue (SATA 6Gb/s)", // tested with WDC WD10EZEX-00RKKA0/80.00A80 "WDC WD((25|32|50)00AAKX|7500AALX|10EALX|10EZEX)-.*", "", "", "" }, { "Western Digital RE Serial ATA", "WDC WD(12|16|25|32)00(SD|YD|YS)-.*", "", "", "" }, { "Western Digital RE2 Serial ATA", "WDC WD((40|50|75)00(YR|YS|AYYS)|(16|32|40|50)0[01]ABYS)-.*", "", "", "" }, { "Western Digital RE2-GP", "WDC WD(5000AB|7500AY|1000FY)PS-.*", "", "", "" }, { "Western Digital RE3 Serial ATA", // tested with WDC WD7502ABYS-02A6B0/03.00C06 "WDC WD((25|32|50|75)02A|(75|10)02F)BYS-.*", "", "", "" }, { "Western Digital RE4", // tested with WDC WD2003FYYS-18W0B0/01.01D02 "WDC WD((((25|50)03A|1003F)BYX)|((15|20)03FYYS))-.*", "", "", "" }, { "Western Digital RE4-GP", // tested with WDC WD2002FYPS-02W3B0/04.01G01 "WDC WD2002FYPS-.*", "", "", "" }, { "Western Digital RE4 (SATA 6Gb/s)", // tested with WDC WD2000FYYZ-01UL1B0/01.01K01 "WDC WD(20|30|40)00FYYZ-.*", "", "", "" }, { "Western Digital Caviar Green", "WDC WD((50|64|75)00AA(C|V)S|(50|64|75)00AADS|10EA(C|V)S|(10|15|20)EADS)-.*", "", "", "-F xerrorlba" // tested with WDC WD7500AADS-00M2B0/01.00A01 }, { "Western Digital Caviar Green (AF)", "WDC WD(((64|75|80)00AA|(10|15|20)EA|(25|30)EZ)R|20EAC)S-.*", "", "", "" }, { "Western Digital Caviar Green (AF, SATA 6Gb/s)", // tested with // WDC WD10EZRX-00A8LB0/01.01A01, WDC WD20EZRX-00DC0B0/80.00A80, // WDC WD30EZRX-00MMMB0/80.00A80 "WDC WD(7500AA|(10|15|20)EA|(10|20|25|30)EZ)RX-.*", "", "", "" }, { "Western Digital Caviar Black", "WDC WD((500|640|750)1AAL|1001FA[EL]|2001FAS)S-.*", "", "", "" }, { "Western Digital Caviar Black", // SATA 6 Gb/s variants, tested with // WDC WD4001FAEX-00MJRA0/01.01L01 "WDC WD(5002AAL|(64|75)02AAE|((10|15|20)02|4001)FAE)X-.*", "", "", "" }, { "Western Digital Caviar Black (AF)", // tested with WDC WD5003AZEX-00RKKA0/80.00A80 "WDC WD(5003AZE)X-.*", "", "", "" }, { "Western Digital AV ATA", // tested with WDC WD3200AVJB-63J5A0/01.03E01 "WDC WD(8|16|25|32|50)00AV[BJ]B-.*", "", "", "" }, { "Western Digital AV SATA", "WDC WD(16|25|32)00AVJS-.*", "", "", "" }, { "Western Digital AV-GP", "WDC WD((16|25|32|50|64|75)00AV[CDV]S|(10|15|20)EV[CDV]S)-.*", "", "", "" }, { "Western Digital AV-GP (AF)", // tested with WDC WD10EURS-630AB1/80.00A80, WDC WD10EUCX-63YZ1Y0/51.0AB52 "WDC WD(7500AURS|10EU[CR]X|(10|15|20|25|30)EURS)-.*", "", "", "" }, { "Western Digital AV-25", "WDC WD((16|25|32|50)00BUD|5000BUC)T-.*", "", "", "" }, { "Western Digital Raptor", "WDC WD((360|740|800)GD|(360|740|800|1500)ADF[DS])-.*", "", "", "" }, { "Western Digital Raptor X", "WDC WD1500AHFD-.*", "", "", "" }, { "Western Digital VelociRaptor", // tested with WDC WD1500HLHX-01JJPV0/04.05G04 "WDC WD(((800H|(1500|3000)[BH]|1600H|3000G)LFS)|((1500|3000|4500|6000)[BH]LHX))-.*", "", "", "" }, { "Western Digital VelociRaptor (AF)", // tested with WDC WD1000DHTZ-04N21V0/04.06A00 "WDC WD(2500H|5000H|1000D)HTZ-.*", "", "", "" }, { "Western Digital Scorpio EIDE", "WDC WD(4|6|8|10|12|16)00(UE|VE)-.*", "", "", "" }, { "Western Digital Scorpio Blue EIDE", // tested with WDC WD3200BEVE-00A0HT0/11.01A11 "WDC WD(4|6|8|10|12|16|25|32)00BEVE-.*", "", "", "" }, { "Western Digital Scorpio Serial ATA", "WDC WD(4|6|8|10|12|16|25)00BEAS-.*", "", "", "" }, { "Western Digital Scorpio Blue Serial ATA", "WDC WD((4|6|8|10|12|16|25)00BEVS|(8|12|16|25|32|40|50|64)00BEVT|7500KEVT|10TEVT)-.*", "", "", "" }, { "Western Digital Scorpio Blue Serial ATA (AF)", // tested with // WDC WD10JPVT-00A1YT0/01.01A01 "WDC WD((16|25|32|50|64|75)00BPVT|10[JT]PVT)-.*", "", "", "" }, { "Western Digital Scorpio Black", // tested with WDC WD5000BEKT-00KA9T0/01.01A01 "WDC WD(8|12|16|25|32|50)00B[EJ]KT-.*", "", "", "" }, { "Western Digital Scorpio Black (AF)", "WDC WD(50|75)00BPKT-.*", "", "", "" }, { "Western Digital Red (AF)", // tested with WDC WD10EFRX-68JCSN0/01.01A01 "WDC WD(10|20|30)EFRX-.*", "", "", "" }, { "Western Digital My Passport (USB)", // tested with WDC WD5000BMVW-11AMCS0/01.01A01 "WDC WD(25|32|40|50)00BMV[UVW]-.*", // *W-* = USB 3.0 "", "", "" }, { "Western Digital My Passport (USB, AF)", // tested with // WDC WD5000KMVV-11TK7S1/01.01A01, WDC WD10TMVW-11ZSMS5/01.01A01, // WDC WD10JMVW-11S5XS1/01.01A01, WDC WD20NMVW-11W68S0/01.01A01 "WDC WD(5000[LK]|7500K|10[JT]|20N)MV[VW]-.*", // *W-* = USB 3.0 "", "", "" }, { "Quantum Bigfoot", // tested with TS10.0A/A21.0G00, TS12.7A/A21.0F00 "QUANTUM BIGFOOT TS(10\\.0|12\\.7)A", "", "", "" }, { "Quantum Fireball lct15", "QUANTUM FIREBALLlct15 ([123]0|22)", "", "", "" }, { "Quantum Fireball lct20", "QUANTUM FIREBALLlct20 [1234]0", "", "", "" }, { "Quantum Fireball CX", "QUANTUM FIREBALL CX10.2A", "", "", "" }, { "Quantum Fireball CR", "QUANTUM FIREBALL CR(4.3|6.4|8.4|13.0)A", "", "", "" }, { "Quantum Fireball EX", // tested with QUANTUM FIREBALL EX10.2A/A0A.0D00 "QUANTUM FIREBALL EX(3\\.2|6\\.4|10\\.2)A", "", "", "" }, { "Quantum Fireball ST", "QUANTUM FIREBALL ST(3.2|4.3|4300)A", "", "", "" }, { "Quantum Fireball SE", "QUANTUM FIREBALL SE4.3A", "", "", "" }, { "Quantum Fireball Plus LM", "QUANTUM FIREBALLP LM(10.2|15|20.[45]|30)", "", "", "" }, { "Quantum Fireball Plus AS", "QUANTUM FIREBALLP AS(10.2|20.5|30.0|40.0|60.0)", "", "", "" }, { "Quantum Fireball Plus KX", "QUANTUM FIREBALLP KX27.3", "", "", "" }, { "Quantum Fireball Plus KA", "QUANTUM FIREBALLP KA(9|10).1", "", "", "" }, //////////////////////////////////////////////////// // USB ID entries //////////////////////////////////////////////////// // Hewlett-Packard { "USB: HP Desktop HD BD07; ", // 2TB "0x03f0:0xbd07", "", "", "-d sat" }, // ALi { "USB: ; ALi M5621", // USB->PATA "0x0402:0x5621", "", "", "" // unsupported }, // VIA { "USB: Connectland BE-USB2-35BP-LCM; VIA VT6204", "0x040d:0x6204", "", "", "" // unsupported }, // Buffalo / Melco { "USB: Buffalo JustStore Portable HD-PVU2; ", "0x0411:0x0181", "", "", "-d sat" }, { "USB: Buffalo MiniStation Stealth HD-PCTU2; ", "0x0411:0x01d9", "", // 0x0108 "", "-d sat" }, // LG Electronics { "USB: LG Mini HXD5; JMicron", "0x043e:0x70f1", "", // 0x0100 "", "-d usbjmicron" }, // Philips { "USB: Philips; ", // SDE3273FC/97 2.5" SATA HDD enclosure "0x0471:0x2021", "", // 0x0103 "", "-d sat" }, // Toshiba { "USB: Toshiba Canvio 500GB; SunPlus", "0x0480:0xa004", "", "", "-d usbsunplus" }, { "USB: Toshiba Canvio Basics; ", "0x0480:0xa006", "", // 0x0001 "", "-d sat" }, { "USB: Toshiba Canvio 3.0 Portable Hard Drive; ", // 1TB "0x0480:0xa007", "", // 0x0001 "", "-d sat" }, { "USB: Toshiba Canvio Desktop; ", // 2TB "0x0480:0xd010", "", "", "-d sat" }, // Cypress { "USB: ; Cypress CY7C68300A (AT2)", "0x04b4:0x6830", "0x0001", "", "" // unsupported }, { "USB: ; Cypress CY7C68300B/C (AT2LP)", "0x04b4:0x6830", "0x0240", "", "-d usbcypress" }, // Fujitsu { "USB: Fujitsu/Zalman ZM-VE300; ", // USB 3.0 "0x04c5:0x2028", "", // 0x0001 "", "-d sat" }, // Fujitsu chip on DeLock 42475 { "USB: Fujitsu SATA-to-USB3.0 bridge chip", // USB 3.0 "0x04c5:0x201d", "", // 0x0001 "", "-d sat" }, // Myson Century { "USB: ; Myson Century CS8818", "0x04cf:0x8818", "", // 0xb007 "", "" // unsupported }, // Samsung { "USB: Samsung S2 Portable; JMicron", "0x04e8:0x1f0[568]", "", "", "-d usbjmicron" }, { "USB: Samsung S1 Portable; JMicron", "0x04e8:0x2f03", "", "", "-d usbjmicron" }, { "USB: Samsung Story Station; ", "0x04e8:0x5f0[56]", "", "", "-d sat" }, { "USB: Samsung G2 Portable; JMicron", "0x04e8:0x6032", "", "", "-d usbjmicron" }, { "USB: Samsung Story Station 3.0; ", "0x04e8:0x6052", "", "", "-d sat" }, { "USB: Samsung Story Station 3.0; ", "0x04e8:0x6054", "", "", "-d sat" }, { "USB: Samsung M2 Portable 3.0; ", "0x04e8:0x60c5", "", "", "-d sat" }, { "USB: Samsung M3 Portable USB 3.0; ", // 1TB "0x04e8:0x61b6", "", // 0x0e00 "", "-d sat" }, // Sunplus { "USB: ; SunPlus", "0x04fc:0x0c05", "", "", "-d usbsunplus" }, { "USB: ; SunPlus SPDIF215", "0x04fc:0x0c15", "", // 0xf615 "", "-d usbsunplus" }, { "USB: ; SunPlus SPDIF225", // USB+SATA->SATA "0x04fc:0x0c25", "", // 0x0103 "", "-d usbsunplus" }, // Iomega { "USB: Iomega Prestige Desktop USB 3.0; ", "0x059b:0x0070", "", // 0x0004 "", "-d sat" // ATA output registers missing }, { "USB: Iomega LPHD080-0; ", "0x059b:0x0272", "", "", "-d usbcypress" }, { "USB: Iomega MDHD500-U; ", "0x059b:0x0275", "", // 0x0001 "", "" // unsupported }, { "USB: Iomega MDHD-UE; ", "0x059b:0x0277", "", "", "-d usbjmicron" }, { "USB: Iomega LDHD-UP; Sunplus", "0x059b:0x0370", "", "", "-d usbsunplus" }, { "USB: Iomega GDHDU2; JMicron", "0x059b:0x0475", "", // 0x0100 "", "-d usbjmicron" }, // LaCie { "USB: LaCie hard disk (FA Porsche design);", "0x059f:0x0651", "", "", "" // unsupported }, { "USB: LaCie hard disk; JMicron", "0x059f:0x0951", "", "", "-d usbjmicron" }, { "USB: LaCie hard disk (Neil Poulton design);", "0x059f:0x1018", "", "", "-d sat" }, { "USB: LaCie Desktop Hard Drive; JMicron", "0x059f:0x1019", "", "", "-d usbjmicron" }, { "USB: LaCie Rugged Hard Drive; JMicron", "0x059f:0x101d", "", // 0x0001 "", "-d usbjmicron,x" }, { "USB: LaCie Little Disk USB2; JMicron", "0x059f:0x1021", "", "", "-d usbjmicron" }, { "USB: LaCie hard disk; ", "0x059f:0x1029", "", // 0x0100 "", "-d sat" }, { "USB: Lacie rikiki; JMicron", "0x059f:0x102a", "", "", "-d usbjmicron,x" }, { "USB: LaCie rikiki USB 3.0; ", "0x059f:0x10(49|57)", "", "", "-d sat" }, { "USB: LaCie minimus USB 3.0; ", "0x059f:0x104a", "", "", "-d sat" }, { "USB: LaCie Rugged Mini USB 3.0; ", "0x059f:0x1051", "", // 0x0000 "", "-d sat" }, // In-System Design { "USB: ; In-System/Cypress ISD-300A1", "0x05ab:0x0060", "", // 0x1101 "", "-d usbcypress" }, // Genesys Logic { "USB: ; Genesys Logic GL881E", "0x05e3:0x0702", "", "", "" // unsupported }, { "USB: ; Genesys Logic", // TODO: requires '-T permissive' "0x05e3:0x0718", "", // 0x0041 "", "-d sat" }, // Micron { "USB: Micron USB SSD; ", "0x0634:0x0655", "", "", "" // unsupported }, // Prolific { "USB: ; Prolific PL2507", // USB->PATA "0x067b:0x2507", "", "", "-d usbjmicron,0" // Port number is required }, { "USB: ; Prolific PL3507", // USB+IEE1394->PATA "0x067b:0x3507", "", // 0x0001 "", "-d usbjmicron,p" }, // Imation { "USB: Imation ; ", // Imation Odyssey external USB dock "0x0718:0x1000", "", // 0x5104 "", "-d sat" }, // Freecom { "USB: Freecom Mobile Drive XXS; JMicron", "0x07ab:0xfc88", "", // 0x0101 "", "-d usbjmicron,x" }, { "USB: Freecom Hard Drive XS; Sunplus", "0x07ab:0xfc8e", "", // 0x010f "", "-d usbsunplus" }, { "USB: Freecom; ", // Intel labeled "0x07ab:0xfc8f", "", // 0x0000 "", "-d sat" }, { "USB: Freecom Classic HD 120GB; ", "0x07ab:0xfccd", "", "", "" // unsupported }, { "USB: Freecom HD 500GB; JMicron", "0x07ab:0xfcda", "", "", "-d usbjmicron" }, // Oxford Semiconductor, Ltd { "USB: ; Oxford", "0x0928:0x0000", "", "", "" // unsupported }, { "USB: ; Oxford OXU921DS", "0x0928:0x0002", "", "", "" // unsupported }, { "USB: ; Oxford", // Zalman ZM-VE200 "0x0928:0x0010", "", // 0x0304 "", "-d sat" }, // Toshiba { "USB: Toshiba PX1270E-1G16; Sunplus", "0x0930:0x0b03", "", "", "-d usbsunplus" }, { "USB: Toshiba PX1396E-3T01; Sunplus", // similar to Dura Micro 501 "0x0930:0x0b09", "", "", "-d usbsunplus" }, { "USB: Toshiba Stor.E Steel; Sunplus", "0x0930:0x0b11", "", "", "-d usbsunplus" }, { "USB: Toshiba Stor.E; ", "0x0930:0x0b1[9ab]", "", // 0x0001 "", "-d sat" }, // Lumberg, Inc. { "USB: Toshiba Stor.E; Sunplus", "0x0939:0x0b16", "", "", "-d usbsunplus" }, // Seagate { "USB: Seagate External Drive; Cypress", "0x0bc2:0x0503", "", // 0x0240 "", "-d usbcypress" }, { "USB: Seagate FreeAgent Go; ", "0x0bc2:0x2(000|100|101)", "", "", "-d sat" }, { "USB: Seagate FreeAgent Go FW; ", "0x0bc2:0x2200", "", "", "-d sat" }, { "USB: Seagate Expansion Portable; ", "0x0bc2:0x2300", "", "", "-d sat" }, { "USB: Seagate FreeAgent Desktop; ", "0x0bc2:0x3000", "", "", "-d sat" }, { "USB: Seagate FreeAgent Desk; ", "0x0bc2:0x3001", "", "", "-d sat" }, { "USB: Seagate FreeAgent Desk; ", // 1TB "0x0bc2:0x3008", "", "", "-d sat,12" }, { "USB: Seagate Expansion External; ", // 2TB, 3TB "0x0bc2:0x33(00|20|32)", "", "", "-d sat" }, { "USB: Seagate FreeAgent GoFlex USB 2.0; ", "0x0bc2:0x5021", "", "", "-d sat" }, { "USB: Seagate FreeAgent GoFlex USB 3.0; ", "0x0bc2:0x5031", "", "", "-d sat,12" }, { "USB: Seagate FreeAgent; ", "0x0bc2:0x5040", "", "", "-d sat" }, { "USB: Seagate FreeAgent GoFlex USB 3.0; ", // 2TB "0x0bc2:0x5071", "", "", "-d sat" }, { "USB: Seagate FreeAgent GoFlex Desk USB 3.0; ", // 3TB "0x0bc2:0x50a1", "", "", "-d sat,12" // "-d sat" does not work (ticket #151) }, { "USB: Seagate FreeAgent GoFlex Desk USB 3.0; ", // 4TB "0x0bc2:0x50a5", "", // 0x0100 "", "-d sat" }, { "USB: Seagate Backup Plus USB 3.0; ", // 1TB "0x0bc2:0xa013", "", // 0x0100 "", "-d sat" }, { "USB: Seagate Backup Plus Desktop USB 3.0; ", // 4TB, 3TB (8 LBA/1 PBA offset) "0x0bc2:0xa0a[14]", "", "", "-d sat" }, // Dura Micro { "USB: Dura Micro; Cypress", "0x0c0b:0xb001", "", // 0x1110 "", "-d usbcypress" }, { "USB: Dura Micro 509; Sunplus", "0x0c0b:0xb159", "", // 0x0103 "", "-d usbsunplus" }, // Maxtor { "USB: Maxtor OneTouch 200GB; ", "0x0d49:0x7010", "", "", "" // unsupported }, { "USB: Maxtor OneTouch; ", "0x0d49:0x7300", "", // 0x0121 "", "-d sat" }, { "USB: Maxtor OneTouch 4; ", "0x0d49:0x7310", "", // 0x0125 "", "-d sat" }, { "USB: Maxtor OneTouch 4 Mini; ", "0x0d49:0x7350", "", // 0x0125 "", "-d sat" }, { "USB: Maxtor BlackArmor Portable; ", "0x0d49:0x7550", "", "", "-d sat" }, { "USB: Maxtor Basics Desktop; ", "0x0d49:0x7410", "", // 0x0122 "", "-d sat" }, { "USB: Maxtor Basics Portable; ", "0x0d49:0x7450", "", // 0x0122 "", "-d sat" }, // Oyen Digital { "USB: Oyen Digital MiniPro USB 3.0; ", "0x0dc4:0x020a", "", "", "-d sat" }, // Cowon Systems, Inc. { "USB: Cowon iAudio X5; ", "0x0e21:0x0510", "", "", "-d usbcypress" }, // iRiver { "USB: iRiver iHP-120/140 MP3 Player; Cypress", "0x1006:0x3002", "", // 0x0100 "", "-d usbcypress" }, // Western Digital { "USB: WD My Passport (IDE); Cypress", "0x1058:0x0701", "", // 0x0240 "", "-d usbcypress" }, { "USB: WD My Passport Portable; ", "0x1058:0x0702", "", // 0x0102 "", "-d sat" }, { "USB: WD My Passport Essential; ", "0x1058:0x0704", "", // 0x0175 "", "-d sat" }, { "USB: WD My Passport Elite; ", "0x1058:0x0705", "", // 0x0175 "", "-d sat" }, { "USB: WD My Passport 070A; ", "0x1058:0x070a", "", // 0x1028 "", "-d sat" }, { "USB: WD My Passport 0730; ", "0x1058:0x0730", "", // 0x1008 "", "-d sat" }, { "USB: WD My Passport Essential SE USB 3.0; ", "0x1058:0x074[02]", "", "", "-d sat" }, { "USB: WD My Passport USB 3.0; ", "0x1058:0x07[4a]8", "", "", "-d sat" }, { "USB: WD My Book ES; ", "0x1058:0x0906", "", // 0x0012 "", "-d sat" }, { "USB: WD My Book Essential; ", "0x1058:0x0910", "", // 0x0106 "", "-d sat" }, { "USB: WD Elements Desktop; ", "0x1058:0x1001", "", // 0x0104 "", "-d sat" }, { "USB: WD Elements Desktop WDE1UBK...; ", "0x1058:0x1003", "", // 0x0175 "", "-d sat" }, { "USB: WD Elements; ", "0x1058:0x10(10|a2)", "", // 0x0105 "", "-d sat" }, { "USB: WD Elements Desktop; ", // 2TB "0x1058:0x1021", "", // 0x2002 "", "-d sat" }, { "USB: WD Elements SE; ", // 1TB "0x1058:0x1023", "", "", "-d sat" }, { "USB: WD Elements SE USB 3.0; ", "0x1058:0x1042", "", "", "-d sat" }, { "USB: WD My Book Essential; ", "0x1058:0x1100", "", // 0x0165 "", "-d sat" }, { "USB: WD My Book Office Edition; ", // 1TB "0x1058:0x1101", "", // 0x0165 "", "-d sat" }, { "USB: WD My Book; ", "0x1058:0x1102", "", // 0x1028 "", "-d sat" }, { "USB: WD My Book Studio II; ", // 2x1TB "0x1058:0x1105", "", "", "-d sat" }, { "USB: WD My Book Essential; ", "0x1058:0x1110", "", // 0x1030 "", "-d sat" }, { "USB: WD My Book Essential USB 3.0; ", // 3TB "0x1058:0x11[34]0", "", // 0x1012/0x1003 "", "-d sat" }, // Atech Flash Technology { "USB: ; Atech", // Enclosure from Kingston SSDNow notebook upgrade kit "0x11b0:0x6298", "", // 0x0108 "", "-d sat" }, // A-DATA { "USB: A-DATA SH93; Cypress", "0x125f:0xa93a", "", // 0x0150 "", "-d usbcypress" }, { "USB: A-DATA DashDrive; Cypress", "0x125f:0xa94a", "", "", "-d usbcypress" }, // Initio { "USB: ; Initio 316000", "0x13fd:0x0540", "", "", "" // unsupported }, { "USB: ; Initio", // Thermaltake BlacX "0x13fd:0x0840", "", "", "-d sat" }, { "USB: ; Initio", // USB->SATA+PATA, Chieftec CEB-25I "0x13fd:0x1040", "", // 0x0106 "", "" // unsupported }, { "USB: ; Initio 6Y120L0", // CoolerMaster XCraft RX-3HU "0x13fd:0x1150", "", "", "" // unsupported }, { "USB: ; Initio", // USB->SATA "0x13fd:0x1240", "", // 0x0104 "", "-d sat" }, { "USB: ; Initio", // USB+SATA->SATA "0x13fd:0x1340", "", // 0x0208 "", "-d sat" }, { "USB: Intenso Memory Station 2,5\"; Initio", "0x13fd:0x1840", "", "", "-d sat" }, { "USB: ; Initio", // NexStar CX USB enclosure "0x13fd:0x1e40", "", "", "-d sat" }, // Super Top { "USB: Super Top generic enclosure; Cypress", "0x14cd:0x6116", "", // 0x0160 also reported as unsupported "", "-d usbcypress" }, // JMicron { "USB: ; JMicron USB 3.0", "0x152d:0x0539", "", // 0x0100 "", "-d usbjmicron" }, { "USB: ; JMicron ", // USB->SATA->4xSATA (port multiplier) "0x152d:0x0551", "", // 0x0100 "", "-d usbjmicron,x" }, { "USB: OCZ THROTTLE OCZESATATHR8G; JMicron JMF601", "0x152d:0x0602", "", "", "" // unsupported }, { "USB: ; JMicron JM20329", // USB->SATA "0x152d:0x2329", "", // 0x0100 "", "-d usbjmicron" }, { "USB: ; JMicron JM20336", // USB+SATA->SATA, USB->2xSATA "0x152d:0x2336", "", // 0x0100 "", "-d usbjmicron,x" }, { "USB: Generic JMicron adapter; JMicron", "0x152d:0x2337", "", "", "-d usbjmicron" }, { "USB: ; JMicron JM20337/8", // USB->SATA+PATA, USB+SATA->PATA "0x152d:0x2338", "", // 0x0100 "", "-d usbjmicron" }, { "USB: ; JMicron JM20339", // USB->SATA "0x152d:0x2339", "", // 0x0100 "", "-d usbjmicron,x" }, { "USB: ; JMicron", // USB+SATA->SATA "0x152d:0x2351", // e.g. Verbatim Portable Hard Drive 500Gb "", // 0x0100 "", "-d sat" }, { "USB: ; JMicron", // USB->SATA "0x152d:0x2352", "", // 0x0100 "", "-d usbjmicron,x" }, { "USB: ; JMicron", // USB->SATA "0x152d:0x2509", "", // 0x0100 "", "-d usbjmicron,x" }, // ASMedia { "USB: ; ASMedia ASM1051", "0x174c:0x5106", // 0x174c:0x55aa after firmware update "", "", "-d sat" }, { "USB: ; ASMedia USB 3.0", // MEDION HDDrive-n-GO, LaCie Rikiki USB 3.0, // Silicon Power Armor A80 (ticket #237) // reported as unsupported: BYTECC T-200U3, Kingwin USB 3.0 docking station "0x174c:0x55aa", "", // 0x0100 "", "-d sat" }, // LucidPort { "USB: ; LucidPORT USB300", // RaidSonic ICY BOX IB-110StU3-B, Sharkoon SATA QuickPort H3 "0x1759:0x500[02]", // 0x5000: USB 2.0, 0x5002: USB 3.0 "", "", "-d sat" }, // Verbatim { "USB: Verbatim Portable Hard Drive; Sunplus", "0x18a5:0x0214", "", // 0x0112 "", "-d usbsunplus" }, { "USB: Verbatim FW/USB160; Oxford OXUF934SSA-LQAG", // USB+IEE1394->SATA "0x18a5:0x0215", "", // 0x0001 "", "-d sat" }, { "USB: Verbatim External Hard Drive 47519; Sunplus", // USB->SATA "0x18a5:0x0216", "", "", "-d usbsunplus" }, { "USB: Verbatim Pocket Hard Drive; JMicron", // SAMSUNG SpinPoint N3U-3 (USB, 4KiB LLS) "0x18a5:0x0227", "", "", "-d usbjmicron" // "-d usbjmicron,x" does not work }, { "USB: Verbatim External Hard Drive; JMicron", // 2TB "0x18a5:0x022a", "", "", "-d usbjmicron" }, { "USB: Verbatim Store'n'Go; JMicron", // USB->SATA "0x18a5:0x022b", "", // 0x0100 "", "-d usbjmicron" }, // Silicon Image { "USB: Vantec NST-400MX-SR; Silicon Image 5744", "0x1a4a:0x1670", "", "", "" // unsupported }, // SunplusIT { "USB: ; SunplusIT", "0x1bcf:0x0c31", "", "", "-d usbsunplus" }, // Innostor { "USB: ; Innostor IS888", // Sharkoon SATA QuickDeck Pro USB 3.0 "0x1f75:0x0888", "", // 0x0034 "", "" // unsupported }, // Power Quotient International { "USB: PQI H560; ", "0x3538:0x0902", "", // 0x0000 "", "-d sat" }, // Hitachi/SimpleTech { "USB: Hitachi Touro Desk; JMicron", // 3TB "0x4971:0x1011", "", "", "-d usbjmicron" }, { "USB: Hitachi Touro Desk 3.0; ", // 2TB "0x4971:0x1015", "", // 0x0000 "", "-d sat" // ATA output registers missing }, { "USB: Hitachi/SimpleTech; JMicron", // 1TB "0x4971:0xce17", "", "", "-d usbjmicron,x" }, // OnSpec { "USB: ; OnSpec", // USB->PATA "0x55aa:0x2b00", "", // 0x0100 "", "" // unsupported }, // 0x6795 (?) { "USB: Sharkoon 2-Bay RAID Box; ", // USB 3.0 "0x6795:0x2756", "", // 0x0100 "", "-d sat" }, /* }; // builtin_knowndrives[] */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/getopt/��������������������������������������������������������������0000755�0000000�0000000�00000000000�12212065523�016361� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/getopt/getopt1.c�����������������������������������������������������0000644�0000000�0000000�00000011057�11523017026�020113� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef _LIBC # include <getopt.h> #else # include "getopt.h" #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include <stdio.h> /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 #include <gnu-versions.h> #if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION #define ELIDE_CODE #endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include <stdlib.h> #endif #ifndef NULL #define NULL 0 #endif int getopt_long (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (argc, argv, options, long_options, opt_index) int argc; char *const *argv; const char *options; const struct option *long_options; int *opt_index; { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } # ifdef _LIBC libc_hidden_def (getopt_long) libc_hidden_def (getopt_long_only) # endif #endif /* Not ELIDE_CODE. */ #ifdef TEST #include <stdio.h> int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == -1) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/getopt/getopt.c������������������������������������������������������0000644�0000000�0000000�00000103310�12062407372�020032� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to drepper@gnu.org before changing it! Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001,2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. Ditto for AIX 3.2 and <stdlib.h>. */ #ifndef _NO_PROTO # define _NO_PROTO #endif #ifdef HAVE_CONFIG_H # include "config.h" #endif #if !defined __STDC__ || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ # ifndef const # define const # endif #endif #include <stdio.h> /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #define GETOPT_INTERFACE_VERSION 2 #if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 # include <gnu-versions.h> # if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION # define ELIDE_CODE # endif #endif #ifndef ELIDE_CODE /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ # include <stdlib.h> # include <unistd.h> #endif /* GNU C library. */ #ifdef VMS # include <unixlib.h> # if HAVE_STRING_H - 0 # include <string.h> # endif #endif #ifndef _ /* This is for other GNU distributions with internationalized messages. */ # if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC # include <libintl.h> # ifndef _ # define _(msgid) gettext (msgid) # endif # else # define _(msgid) (msgid) # endif # if defined _LIBC && defined USE_IN_LIBIO # include <wchar.h> # endif #endif #ifndef attribute_hidden # define attribute_hidden #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* 1003.2 says this must be 1 before any call. */ int optind = 1; /* Formerly, initialization of getopt depended on optind==0, which causes problems with re-calling getopt as programs generally don't know that. */ int __getopt_initialized attribute_hidden; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return -1 with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ # include <string.h> # define my_index strchr #else # if HAVE_STRING_H # include <string.h> # else # include <strings.h> # endif /* Avoid depending on library functions or files whose names are inconsistent. */ #ifndef getenv extern char *getenv (); #endif static char * my_index (str, chr) const char *str; int chr; { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ # if (!defined __STDC__ || !__STDC__) && !defined strlen /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); # endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; #ifdef _LIBC /* Stored original parameters. XXX This is no good solution. We should rather copy the args so that we can compare them later. But we must not use malloc(3). */ extern int __libc_argc; extern char **__libc_argv; /* Bash 2.0 gives us an environment variable containing flags indicating ARGV elements that should not be considered arguments. */ # ifdef USE_NONOPTION_FLAGS /* Defined in getopt_init.c */ extern char *__getopt_nonoption_flags; static int nonoption_flags_max_len; static int nonoption_flags_len; # endif # ifdef USE_NONOPTION_FLAGS # define SWAP_FLAGS(ch1, ch2) \ if (nonoption_flags_len > 0) \ { \ char __tmp = __getopt_nonoption_flags[ch1]; \ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ __getopt_nonoption_flags[ch2] = __tmp; \ } # else # define SWAP_FLAGS(ch1, ch2) # endif #else /* !_LIBC */ # define SWAP_FLAGS(ch1, ch2) #endif /* _LIBC */ /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ #if defined __STDC__ && __STDC__ static void exchange (char **); #endif static void exchange (argv) char **argv; { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS /* First make sure the handling of the `__getopt_nonoption_flags' string can work normally. Our top argument must be in the range of the string. */ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) { /* We must extend the array. The user plays games with us and presents new arguments. */ char *new_str = malloc (top + 1); if (new_str == NULL) nonoption_flags_len = nonoption_flags_max_len = 0; else { memset (__mempcpy (new_str, __getopt_nonoption_flags, nonoption_flags_max_len), '\0', top + 1 - nonoption_flags_max_len); nonoption_flags_max_len = top + 1; __getopt_nonoption_flags = new_str; } } #endif while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; SWAP_FLAGS (bottom + i, middle + i); } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ #if defined __STDC__ && __STDC__ static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * _getopt_initialize (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; #if defined _LIBC && defined USE_NONOPTION_FLAGS if (posixly_correct == NULL && argc == __libc_argc && argv == __libc_argv) { if (nonoption_flags_max_len == 0) { if (__getopt_nonoption_flags == NULL || __getopt_nonoption_flags[0] == '\0') nonoption_flags_max_len = -1; else { const char *orig_str = __getopt_nonoption_flags; int len = nonoption_flags_max_len = strlen (orig_str); if (nonoption_flags_max_len < argc) nonoption_flags_max_len = argc; __getopt_nonoption_flags = (char *) malloc (nonoption_flags_max_len); if (__getopt_nonoption_flags == NULL) nonoption_flags_max_len = -1; else memset (__mempcpy (__getopt_nonoption_flags, orig_str, len), '\0', nonoption_flags_max_len - len); } } nonoption_flags_len = nonoption_flags_max_len; } else nonoption_flags_len = 0; #endif return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns -1. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int argc; char *const *argv; const char *optstring; const struct option *longopts; int *longind; int long_only; { int print_errors = opterr; if (optstring[0] == ':') print_errors = 0; if (argc < 1) return -1; optarg = NULL; if (optind == 0 || !__getopt_initialized) { if (optind == 0) optind = 1; /* Don't scan ARGV[0], the program name. */ optstring = _getopt_initialize (argc, argv, optstring); __getopt_initialized = 1; } /* Test whether ARGV[optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag from the shell indicating it is not an option. The later information is only used when the used in the GNU libc. */ #if defined _LIBC && defined USE_NONOPTION_FLAGS # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ || (optind < nonoption_flags_len \ && __getopt_nonoption_flags[optind] == '1')) #else # define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') #endif if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been moved back by the user (who may also have changed the arguments). */ if (last_nonopt > optind) last_nonopt = optind; if (first_nonopt > optind) first_nonopt = optind; if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && NONOPTION_P) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return -1; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if (NONOPTION_P) { if (ordering == REQUIRE_ORDER) return -1; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = -1; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == (unsigned int) strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); #endif } nextchar += strlen (nextchar); optind++; optopt = 0; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (argv[optind - 1][1] == '-') { /* --option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("\ %s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); #else fprintf (stderr, _("\ %s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); #endif } else { /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("\ %s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); #else fprintf (stderr, _("\ %s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #endif } nextchar += strlen (nextchar); optopt = pfound->val; return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); #endif } nextchar += strlen (nextchar); optopt = pfound->val; return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (argv[optind][1] == '-') { /* --option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); #else fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); #endif } else { /* +option or -option */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); #else fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #endif } nextchar = (char *) ""; optind++; optopt = 0; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; int n; #endif if (posixly_correct) { /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: illegal option -- %c\n"), argv[0], c); #else fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); #endif } else { #if defined _LIBC && defined USE_IN_LIBIO n = __asprintf (&buf, _("%s: invalid option -- %c\n"), argv[0], c); #else fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c); #endif } #if defined _LIBC && defined USE_IN_LIBIO if (n >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #endif } optopt = c; return '?'; } /* Convenience. Treat POSIX -W foo same as long option --foo */ if (temp[0] == 'W' && temp[1] == ';') { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("%s: option requires an argument -- %c\n"), argv[0], c) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; return c; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; /* optarg is now the argument, see if it's in the table of longopts. */ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if ((unsigned int) (nameend - nextchar) == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), argv[0], argv[optind]); #endif } nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("\ %s: option `-W %s' doesn't allow an argument\n"), argv[0], pfound->name); #endif } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (print_errors) { #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); #endif } nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } nextchar = NULL; return 'W'; /* Let the application handle it. */ } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (print_errors) { /* 1003.2 specifies the format of this message. */ #if defined _LIBC && defined USE_IN_LIBIO char *buf; if (__asprintf (&buf, _("\ %s: option requires an argument -- %c\n"), argv[0], c) >= 0) { if (_IO_fwide (stderr, 0) > 0) __fwprintf (stderr, L"%s", buf); else fputs (buf, stderr); free (buf); } #else fprintf (stderr, _("%s: option requires an argument -- %c\n"), argv[0], c); #endif } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (argc, argv, optstring) int argc; char *const *argv; const char *optstring; { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* Not ELIDE_CODE. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (argc, argv) int argc; char **argv; { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == -1) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/getopt/getopt.h������������������������������������������������������0000644�0000000�0000000�00000014477�12062407372�020056� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Declarations for getopt. Copyright (C) 1989-1994, 1996-1999, 2001 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _GETOPT_H #ifndef __need_getopt # define _GETOPT_H 1 #endif /* If __GNU_LIBRARY__ is not already defined, either we are being used standalone, or this is the first header included in the source file. If we are being used with glibc, we need to include <features.h>, but that does not exist if we are standalone. So: if __GNU_LIBRARY__ is not defined, include <ctype.h>, which will pull in <features.h> for us if it's from glibc. (Why ctype.h? It's guaranteed to exist and it doesn't flood the namespace with stuff the way some other headers do.) */ #if !defined __GNU_LIBRARY__ # include <ctype.h> #endif #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns -1, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; #ifndef __need_getopt /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { # if (defined __STDC__ && __STDC__) || defined __cplusplus const char *name; # else char *name; # endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ # define no_argument 0 # define required_argument 1 # define optional_argument 2 #endif /* need getopt */ /* Get definitions and prototypes for functions to process the arguments in ARGV (ARGC of them, minus the program name) for options given in OPTS. Return the option character from OPTS just read. Return -1 when there are no more options. For unrecognized options, or options missing arguments, `optopt' is set to the option letter, and '?' is returned. The OPTS string is a list of characters which are recognized option letters, optionally followed by colons, specifying that that letter takes an argument, to be placed in `optarg'. If a letter in OPTS is followed by two colons, its argument is optional. This behavior is specific to the GNU `getopt'. The argument `--' causes premature termination of argument scanning, explicitly telling `getopt' that there are no more options. If OPTS begins with `--', then non-option arguments are treated as arguments to the option '\0'. This behavior is specific to the GNU `getopt'. */ #if (defined __STDC__ && __STDC__) || defined __cplusplus # ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int ___argc, char *const *___argv, const char *__shortopts); # else /* not __GNU_LIBRARY__ */ extern int getopt (); # endif /* __GNU_LIBRARY__ */ # ifndef __need_getopt extern int getopt_long (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind); extern int getopt_long_only (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int ___argc, char *const *___argv, const char *__shortopts, const struct option *__longopts, int *__longind, int __long_only); # endif #else /* not __STDC__ */ extern int getopt (); # ifndef __need_getopt extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); # endif #endif /* __STDC__ */ #ifdef __cplusplus } #endif /* Make sure we later can get all the definitions and declarations. */ #undef __need_getopt #endif /* getopt.h */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_freebsd.cpp�������������������������������������������������������0000644�0000000�0000000�00000163041�12165521246�017711� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_freebsd.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-10 Eduard Martinescu <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <fcntl.h> #include <err.h> #include <errno.h> #include <camlib.h> #include <cam/scsi/scsi_message.h> #include <cam/scsi/scsi_pass.h> #if defined(__DragonFly__) #include <sys/nata.h> #else #include <sys/ata.h> #endif #include <sys/stat.h> #include <unistd.h> #include <glob.h> #include <stddef.h> #include <paths.h> #include <sys/utsname.h> #include "config.h" #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "cciss.h" #include "utility.h" #include "os_freebsd.h" #include "dev_interface.h" #include "dev_ata_cmd_set.h" #include "dev_areca.h" #define USBDEV "/dev/usb" #if defined(__FreeBSD_version) // This way we define one variable for the GNU/kFreeBSD and FreeBSD #define FREEBSDVER __FreeBSD_version #else #define FREEBSDVER __FreeBSD_kernel_version #endif #if (FREEBSDVER >= 800000) #include <libusb20_desc.h> #include <libusb20.h> #elif defined(__DragonFly__) #include <bus/usb/usb.h> #include <bus/usb/usbhid.h> #else #include <dev/usb/usb.h> #include <dev/usb/usbhid.h> #endif #define CONTROLLER_3WARE_9000_CHAR 0x01 #define CONTROLLER_3WARE_678K_CHAR 0x02 #ifndef PATHINQ_SETTINGS_SIZE #define PATHINQ_SETTINGS_SIZE 128 #endif const char *os_XXXX_c_cvsid="$Id: os_freebsd.cpp 3824 2013-07-05 10:40:38Z samm2 $" \ ATACMDS_H_CVSID CCISS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_FREEBSD_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; #define NO_RETURN 0 #define BAD_SMART 1 #define NO_DISK_3WARE 2 #define BAD_KERNEL 3 #define MAX_MSG 3 // Utility function for printing warnings void printwarning(int msgNo, const char* extra) { static int printed[] = {0,0,0,0}; static const char* message[]={ "The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n can not be retrieved with this version of ATAng, please do not rely on this value\nYou should update to at least 5.2\n", "Error SMART Status command failed\nPlease get assistance from \n" PACKAGE_HOMEPAGE "\nRegister values returned from SMART Status command are:\n", "You must specify a DISK # for 3ware drives with -d 3ware,<n> where <n> begins with 1 for first disk drive\n", "ATA support is not provided for this kernel version. Please ugrade to a recent 5-CURRENT kernel (post 09/01/2003 or so)\n" }; if (msgNo >= 0 && msgNo <= MAX_MSG) { if (!printed[msgNo]) { printed[msgNo] = 1; pout("%s", message[msgNo]); if (extra) pout("%s",extra); } } return; } // Interface to ATA devices behind 3ware escalade RAID controller cards. See os_linux.c #define BUFFER_LEN_678K_CHAR ( sizeof(struct twe_usercommand) ) // 520 #define BUFFER_LEN_9000_CHAR ( sizeof(TW_OSLI_IOCTL_NO_DATA_BUF) + sizeof(TWE_Command) ) // 2048 #define TW_IOCTL_BUFFER_SIZE ( MAX(BUFFER_LEN_678K_CHAR, BUFFER_LEN_9000_CHAR) ) #ifndef ATA_DEVICE #define ATA_DEVICE "/dev/ata" #endif #define ARGUSED(x) ((void)(x)) // global variable holding byte count of allocated memory long long bytes; extern unsigned char failuretest_permissive; ///////////////////////////////////////////////////////////////////////////// namespace os_freebsd { // No need to publish anything, name provided for Doxygen ///////////////////////////////////////////////////////////////////////////// /// Implement shared open/close routines with old functions. class freebsd_smart_device : virtual public /*implements*/ smart_device { public: explicit freebsd_smart_device(const char * mode) : smart_device(never_called), m_fd(-1), m_mode(mode) { } virtual ~freebsd_smart_device() throw(); virtual bool is_open() const; virtual bool open(); virtual bool close(); protected: /// Return filedesc for derived classes. int get_fd() const { return m_fd; } void set_fd(int fd) { m_fd = fd; } private: int m_fd; ///< filedesc, -1 if not open. const char * m_mode; ///< Mode string for deviceopen(). }; #ifdef __GLIBC__ static inline void * reallocf(void *ptr, size_t size) { void *rv = realloc(ptr, size); if((rv == NULL) && (size != 0)) free(ptr); return rv; } #endif freebsd_smart_device::~freebsd_smart_device() throw() { if (m_fd >= 0) os_freebsd::freebsd_smart_device::close(); } // migration from the old_style unsigned char m_controller_type; unsigned char m_controller_port; // examples for smartctl static const char smartctl_examples[] = "=================================================== SMARTCTL EXAMPLES =====\n\n" " smartctl -a /dev/ad0 (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/ad0\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/ad0 (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/ad0\n" " (Prints Self-Test & Attribute errors)\n" " (Prints Self-Test & Attribute errors)\n\n" " smartctl -a --device=3ware,2 /dev/twa0\n" " smartctl -a --device=3ware,2 /dev/twe0\n" " smartctl -a --device=3ware,2 /dev/tws0\n" " (Prints all SMART information for ATA disk on\n" " third port of first 3ware RAID controller)\n" " smartctl -a --device=cciss,0 /dev/ciss0\n" " (Prints all SMART information for first disk \n" " on Common Interface for SCSI-3 Support driver)\n" " smartctl -a --device=areca,3/1 /dev/arcmsr0\n" " (Prints all SMART information for 3rd disk in the 1st enclosure \n" " on first ARECA RAID controller)\n" ; bool freebsd_smart_device::is_open() const { return (m_fd >= 0); } bool freebsd_smart_device::open() { const char *dev = get_dev_name(); if ((m_fd = ::open(dev,O_RDONLY))<0) { set_err(errno); return false; } return true; } bool freebsd_smart_device::close() { int failed = 0; // close device, if open if (is_open()) failed=::close(get_fd()); set_fd(-1); if(failed) return false; else return true; } ///////////////////////////////////////////////////////////////////////////// /// Implement standard ATA support class freebsd_ata_device : public /*implements*/ ata_device, public /*extends*/ freebsd_smart_device { public: freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); protected: virtual int do_cmd(struct ata_ioc_request* request, bool is_48bit_cmd); }; freebsd_ata_device::freebsd_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "ata", req_type), freebsd_smart_device("ATA") { } int freebsd_ata_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd) { int fd = get_fd(), ret; ARGUSED(is_48bit_cmd); // no support for 48 bit commands in the IOCATAREQUEST ret = ioctl(fd, IOCATAREQUEST, request); if (ret) set_err(errno); return ret; } bool freebsd_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { bool ata_48bit = false; // no ata_48bit_support via IOCATAREQUEST if(!strcmp("atacam",get_dev_type())) // enable for atacam interface ata_48bit = true; if (!ata_cmd_is_ok(in, true, // data_out_support true, // multi_sector_support ata_48bit) ) { set_err(ENOSYS, "48-bit ATA commands not implemented for legacy controllers"); return false; } struct ata_ioc_request request; bzero(&request,sizeof(struct ata_ioc_request)); request.timeout=SCSI_TIMEOUT_DEFAULT; request.u.ata.command=in.in_regs.command; request.u.ata.feature=in.in_regs.features; request.u.ata.count = in.in_regs.sector_count_16; request.u.ata.lba = in.in_regs.lba_48; switch (in.direction) { case ata_cmd_in::no_data: request.flags=ATA_CMD_CONTROL; break; case ata_cmd_in::data_in: request.flags=ATA_CMD_READ | ATA_CMD_CONTROL; request.data=(char *)in.buffer; request.count=in.size; break; case ata_cmd_in::data_out: request.flags=ATA_CMD_WRITE | ATA_CMD_CONTROL; request.data=(char *)in.buffer; request.count=in.size; break; default: return set_err(ENOSYS); } clear_err(); errno = 0; if (do_cmd(&request, in.in_regs.is_48bit_cmd())) return false; if (request.error) return set_err(EIO, "request failed, error code 0x%02x", request.error); out.out_regs.error = request.error; out.out_regs.sector_count_16 = request.u.ata.count; out.out_regs.lba_48 = request.u.ata.lba; // Command specific processing if (in.in_regs.command == ATA_SMART_CMD && in.in_regs.features == ATA_SMART_STATUS && in.out_needed.lba_high) { unsigned const char normal_lo=0x4f, normal_hi=0xc2; unsigned const char failed_lo=0xf4, failed_hi=0x2c; // Cyl low and Cyl high unchanged means "Good SMART status" if (!(out.out_regs.lba_mid==normal_lo && out.out_regs.lba_high==normal_hi) // These values mean "Bad SMART status" && !(out.out_regs.lba_mid==failed_lo && out.out_regs.lba_high==failed_hi)) { // We haven't gotten output that makes sense; print out some debugging info char buf[512]; snprintf(buf, sizeof(buf), "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", (int)request.u.ata.command, (int)request.u.ata.feature, (int)request.u.ata.count, (int)((request.u.ata.lba) & 0xff), (int)((request.u.ata.lba>>8) & 0xff), (int)((request.u.ata.lba>>16) & 0xff), (int)request.error); printwarning(BAD_SMART,buf); out.out_regs.lba_high = failed_hi; out.out_regs.lba_mid = failed_lo; } } return true; } #if FREEBSDVER > 800100 class freebsd_atacam_device : public freebsd_ata_device { public: freebsd_atacam_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "atacam", req_type), freebsd_ata_device(intf, dev_name, req_type) {} virtual bool open(); virtual bool close(); protected: int m_fd; struct cam_device *m_camdev; virtual int do_cmd( struct ata_ioc_request* request , bool is_48bit_cmd); }; bool freebsd_atacam_device::open(){ const char *dev = get_dev_name(); if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) { set_err(errno); return false; } set_fd(m_camdev->fd); return true; } bool freebsd_atacam_device::close(){ cam_close_device(m_camdev); set_fd(-1); return true; } int freebsd_atacam_device::do_cmd( struct ata_ioc_request* request, bool is_48bit_cmd) { union ccb ccb; int camflags; // FIXME: // 48bit commands are broken in ATACAM before r242422/HEAD // and may cause system hang // Waiting for MFC to make sure that bug is fixed, // later version check needs to be added if(!strcmp("ata",m_camdev->sim_name) && is_48bit_cmd) { set_err(ENOSYS, "48-bit ATA commands not implemented for legacy controllers"); return -1; } memset(&ccb, 0, sizeof(ccb)); if (request->count == 0) camflags = CAM_DIR_NONE; else if (request->flags & ATA_CMD_READ) camflags = CAM_DIR_IN; else camflags = CAM_DIR_OUT; cam_fill_ataio(&ccb.ataio, 0, NULL, camflags, MSG_SIMPLE_Q_TAG, (u_int8_t*)request->data, request->count, request->timeout * 1000); // timeout in seconds ccb.ataio.cmd.flags = CAM_ATAIO_NEEDRESULT | (is_48bit_cmd ? CAM_ATAIO_48BIT : 0); // ata_28bit_cmd ccb.ataio.cmd.command = request->u.ata.command; ccb.ataio.cmd.features = request->u.ata.feature; ccb.ataio.cmd.lba_low = request->u.ata.lba; ccb.ataio.cmd.lba_mid = request->u.ata.lba >> 8; ccb.ataio.cmd.lba_high = request->u.ata.lba >> 16; // ata_48bit cmd ccb.ataio.cmd.lba_low_exp = request->u.ata.lba >> 24; ccb.ataio.cmd.lba_mid_exp = request->u.ata.lba >> 32; ccb.ataio.cmd.lba_high_exp = request->u.ata.lba >> 40; ccb.ataio.cmd.device = 0x40 | ((request->u.ata.lba >> 24) & 0x0f); ccb.ataio.cmd.sector_count = request->u.ata.count; ccb.ataio.cmd.sector_count_exp = request->u.ata.count >> 8;; ccb.ccb_h.flags |= CAM_DEV_QFRZDIS; if (cam_send_ccb(m_camdev, &ccb) < 0) { set_err(EIO, "cam_send_ccb failed"); return -1; } if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { cam_error_print(m_camdev, &ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); set_err(EIO); return -1; } request->u.ata.lba = ((u_int64_t)(ccb.ataio.res.lba_low)) | ((u_int64_t)(ccb.ataio.res.lba_mid) << 8) | ((u_int64_t)(ccb.ataio.res.lba_high) << 16) | ((u_int64_t)(ccb.ataio.res.lba_low_exp) << 24) | ((u_int64_t)(ccb.ataio.res.lba_mid_exp) << 32) | ((u_int64_t)(ccb.ataio.res.lba_high_exp) << 40); request->u.ata.count = ccb.ataio.res.sector_count | (ccb.ataio.res.sector_count_exp << 8); request->error = ccb.ataio.res.error; return 0; } #endif ///////////////////////////////////////////////////////////////////////////// /// Implement AMCC/3ware RAID support class freebsd_escalade_device : public /*implements*/ ata_device, public /*extends*/ freebsd_smart_device { public: freebsd_escalade_device(smart_interface * intf, const char * dev_name, int escalade_type, int disknum); protected: virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); virtual bool open(); private: int m_escalade_type; ///< Type string for escalade_command_interface(). int m_disknum; ///< Disk number. }; freebsd_escalade_device::freebsd_escalade_device(smart_interface * intf, const char * dev_name, int escalade_type, int disknum) : smart_device(intf, dev_name, "3ware", "3ware"), freebsd_smart_device( escalade_type==CONTROLLER_3WARE_9000_CHAR ? "ATA_3WARE_9000" : escalade_type==CONTROLLER_3WARE_678K_CHAR ? "ATA_3WARE_678K" : /* CONTROLLER_3WARE_678K */ "ATA" ), m_escalade_type(escalade_type), m_disknum(disknum) { set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum); } bool freebsd_escalade_device::open() { const char *dev = get_dev_name(); int fd; if ((fd = ::open(dev,O_RDWR))<0) { set_err(errno); return false; } set_fd(fd); return true; } bool freebsd_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { // to hold true file descriptor int fd = get_fd(); if (!ata_cmd_is_ok(in, true, // data_out_support false, // TODO: multi_sector_support true) // ata_48bit_support ) return false; struct twe_usercommand* cmd_twe = NULL; TW_OSLI_IOCTL_NO_DATA_BUF* cmd_twa = NULL; TWE_Command_ATA* ata = NULL; // Used by both the SCSI and char interfaces char ioctl_buffer[TW_IOCTL_BUFFER_SIZE]; if (m_disknum < 0) { printwarning(NO_DISK_3WARE,NULL); return -1; } memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE); if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { cmd_twa = (TW_OSLI_IOCTL_NO_DATA_BUF*)ioctl_buffer; cmd_twa->pdata = ((TW_OSLI_IOCTL_WITH_PAYLOAD*)cmd_twa)->payload.data_buf; cmd_twa->driver_pkt.buffer_length = in.size; // using "old" packet format to speak with SATA devices ata = (TWE_Command_ATA*)&cmd_twa->cmd_pkt.command.cmd_pkt_7k; } else if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { cmd_twe = (struct twe_usercommand*)ioctl_buffer; ata = &cmd_twe->tu_command.ata; } else { return set_err(ENOSYS, "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" "Please contact " PACKAGE_BUGREPORT "\n", (int)m_escalade_type, m_disknum); } ata->opcode = TWE_OP_ATA_PASSTHROUGH; // Same for (almost) all commands - but some reset below ata->request_id = 0xFF; ata->unit = m_disknum; ata->status = 0; ata->flags = 0x1; ata->size = 0x5; // TODO: multisector support // Set registers { const ata_in_regs_48bit & r = in.in_regs; ata->features = r.features_16; ata->sector_count = r.sector_count_16; ata->sector_num = r.lba_low_16; ata->cylinder_lo = r.lba_mid_16; ata->cylinder_hi = r.lba_high_16; ata->drive_head = r.device; ata->command = r.command; } // Is this a command that reads or returns 512 bytes? // passthru->param values are: // 0x0 - non data command without TFR write check, // 0x8 - non data command with TFR write check, // 0xD - data command that returns data to host from device // 0xF - data command that writes data from host to device // passthru->size values are 0x5 for non-data and 0x07 for data bool readdata = false; if (in.direction == ata_cmd_in::data_in) { if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { cmd_twe->tu_data = in.buffer; cmd_twe->tu_size = 512; } readdata=true; ata->sgl_offset = 0x5; ata->param = 0xD; // For 64-bit to work correctly, up the size of the command packet // in dwords by 1 to account for the 64-bit single sgl 'address' // field. Note that this doesn't agree with the typedefs but it's // right (agree with kernel driver behavior/typedefs). // if (sizeof(long)==8) // ata->size++; } else if (in.direction == ata_cmd_in::no_data) { // Non data command -- but doesn't use large sector // count register values. ata->sgl_offset = 0x0; ata->param = 0x8; ata->sector_count = 0x0; } else if (in.direction == ata_cmd_in::data_out) { ata->sgl_offset = 0x5; ata->param = 0xF; // PIO data write if (m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { cmd_twe->tu_data = in.buffer; cmd_twe->tu_size = 512; } else if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { memcpy(cmd_twa->pdata, in.buffer, in.size); } } else return set_err(EINVAL); // 3WARE controller can NOT have packet device internally if (in.in_regs.command == ATA_IDENTIFY_PACKET_DEVICE) { return set_err(ENODEV, "No drive on port %d", m_disknum); } // Now send the command down through an ioctl() int ioctlreturn; if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) { ioctlreturn=ioctl(fd,TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH,cmd_twa); } else { ioctlreturn=ioctl(fd,TWEIO_COMMAND,cmd_twe); } // Deal with the different error cases if (ioctlreturn) { return set_err(EIO); } // See if the ATA command failed. Now that we have returned from // the ioctl() call, if passthru is valid, then: // - ata->status contains the 3ware controller STATUS // - ata->command contains the ATA STATUS register // - ata->features contains the ATA ERROR register // // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS // If bit 0 (error bit) is set, then ATA ERROR register is valid. // While we *might* decode the ATA ERROR register, at the moment it // doesn't make much sense: we don't care in detail why the error // happened. if (ata->status || (ata->command & 0x21)) { if (scsi_debugmode) pout("Command failed, ata.status=(0x%2.2x), ata.command=(0x%2.2x), ata.flags=(0x%2.2x)\n",ata->status,ata->command,ata->flags); return set_err(EIO); } // If this is a read data command, copy data to output buffer if (readdata) { if (m_escalade_type==CONTROLLER_3WARE_9000_CHAR) memcpy(in.buffer, cmd_twa->pdata, in.size); else if(m_escalade_type==CONTROLLER_3WARE_678K_CHAR) { memcpy(in.buffer, cmd_twe->tu_data, in.size); // untested } } // Return register values if (ata) { ata_out_regs_48bit & r = out.out_regs; r.error = ata->features; r.sector_count_16 = ata->sector_count; r.lba_low_16 = ata->sector_num; r.lba_mid_16 = ata->cylinder_lo; r.lba_high_16 = ata->cylinder_hi; r.device = ata->drive_head; r.status = ata->command; } // look for nonexistent devices/ports if (in.in_regs.command == ATA_IDENTIFY_DEVICE && !nonempty((unsigned char *)in.buffer, in.size)) { return set_err(ENODEV, "No drive on port %d", m_disknum); } return true; } ///////////////////////////////////////////////////////////////////////////// /// Implement Highpoint RAID support with old functions class freebsd_highpoint_device : public /*implements*/ ata_device_with_command_set, public /*extends*/ freebsd_smart_device { public: freebsd_highpoint_device(smart_interface * intf, const char * dev_name, unsigned char controller, unsigned char channel, unsigned char port); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); virtual bool open(); private: unsigned char m_hpt_data[3]; ///< controller/channel/port }; freebsd_highpoint_device::freebsd_highpoint_device(smart_interface * intf, const char * dev_name, unsigned char controller, unsigned char channel, unsigned char port) : smart_device(intf, dev_name, "hpt", "hpt"), freebsd_smart_device("ATA") { m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port; set_info().info_name = strprintf("%s [hpt_disk_%u/%u/%u]", dev_name, m_hpt_data[0], m_hpt_data[1], m_hpt_data[2]); } bool freebsd_highpoint_device::open() { const char *dev = get_dev_name(); int fd; if ((fd = ::open(dev,O_RDWR))<0) { set_err(errno); return false; } set_fd(fd); return true; } int freebsd_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data) { int fd=get_fd(); int ids[2]; HPT_IOCTL_PARAM param; HPT_CHANNEL_INFO_V2 info; unsigned char* buff[512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)]; PHPT_PASS_THROUGH_HEADER pide_pt_hdr, pide_pt_hdr_out; // get internal deviceid ids[0] = m_hpt_data[0] - 1; ids[1] = m_hpt_data[1] - 1; memset(¶m, 0, sizeof(HPT_IOCTL_PARAM)); param.magic = HPT_IOCTL_MAGIC; param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO_V2; param.in = (unsigned char *)ids; param.in_size = sizeof(unsigned int) * 2; param.out = (unsigned char *)&info; param.out_size = sizeof(HPT_CHANNEL_INFO_V2); if (m_hpt_data[2]==1) { param.ctrl_code = HPT_IOCTL_GET_CHANNEL_INFO; param.out_size = sizeof(HPT_CHANNEL_INFO); } if (ioctl(fd, HPT_DO_IOCONTROL, ¶m)!=0 || info.devices[m_hpt_data[2]-1]==0) { return -1; } // perform smart action memset(buff, 0, 512 + 2 * sizeof(HPT_PASS_THROUGH_HEADER)); pide_pt_hdr = (PHPT_PASS_THROUGH_HEADER)buff; pide_pt_hdr->lbamid = 0x4f; pide_pt_hdr->lbahigh = 0xc2; pide_pt_hdr->command = ATA_SMART_CMD; pide_pt_hdr->id = info.devices[m_hpt_data[2] - 1]; switch (command){ case READ_VALUES: pide_pt_hdr->feature=ATA_SMART_READ_VALUES; pide_pt_hdr->protocol=HPT_READ; break; case READ_THRESHOLDS: pide_pt_hdr->feature=ATA_SMART_READ_THRESHOLDS; pide_pt_hdr->protocol=HPT_READ; break; case READ_LOG: pide_pt_hdr->feature=ATA_SMART_READ_LOG_SECTOR; pide_pt_hdr->lbalow=select; pide_pt_hdr->protocol=HPT_READ; break; case IDENTIFY: pide_pt_hdr->command=ATA_IDENTIFY_DEVICE; pide_pt_hdr->protocol=HPT_READ; break; case ENABLE: pide_pt_hdr->feature=ATA_SMART_ENABLE; break; case DISABLE: pide_pt_hdr->feature=ATA_SMART_DISABLE; break; case AUTO_OFFLINE: pide_pt_hdr->feature=ATA_SMART_AUTO_OFFLINE; pide_pt_hdr->sectorcount=select; break; case AUTOSAVE: pide_pt_hdr->feature=ATA_SMART_AUTOSAVE; pide_pt_hdr->sectorcount=select; break; case IMMEDIATE_OFFLINE: pide_pt_hdr->feature=ATA_SMART_IMMEDIATE_OFFLINE; pide_pt_hdr->lbalow=select; break; case STATUS_CHECK: case STATUS: pide_pt_hdr->feature=ATA_SMART_STATUS; break; case CHECK_POWER_MODE: pide_pt_hdr->command=ATA_CHECK_POWER_MODE; break; case WRITE_LOG: memcpy(buff+sizeof(HPT_PASS_THROUGH_HEADER), data, 512); pide_pt_hdr->feature=ATA_SMART_WRITE_LOG_SECTOR; pide_pt_hdr->lbalow=select; pide_pt_hdr->protocol=HPT_WRITE; break; default: pout("Unrecognized command %d in highpoint_command_interface()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); errno=ENOSYS; return -1; } if (pide_pt_hdr->protocol!=0) { pide_pt_hdr->sectors = 1; pide_pt_hdr->sectorcount = 1; } memset(¶m, 0, sizeof(HPT_IOCTL_PARAM)); param.magic = HPT_IOCTL_MAGIC; param.ctrl_code = HPT_IOCTL_IDE_PASS_THROUGH; param.in = (unsigned char *)buff; param.in_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? 0 : pide_pt_hdr->sectors * 512); param.out = (unsigned char *)buff+param.in_size; param.out_size = sizeof(HPT_PASS_THROUGH_HEADER) + (pide_pt_hdr->protocol==HPT_READ ? pide_pt_hdr->sectors * 512 : 0); pide_pt_hdr_out = (PHPT_PASS_THROUGH_HEADER)param.out; if ((ioctl(fd, HPT_DO_IOCONTROL, ¶m)!=0) || (pide_pt_hdr_out->command & 1)) { return -1; } if (command==STATUS_CHECK) { unsigned const char normal_lo=0x4f, normal_hi=0xc2; unsigned const char failed_lo=0xf4, failed_hi=0x2c; unsigned char low,high; high = pide_pt_hdr_out->lbahigh; low = pide_pt_hdr_out->lbamid; // Cyl low and Cyl high unchanged means "Good SMART status" if (low==normal_lo && high==normal_hi) return 0; // These values mean "Bad SMART status" if (low==failed_lo && high==failed_hi) return 1; // We haven't gotten output that makes sense; print out some debugging info char buf[512]; snprintf(buf, sizeof(buf), "CMD=0x%02x\nFR =0x%02x\nNS =0x%02x\nSC =0x%02x\nCL =0x%02x\nCH =0x%02x\nRETURN =0x%04x\n", (int)pide_pt_hdr_out->command, (int)pide_pt_hdr_out->feature, (int)pide_pt_hdr_out->sectorcount, (int)pide_pt_hdr_out->lbalow, (int)pide_pt_hdr_out->lbamid, (int)pide_pt_hdr_out->lbahigh, (int)pide_pt_hdr_out->sectors); printwarning(BAD_SMART,buf); } else if (command==CHECK_POWER_MODE) data[0] = pide_pt_hdr_out->sectorcount & 0xff; else if (pide_pt_hdr->protocol==HPT_READ) memcpy(data, (unsigned char *)buff + 2 * sizeof(HPT_PASS_THROUGH_HEADER), pide_pt_hdr->sectors * 512); return 0; } ///////////////////////////////////////////////////////////////////////////// /// Standard SCSI support class freebsd_scsi_device : public /*implements*/ scsi_device, public /*extends*/ freebsd_smart_device { public: freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type); virtual smart_device * autodetect_open(); virtual bool scsi_pass_through(scsi_cmnd_io * iop); virtual bool open(); virtual bool close(); private: int m_fd; struct cam_device *m_camdev; }; bool freebsd_scsi_device::open(){ const char *dev = get_dev_name(); if ((m_camdev = cam_open_device(dev, O_RDWR)) == NULL) { set_err(errno); return false; } set_fd(m_camdev->fd); return true; } bool freebsd_scsi_device::close(){ cam_close_device(m_camdev); set_fd(-1); return true; } freebsd_scsi_device::freebsd_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "scsi", req_type), freebsd_smart_device("SCSI") { } bool freebsd_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) { int report=scsi_debugmode; union ccb *ccb; if (report > 0) { unsigned int k; const unsigned char * ucp = iop->cmnd; const char * np; np = scsi_get_opcode_name(ucp[0]); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < iop->cmnd_len; ++k) pout("%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout("]\n Outgoing data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else pout("]"); } if(m_camdev==NULL) { warnx("error: camdev=0!"); return -ENOTTY; } if (!(ccb = cam_getccb(m_camdev))) { warnx("error allocating ccb"); return -ENOMEM; } // mfi SAT layer is known to be buggy if(!strcmp("mfi",m_camdev->sim_name)) { if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { // Controller does not return ATA output registers in SAT sense data if (iop->cmnd[2] & (1 << 5)) // chk_cond return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware"); } // SMART WRITE LOG SECTOR causing media errors if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 && iop->cmnd[14] == ATA_SMART_CMD && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) { if(!failuretest_permissive) return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); } } // clear out structure, except for header that was filled in for us bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); cam_fill_csio(&ccb->csio, /*retrires*/ 1, /*cbfcnp*/ NULL, /* flags */ (iop->dxfer_dir == DXFER_NONE ? CAM_DIR_NONE :(iop->dxfer_dir == DXFER_FROM_DEVICE ? CAM_DIR_IN : CAM_DIR_OUT)), /* tagaction */ MSG_SIMPLE_Q_TAG, /* dataptr */ iop->dxferp, /* datalen */ iop->dxfer_len, /* senselen */ iop->max_sense_len, /* cdblen */ iop->cmnd_len, /* timout (converted to seconds) */ iop->timeout*1000); memcpy(ccb->csio.cdb_io.cdb_bytes,iop->cmnd,iop->cmnd_len); if (cam_send_ccb(m_camdev,ccb) < 0) { warn("error sending SCSI ccb"); cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); cam_freeccb(ccb); return -EIO; } if (((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) && ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_SCSI_STATUS_ERROR)) { cam_error_print(m_camdev,ccb,CAM_ESF_ALL,CAM_EPF_ALL,stderr); cam_freeccb(ccb); return -EIO; } if (iop->sensep) { iop->resp_sense_len = ccb->csio.sense_len - ccb->csio.sense_resid; memcpy(iop->sensep,&(ccb->csio.sense_data),iop->resp_sense_len); } iop->scsi_status = ccb->csio.scsi_status; cam_freeccb(ccb); if (report > 0) { int trunc; pout(" status=0\n"); trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex(iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } // mfip replacing PDT of the device so response does not make a sense // this sets PDT to 00h - direct-access block device if((!strcmp("mfi", m_camdev->sim_name) || !strcmp("mpt", m_camdev->sim_name)) && iop->cmnd[0] == INQUIRY) { if (report > 0) { pout("device on %s controller, patching PDT\n", m_camdev->sim_name); } iop->dxferp[0] = iop->dxferp[0] & 0xe0; } return true; } ///////////////////////////////////////////////////////////////////////////// /// Areca RAID support /////////////////////////////////////////////////////////////////// // SATA(ATA) device behind Areca RAID Controller class freebsd_areca_ata_device : public /*implements*/ areca_ata_device, public /*extends*/ freebsd_smart_device { public: freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); virtual smart_device * autodetect_open(); virtual bool arcmsr_lock(); virtual bool arcmsr_unlock(); virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); }; /////////////////////////////////////////////////////////////////// // SAS(SCSI) device behind Areca RAID Controller class freebsd_areca_scsi_device : public /*implements*/ areca_scsi_device, public /*extends*/ freebsd_smart_device { public: freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); virtual smart_device * autodetect_open(); virtual bool arcmsr_lock(); virtual bool arcmsr_unlock(); virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); }; // Areca RAID Controller(SATA Disk) freebsd_areca_ata_device::freebsd_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), freebsd_smart_device("ATA") { set_disknum(disknum); set_encnum(encnum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } smart_device * freebsd_areca_ata_device::autodetect_open() { int is_ata = 1; // autodetect device type is_ata = arcmsr_get_dev_type(); if(is_ata < 0) { set_err(EIO); return this; } if(is_ata == 1) { // SATA device return this; } // SAS device smart_device_auto_ptr newdev(new freebsd_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum())); close(); delete this; newdev->open(); // TODO: Can possibly pass open fd return newdev.release(); } int freebsd_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) { int ioctlreturn = 0; if(!is_open()) { if(!open()){ } } ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp); if (ioctlreturn) { // errors found return -1; } return ioctlreturn; } bool freebsd_areca_ata_device::arcmsr_lock() { return true; } bool freebsd_areca_ata_device::arcmsr_unlock() { return true; } // Areca RAID Controller(SAS Device) freebsd_areca_scsi_device::freebsd_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), freebsd_smart_device("SCSI") { set_disknum(disknum); set_encnum(encnum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } smart_device * freebsd_areca_scsi_device::autodetect_open() { return this; } int freebsd_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) { int ioctlreturn = 0; if(!is_open()) { if(!open()){ } } ioctlreturn = ioctl(get_fd(), ((sSRB_BUFFER *)(iop->dxferp))->srbioctl.ControlCode, iop->dxferp); if (ioctlreturn) { // errors found return -1; } return ioctlreturn; } bool freebsd_areca_scsi_device::arcmsr_lock() { return true; } bool freebsd_areca_scsi_device::arcmsr_unlock() { return true; } ///////////////////////////////////////////////////////////////////////////// /// Implement CCISS RAID support with old functions class freebsd_cciss_device : public /*implements*/ scsi_device, public /*extends*/ freebsd_smart_device { public: freebsd_cciss_device(smart_interface * intf, const char * name, unsigned char disknum); virtual bool scsi_pass_through(scsi_cmnd_io * iop); virtual bool open(); private: unsigned char m_disknum; ///< Disk number. }; bool freebsd_cciss_device::open() { const char *dev = get_dev_name(); int fd; if ((fd = ::open(dev,O_RDWR))<0) { set_err(errno); return false; } set_fd(fd); return true; } freebsd_cciss_device::freebsd_cciss_device(smart_interface * intf, const char * dev_name, unsigned char disknum) : smart_device(intf, dev_name, "cciss", "cciss"), freebsd_smart_device("SCSI"), m_disknum(disknum) { set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum); } bool freebsd_cciss_device::scsi_pass_through(scsi_cmnd_io * iop) { int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode); if (status < 0) return set_err(-status); return true; // not reached return true; } ///////////////////////////////////////////////////////////////////////////// /// SCSI open with autodetection support smart_device * freebsd_scsi_device::autodetect_open() { // Open device if (!open()) return this; // No Autodetection if device type was specified by user if (*get_req_type()) return this; // The code below is based on smartd.cpp:SCSIFilterKnown() // Get INQUIRY unsigned char req_buff[64] = {0, }; int req_len = 36; if (scsiStdInquiry(this, req_buff, req_len)) { // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices // watch this spot ... other devices could lock up here req_len = 64; if (scsiStdInquiry(this, req_buff, req_len)) { // device doesn't like INQUIRY commands close(); set_err(EIO, "INQUIRY failed"); return this; } } int avail_len = req_buff[4] + 5; int len = (avail_len < req_len ? avail_len : req_len); if (len < 36) return this; // Use INQUIRY to detect type // 3ware ? if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4) || !strcmp("tws",m_camdev->sim_name) || !strcmp("twa",m_camdev->sim_name)) { close(); set_err(EINVAL, "3ware/LSI controller, please try adding '-d 3ware,N',\n" "you may need to replace %s with /dev/twaN, /dev/tweN or /dev/twsN", get_dev_name()); return this; } // SAT or USB, skip MFI controllers because of bugs { smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); if (newdev) { // NOTE: 'this' is now owned by '*newdev' if(!strcmp("mfi",m_camdev->sim_name)) { newdev->close(); newdev->set_err(ENOSYS, "SATA device detected,\n" "MegaRAID SAT layer is reportedly buggy, use '-d sat' to try anyhow"); } return newdev; } } // Nothing special found return this; } ///////////////////////////////////////////////////////////////////////////// /// Implement platform interface with old functions. class freebsd_smart_interface : public /*implements*/ smart_interface { public: virtual std::string get_os_version_str(); virtual std::string get_app_examples(const char * appname); virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern = 0); protected: virtual ata_device * get_ata_device(const char * name, const char * type); #if FREEBSDVER > 800100 virtual ata_device * get_atacam_device(const char * name, const char * type); #endif virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); virtual smart_device * get_custom_smart_device(const char * name, const char * type); virtual std::string get_valid_custom_dev_types_str(); }; ////////////////////////////////////////////////////////////////////// std::string freebsd_smart_interface::get_os_version_str() { struct utsname osname; uname(&osname); return strprintf("%s %s %s", osname.sysname, osname.release, osname.machine); } std::string freebsd_smart_interface::get_app_examples(const char * appname) { if (!strcmp(appname, "smartctl")) return smartctl_examples; return ""; } ata_device * freebsd_smart_interface::get_ata_device(const char * name, const char * type) { return new freebsd_ata_device(this, name, type); } #if FREEBSDVER > 800100 ata_device * freebsd_smart_interface::get_atacam_device(const char * name, const char * type) { return new freebsd_atacam_device(this, name, type); } #endif scsi_device * freebsd_smart_interface::get_scsi_device(const char * name, const char * type) { return new freebsd_scsi_device(this, name, type); } // we are using CAM subsystem XPT enumerator to found all CAM (scsi/usb/ada/...) // devices on system despite of it's names // // If any errors occur, leave errno set as it was returned by the // system call, and return <0. // // arguments: // names: resulting array // show_all - export duplicate device name or not // // Return values: // -1: error // >=0: number of discovered devices bool get_dev_names_cam(std::vector<std::string> & names, bool show_all) { int fd; if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) { if (errno == ENOENT) /* There are no CAM device on this computer */ return 0; int serrno = errno; pout("%s control device couldn't opened: %s\n", XPT_DEVICE, strerror(errno)); errno = serrno; return false; } union ccb ccb; bzero(&ccb, sizeof(union ccb)); ccb.ccb_h.path_id = CAM_XPT_PATH_ID; ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; ccb.ccb_h.func_code = XPT_DEV_MATCH; int bufsize = sizeof(struct dev_match_result) * MAX_NUM_DEV; ccb.cdm.match_buf_len = bufsize; // TODO: Use local buffer instead of malloc() if possible ccb.cdm.matches = (struct dev_match_result *)malloc(bufsize); bzero(ccb.cdm.matches,bufsize); // clear ccb.cdm.matches structure if (ccb.cdm.matches == NULL) { close(fd); throw std::bad_alloc(); } ccb.cdm.num_matches = 0; ccb.cdm.num_patterns = 0; ccb.cdm.pattern_buf_len = 0; /* * We do the ioctl multiple times if necessary, in case there are * more than MAX_NUM_DEV nodes in the EDT. */ int skip_device = 0, skip_bus = 0, changed = 0; // TODO: bool std::string devname; do { if (ioctl(fd, CAMIOCOMMAND, &ccb) == -1) { int serrno = errno; pout("error sending CAMIOCOMMAND ioctl: %s\n", strerror(errno)); free(ccb.cdm.matches); close(fd); errno = serrno; return false; } if ((ccb.ccb_h.status != CAM_REQ_CMP) || ((ccb.cdm.status != CAM_DEV_MATCH_LAST) && (ccb.cdm.status != CAM_DEV_MATCH_MORE))) { pout("got CAM error %#x, CDM error %d\n", ccb.ccb_h.status, ccb.cdm.status); free(ccb.cdm.matches); close(fd); errno = ENXIO; return false; } for (unsigned i = 0; i < ccb.cdm.num_matches; i++) { struct bus_match_result *bus_result; struct device_match_result *dev_result; struct periph_match_result *periph_result; if (ccb.cdm.matches[i].type == DEV_MATCH_BUS) { bus_result = &ccb.cdm.matches[i].result.bus_result; if (strcmp(bus_result->dev_name,"xpt") == 0) /* skip XPT bus at all */ skip_bus = 1; else skip_bus = 0; changed = 1; } else if (ccb.cdm.matches[i].type == DEV_MATCH_DEVICE) { dev_result = &ccb.cdm.matches[i].result.device_result; if (dev_result->flags & DEV_RESULT_UNCONFIGURED || skip_bus == 1) skip_device = 1; else skip_device = 0; // /* Shall we skip non T_DIRECT devices ? */ // if (dev_result->inq_data.device != T_DIRECT) // skip_device = 1; changed = 1; } else if (ccb.cdm.matches[i].type == DEV_MATCH_PERIPH && (skip_device == 0 || show_all)) { /* One device may be populated as many peripherals (pass0 & da0 for example). * We are searching for best name */ periph_result = &ccb.cdm.matches[i].result.periph_result; /* Prefer non-"pass" names */ if (devname.empty() || strncmp(periph_result->periph_name, "pass", 4) != 0) { devname = strprintf("%s%s%d", _PATH_DEV, periph_result->periph_name, periph_result->unit_number); } changed = 0; }; if ((changed == 1 || show_all) && !devname.empty()) { names.push_back(devname); devname.erase(); changed = 0; }; } } while ((ccb.ccb_h.status == CAM_REQ_CMP) && (ccb.cdm.status == CAM_DEV_MATCH_MORE)); if (!devname.empty()) names.push_back(devname); free(ccb.cdm.matches); close(fd); return true; } // we are using ATA subsystem enumerator to found all ATA devices on system // despite of it's names // // If any errors occur, leave errno set as it was returned by the // system call, and return <0. // Return values: // -1: error // >=0: number of discovered devices int get_dev_names_ata(char*** names) { struct ata_ioc_devices devices; int fd=-1,maxchannel,serrno=-1,n=0; char **mp = NULL; *names=NULL; if ((fd = open(ATA_DEVICE, O_RDWR)) < 0) { if (errno == ENOENT) /* There are no ATA device on this computer */ return 0; serrno = errno; pout("%s control device can't be opened: %s\n", ATA_DEVICE, strerror(errno)); n = -1; goto end; }; if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0) { serrno = errno; pout("ioctl(IOCATAGMAXCHANNEL) on /dev/ata failed: %s\n", strerror(errno)); n = -1; goto end; }; // allocate space for up to MAX_NUM_DEV number of ATA devices mp = (char **)calloc(MAX_NUM_DEV, sizeof(char*)); if (mp == NULL) { serrno=errno; pout("Out of memory constructing scan device list (on line %d)\n", __LINE__); n = -1; goto end; }; for (devices.channel = 0; devices.channel < maxchannel && n < MAX_NUM_DEV; devices.channel++) { int j; if (ioctl(fd, IOCATADEVICES, &devices) < 0) { if (errno == ENXIO) continue; /* such channel not exist */ pout("ioctl(IOCATADEVICES) on %s channel %d failed: %s\n", ATA_DEVICE, devices.channel, strerror(errno)); n = -1; goto end; }; for (j=0;j<=1 && n<MAX_NUM_DEV;j++) { if (devices.name[j][0] != '\0') { asprintf(mp+n, "%s%s", _PATH_DEV, devices.name[j]); if (mp[n] == NULL) { pout("Out of memory constructing scan ATA device list (on line %d)\n", __LINE__); n = -1; goto end; }; bytes+=1+strlen(mp[n]); n++; }; }; }; mp = (char **)reallocf(mp,n*(sizeof (char*))); // shrink to correct size if (mp == NULL && n > 0 ) { // reallocf never fail for size=0, but may return NULL serrno=errno; pout("Out of memory constructing scan device list (on line %d)\n", __LINE__); n = -1; goto end; }; bytes += (n)*(sizeof(char*)); // and set allocated byte count end: if (fd>=0) close(fd); if (n <= 0) { free(mp); mp = NULL; } *names=mp; if (serrno>-1) errno=serrno; return n; } bool freebsd_smart_interface::scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern /*= 0*/) { if (pattern) { set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); return false; } // Make namelists char * * atanames = 0; int numata = 0; if (!type || !strcmp(type, "ata")) { numata = get_dev_names_ata(&atanames); if (numata < 0) { set_err(ENOMEM); return false; } } std::vector<std::string> scsinames; if (!type || !strcmp(type, "scsi")) { // do not export duplicated names if (!get_dev_names_cam(scsinames, false)) { set_err(errno); return false; } } // Add to devlist int i; if (type==NULL) type=""; for (i = 0; i < numata; i++) { ata_device * atadev = get_ata_device(atanames[i], type); if (atadev) devlist.push_back(atadev); free(atanames[i]); } if(numata) free(atanames); for (i = 0; i < (int)scsinames.size(); i++) { if(!*type) { // try USB autodetection if no type specified smart_device * smartdev = autodetect_smart_device(scsinames[i].c_str()); if(smartdev) devlist.push_back(smartdev); } else { scsi_device * scsidev = get_scsi_device(scsinames[i].c_str(), type); if (scsidev) devlist.push_back(scsidev); } } return true; } #if (FREEBSDVER < 800000) // without this build fail on FreeBSD 8 static char done[USB_MAX_DEVICES]; static int usbdevinfo(int f, int a, int rec, int busno, unsigned short & vendor_id, unsigned short & product_id, unsigned short & version) { struct usb_device_info di; int e, p, i; char devname[256]; snprintf(devname, sizeof(devname),"umass%d",busno); di.udi_addr = a; e = ioctl(f, USB_DEVICEINFO, &di); if (e) { if (errno != ENXIO) printf("addr %d: I/O error\n", a); return 0; } done[a] = 1; // list devices for (i = 0; i < USB_MAX_DEVNAMES; i++) { if (di.udi_devnames[i][0]) { if(strcmp(di.udi_devnames[i],devname)==0) { // device found! vendor_id = di.udi_vendorNo; product_id = di.udi_productNo; version = di.udi_releaseNo; return 1; // FIXME } } } if (!rec) return 0; for (p = 0; p < di.udi_nports; p++) { int s = di.udi_ports[p]; if (s >= USB_MAX_DEVICES) { continue; } if (s == 0) printf("addr 0 should never happen!\n"); else { if(usbdevinfo(f, s, 1, busno, vendor_id, product_id, version)) return 1; } } return 0; } #endif static int usbdevlist(int busno,unsigned short & vendor_id, unsigned short & product_id, unsigned short & version) { #if (FREEBSDVER >= 800000) // libusb2 interface struct libusb20_device *pdev = NULL; struct libusb20_backend *pbe; uint32_t matches = 0; char buf[128]; // do not change! char devname[128]; uint8_t n; struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; pbe = libusb20_be_alloc_default(); while ((pdev = libusb20_be_device_foreach(pbe, pdev))) { matches++; if (libusb20_dev_open(pdev, 0)) { warnx("libusb20_dev_open: could not open device"); return 0; } pdesc=libusb20_dev_get_device_desc(pdev); snprintf(devname, sizeof(devname),"umass%d:",busno); for (n = 0; n != 255; n++) { if (libusb20_dev_get_iface_desc(pdev, n, buf, sizeof(buf))) break; if (buf[0] == 0) continue; if(strncmp(buf,devname,strlen(devname))==0){ // found! vendor_id = pdesc->idVendor; product_id = pdesc->idProduct; version = pdesc->bcdDevice; libusb20_dev_close(pdev); libusb20_be_free(pbe); return 1; } } libusb20_dev_close(pdev); } if (matches == 0) { printf("No device match or lack of permissions.\n"); } libusb20_be_free(pbe); return false; #else // freebsd < 8.0 USB stack, ioctl interface int i, f, a, rc; char buf[50]; int ncont; for (ncont = 0, i = 0; i < 10; i++) { snprintf(buf, sizeof(buf), "%s%d", USBDEV, i); f = open(buf, O_RDONLY); if (f >= 0) { memset(done, 0, sizeof done); for (a = 1; a < USB_MAX_DEVICES; a++) { if (!done[a]) { rc = usbdevinfo(f, a, 1, busno,vendor_id, product_id, version); if(rc) return 1; } } close(f); } else { if (errno == ENOENT || errno == ENXIO) continue; warn("%s", buf); } ncont++; } return 0; #endif } smart_device * freebsd_smart_interface::autodetect_smart_device(const char * name) { unsigned short vendor_id = 0, product_id = 0, version = 0; struct cam_device *cam_dev; union ccb ccb; int bus=-1; int i,c; int len; const char * test_name = name; // if dev_name null, or string length zero if (!name || !(len = strlen(name))) return 0; // Dereference symlinks struct stat st; std::string pathbuf; if (!lstat(name, &st) && S_ISLNK(st.st_mode)) { char * p = realpath(name, (char *)0); if (p) { pathbuf = p; free(p); test_name = pathbuf.c_str(); } } // check ATA bus char * * atanames = 0; int numata = 0; numata = get_dev_names_ata(&atanames); if (numata > 0) { // check ATA/ATAPI devices for (i = 0; i < numata; i++) { if(!strcmp(atanames[i],test_name)) { for (c = i; c < numata; c++) free(atanames[c]); free(atanames); return new freebsd_ata_device(this, test_name, ""); } else free(atanames[i]); } if(numata) free(atanames); } else { if (numata < 0) pout("Unable to get ATA device list\n"); } // check CAM std::vector<std::string> scsinames; if (!get_dev_names_cam(scsinames, true)) pout("Unable to get CAM device list\n"); else if (!scsinames.empty()) { // check all devices on CAM bus for (i = 0; i < (int)scsinames.size(); i++) { if(strcmp(scsinames[i].c_str(), test_name)==0) { // our disk device is CAM if(strncmp(scsinames[i].c_str(), "/dev/pmp", strlen("/dev/pmp")) == 0) { pout("Skipping port multiplier [%s]\n", scsinames[i].c_str()); set_err(EINVAL); return 0; } if ((cam_dev = cam_open_device(test_name, O_RDWR)) == NULL) { // open failure set_err(errno); return 0; } // zero the payload bzero(&(&ccb.ccb_h)[1], PATHINQ_SETTINGS_SIZE); ccb.ccb_h.func_code = XPT_PATH_INQ; // send PATH_INQ to the device if (ioctl(cam_dev->fd, CAMIOCOMMAND, &ccb) == -1) { warn("Get Transfer Settings CCB failed\n" "%s", strerror(errno)); cam_close_device(cam_dev); return 0; } // now check if we are working with USB device, see umass.c if(strcmp(ccb.cpi.dev_name,"umass-sim") == 0) { // USB device found usbdevlist(bus,vendor_id, product_id, version); int bus=ccb.cpi.unit_number; // unit_number will match umass number cam_close_device(cam_dev); if(usbdevlist(bus,vendor_id, product_id, version)){ const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version); if (usbtype) return get_sat_device(usbtype, new freebsd_scsi_device(this, test_name, "")); } return 0; } #if FREEBSDVER > 800100 // check if we have ATA device connected to CAM (ada) if(ccb.cpi.protocol == PROTO_ATA){ cam_close_device(cam_dev); return new freebsd_atacam_device(this, test_name, ""); } #endif // close cam device, we don`t need it anymore cam_close_device(cam_dev); // handle as usual scsi return new freebsd_scsi_device(this, test_name, ""); } } } // device is LSI raid supported by mfi driver if(!strncmp("/dev/mfid", test_name, strlen("/dev/mfid"))) set_err(EINVAL, "To monitor disks on LSI RAID load mfip.ko module and run 'smartctl -a /dev/passX' to show SMART information"); // device type unknown return 0; } smart_device * freebsd_smart_interface::get_custom_smart_device(const char * name, const char * type) { // 3Ware ? static const char * fbsd_dev_twe_ctrl = "/dev/twe"; static const char * fbsd_dev_twa_ctrl = "/dev/twa"; static const char * fbsd_dev_tws_ctrl = "/dev/tws"; int disknum = -1, n1 = -1, n2 = -1, contr = -1; if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { if (n2 != (int)strlen(type)) { set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer"); return 0; } if (!(0 <= disknum && disknum <= 127)) { set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum); return 0; } // guess 3ware device type based on device name if (str_starts_with(name, fbsd_dev_twa_ctrl) || str_starts_with(name, fbsd_dev_tws_ctrl) ) { contr=CONTROLLER_3WARE_9000_CHAR; } if (!strncmp(fbsd_dev_twe_ctrl, name, strlen(fbsd_dev_twe_ctrl))){ contr=CONTROLLER_3WARE_678K_CHAR; } if(contr == -1){ set_err(EINVAL, "3ware controller type unknown, use %sX, %sX or %sX devices", fbsd_dev_twe_ctrl, fbsd_dev_twa_ctrl, fbsd_dev_tws_ctrl); return 0; } return new freebsd_escalade_device(this, name, contr, disknum); } // Highpoint ? int controller = -1, channel = -1; disknum = 1; n1 = n2 = -1; int n3 = -1; if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) { int len = strlen(type); if (!(n2 == len || n3 == len)) { set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items"); return 0; } if (!(1 <= controller && controller <= 8)) { set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied"); return 0; } if (!(1 <= channel && channel <= 128)) { set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied"); return 0; } if (!(1 <= disknum && disknum <= 15)) { set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied"); return 0; } return new freebsd_highpoint_device(this, name, controller, channel, disknum); } // CCISS ? disknum = n1 = n2 = -1; if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { if (n2 != (int)strlen(type)) { set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer"); return 0; } if (!(0 <= disknum && disknum <= 127)) { set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum); return 0; } return get_sat_device("sat,auto", new freebsd_cciss_device(this, name, disknum)); } #if FREEBSDVER > 800100 // adaX devices ? if(!strcmp(type,"atacam")) return new freebsd_atacam_device(this, name, ""); #endif // Areca? disknum = n1 = n2 = -1; int encnum = 1; if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { if (!(1 <= disknum && disknum <= 128)) { set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); return 0; } if (!(1 <= encnum && encnum <= 8)) { set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); return 0; } return new freebsd_areca_ata_device(this, name, disknum, encnum); } return 0; } std::string freebsd_smart_interface::get_valid_custom_dev_types_str() { return "3ware,N, hpt,L/M/N, cciss,N, areca,N/E" #if FREEBSDVER > 800100 ", atacam" #endif ; } } // namespace ///////////////////////////////////////////////////////////////////////////// /// Initialize platform interface and register with smi() void smart_interface::init() { static os_freebsd::freebsd_smart_interface the_interface; smart_interface::set(&the_interface); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/COPYING��������������������������������������������������������������0000644�0000000�0000000�00000043254�11652065010�016120� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) <year> <name of author> 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 Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_linux.cpp���������������������������������������������������������0000644�0000000�0000000�00000277227�12165521246�017452� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_linux.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-11 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-11 Doug Gilbert <dgilbert@interlog.com> * Copyright (C) 2008-12 Hank Wu <hank@areca.com.tw> * Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net> * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008 Jordan Hargrave <jordan_hargrave@dell.com> * * Parts of this file are derived from code that was * * Written By: Adam Radford <linux@3ware.com> * Modifications By: Joel Jacobson <linux@3ware.com> * Arnaldo Carvalho de Melo <acme@conectiva.com.br> * Brad Strand <linux@3ware.com> * * Copyright (C) 1999-2003 3ware Inc. * * Kernel compatablity By: Andre Hedrick <andre@suse.com> * Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> * * Other ars of this file are derived from code that was * * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ // This file contains the linux-specific IOCTL parts of // smartmontools. It includes one interface routine for ATA devices, // one for SCSI devices, and one for ATA devices behind escalade // controllers. #include "config.h" #include <errno.h> #include <fcntl.h> #include <glob.h> #include <scsi/scsi.h> #include <scsi/scsi_ioctl.h> #include <scsi/sg.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/utsname.h> #include <unistd.h> #include <stddef.h> // for offsetof() #include <sys/uio.h> #include <sys/types.h> #include <dirent.h> #ifndef makedev // old versions of types.h do not include sysmacros.h #include <sys/sysmacros.h> #endif #ifdef WITH_SELINUX #include <selinux/selinux.h> #endif #include "int64.h" #include "atacmds.h" #include "os_linux.h" #include "scsicmds.h" #include "utility.h" #include "cciss.h" #include "megaraid.h" #include "dev_interface.h" #include "dev_ata_cmd_set.h" #include "dev_areca.h" #ifndef ENOTSUP #define ENOTSUP ENOSYS #endif #define ARGUSED(x) ((void)(x)) const char * os_linux_cpp_cvsid = "$Id: os_linux.cpp 3824 2013-07-05 10:40:38Z samm2 $" OS_LINUX_H_CVSID; extern unsigned char failuretest_permissive; namespace os_linux { // No need to publish anything, name provided for Doxygen ///////////////////////////////////////////////////////////////////////////// /// Shared open/close routines class linux_smart_device : virtual public /*implements*/ smart_device { public: explicit linux_smart_device(int flags, int retry_flags = -1) : smart_device(never_called), m_fd(-1), m_flags(flags), m_retry_flags(retry_flags) { } virtual ~linux_smart_device() throw(); virtual bool is_open() const; virtual bool open(); virtual bool close(); protected: /// Return filedesc for derived classes. int get_fd() const { return m_fd; } void set_fd(int fd) { m_fd = fd; } private: int m_fd; ///< filedesc, -1 if not open. int m_flags; ///< Flags for ::open() int m_retry_flags; ///< Flags to retry ::open(), -1 if no retry }; linux_smart_device::~linux_smart_device() throw() { if (m_fd >= 0) ::close(m_fd); } bool linux_smart_device::is_open() const { return (m_fd >= 0); } bool linux_smart_device::open() { m_fd = ::open(get_dev_name(), m_flags); if (m_fd < 0 && errno == EROFS && m_retry_flags != -1) // Retry m_fd = ::open(get_dev_name(), m_retry_flags); if (m_fd < 0) { if (errno == EBUSY && (m_flags & O_EXCL)) // device is locked return set_err(EBUSY, "The requested controller is used exclusively by another process!\n" "(e.g. smartctl or smartd)\n" "Please quit the impeding process or try again later..."); return set_err((errno==ENOENT || errno==ENOTDIR) ? ENODEV : errno); } if (m_fd >= 0) { // sets FD_CLOEXEC on the opened device file descriptor. The // descriptor is otherwise leaked to other applications (mail // sender) which may be considered a security risk and may result // in AVC messages on SELinux-enabled systems. if (-1 == fcntl(m_fd, F_SETFD, FD_CLOEXEC)) // TODO: Provide an error printing routine in class smart_interface pout("fcntl(set FD_CLOEXEC) failed, errno=%d [%s]\n", errno, strerror(errno)); } return true; } // equivalent to close(file descriptor) bool linux_smart_device::close() { int fd = m_fd; m_fd = -1; if (::close(fd) < 0) return set_err(errno); return true; } // examples for smartctl static const char smartctl_examples[] = "=================================================== SMARTCTL EXAMPLES =====\n\n" " smartctl --all /dev/hda (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n" " (Enables SMART on first disk)\n\n" " smartctl --test=long /dev/hda (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl --all --device=3ware,2 /dev/sda\n" " smartctl --all --device=3ware,2 /dev/twe0\n" " smartctl --all --device=3ware,2 /dev/twa0\n" " smartctl --all --device=3ware,2 /dev/twl0\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" " smartctl --all --device=hpt,1/1/3 /dev/sda\n" " (Prints all SMART info for the SATA disk attached to the 3rd PMPort\n" " of the 1st channel on the 1st HighPoint RAID controller)\n" " smartctl --all --device=areca,3/1 /dev/sg2\n" " (Prints all SMART info for 3rd ATA disk of the 1st enclosure\n" " on Areca RAID controller)\n" ; ///////////////////////////////////////////////////////////////////////////// /// Linux ATA support class linux_ata_device : public /*implements*/ ata_device_with_command_set, public /*extends*/ linux_smart_device { public: linux_ata_device(smart_interface * intf, const char * dev_name, const char * req_type); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); }; linux_ata_device::linux_ata_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "ata", req_type), linux_smart_device(O_RDONLY | O_NONBLOCK) { } // PURPOSE // This is an interface routine meant to isolate the OS dependent // parts of the code, and to provide a debugging interface. Each // different port and OS needs to provide it's own interface. This // is the linux one. // DETAILED DESCRIPTION OF ARGUMENTS // device: is the file descriptor provided by open() // command: defines the different operations. // select: additional input data if needed (which log, which type of // self-test). // data: location to write output data, if needed (512 bytes). // Note: not all commands use all arguments. // RETURN VALUES // -1 if the command failed // 0 if the command succeeded, // STATUS_CHECK routine: // -1 if the command failed // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" #define BUFFER_LENGTH (4+512) int linux_ata_device::ata_command_interface(smart_command_set command, int select, char * data) { unsigned char buff[BUFFER_LENGTH]; // positive: bytes to write to caller. negative: bytes to READ from // caller. zero: non-data command int copydata=0; const int HDIO_DRIVE_CMD_OFFSET = 4; // See struct hd_drive_cmd_hdr in hdreg.h. Before calling ioctl() // buff[0]: ATA COMMAND CODE REGISTER // buff[1]: ATA SECTOR NUMBER REGISTER == LBA LOW REGISTER // buff[2]: ATA FEATURES REGISTER // buff[3]: ATA SECTOR COUNT REGISTER // Note that on return: // buff[2] contains the ATA SECTOR COUNT REGISTER // clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes) memset(buff, 0, BUFFER_LENGTH); buff[0]=ATA_SMART_CMD; switch (command){ case CHECK_POWER_MODE: buff[0]=ATA_CHECK_POWER_MODE; copydata=1; break; case READ_VALUES: buff[2]=ATA_SMART_READ_VALUES; buff[3]=1; copydata=512; break; case READ_THRESHOLDS: buff[2]=ATA_SMART_READ_THRESHOLDS; buff[1]=buff[3]=1; copydata=512; break; case READ_LOG: buff[2]=ATA_SMART_READ_LOG_SECTOR; buff[1]=select; buff[3]=1; copydata=512; break; case WRITE_LOG: break; case IDENTIFY: buff[0]=ATA_IDENTIFY_DEVICE; buff[3]=1; copydata=512; break; case PIDENTIFY: buff[0]=ATA_IDENTIFY_PACKET_DEVICE; buff[3]=1; copydata=512; break; case ENABLE: buff[2]=ATA_SMART_ENABLE; buff[1]=1; break; case DISABLE: buff[2]=ATA_SMART_DISABLE; buff[1]=1; break; case STATUS: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. buff[2]=ATA_SMART_STATUS; break; case AUTO_OFFLINE: // NOTE: According to ATAPI 4 and UP, this command is obsolete // select == 241 for enable but no data transfer. Use TASK ioctl. buff[1]=ATA_SMART_AUTO_OFFLINE; buff[2]=select; break; case AUTOSAVE: // select == 248 for enable but no data transfer. Use TASK ioctl. buff[1]=ATA_SMART_AUTOSAVE; buff[2]=select; break; case IMMEDIATE_OFFLINE: buff[2]=ATA_SMART_IMMEDIATE_OFFLINE; buff[1]=select; break; case STATUS_CHECK: // This command uses HDIO_DRIVE_TASK and has different syntax than // the other commands. buff[1]=ATA_SMART_STATUS; break; default: pout("Unrecognized command %d in linux_ata_command_interface()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); errno=ENOSYS; return -1; } // This command uses the HDIO_DRIVE_TASKFILE ioctl(). This is the // only ioctl() that can be used to WRITE data to the disk. if (command==WRITE_LOG) { unsigned char task[sizeof(ide_task_request_t)+512]; ide_task_request_t *reqtask=(ide_task_request_t *) task; task_struct_t *taskfile=(task_struct_t *) reqtask->io_ports; int retval; memset(task, 0, sizeof(task)); taskfile->data = 0; taskfile->feature = ATA_SMART_WRITE_LOG_SECTOR; taskfile->sector_count = 1; taskfile->sector_number = select; taskfile->low_cylinder = 0x4f; taskfile->high_cylinder = 0xc2; taskfile->device_head = 0; taskfile->command = ATA_SMART_CMD; reqtask->data_phase = TASKFILE_OUT; reqtask->req_cmd = IDE_DRIVE_TASK_OUT; reqtask->out_size = 512; reqtask->in_size = 0; // copy user data into the task request structure memcpy(task+sizeof(ide_task_request_t), data, 512); if ((retval=ioctl(get_fd(), HDIO_DRIVE_TASKFILE, task))) { if (retval==-EINVAL) pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASKFILE_IO set\n"); return -1; } return 0; } // There are two different types of ioctls(). The HDIO_DRIVE_TASK // one is this: if (command==STATUS_CHECK || command==AUTOSAVE || command==AUTO_OFFLINE){ int retval; // NOT DOCUMENTED in /usr/src/linux/include/linux/hdreg.h. You // have to read the IDE driver source code. Sigh. // buff[0]: ATA COMMAND CODE REGISTER // buff[1]: ATA FEATURES REGISTER // buff[2]: ATA SECTOR_COUNT // buff[3]: ATA SECTOR NUMBER // buff[4]: ATA CYL LO REGISTER // buff[5]: ATA CYL HI REGISTER // buff[6]: ATA DEVICE HEAD unsigned const char normal_lo=0x4f, normal_hi=0xc2; unsigned const char failed_lo=0xf4, failed_hi=0x2c; buff[4]=normal_lo; buff[5]=normal_hi; if ((retval=ioctl(get_fd(), HDIO_DRIVE_TASK, buff))) { if (retval==-EINVAL) { pout("Error SMART Status command via HDIO_DRIVE_TASK failed"); pout("Rebuild older linux 2.2 kernels with HDIO_DRIVE_TASK support added\n"); } else syserror("Error SMART Status command failed"); return -1; } // Cyl low and Cyl high unchanged means "Good SMART status" if (buff[4]==normal_lo && buff[5]==normal_hi) return 0; // These values mean "Bad SMART status" if (buff[4]==failed_lo && buff[5]==failed_hi) return 1; // We haven't gotten output that makes sense; print out some debugging info syserror("Error SMART Status command failed"); pout("Please get assistance from " PACKAGE_HOMEPAGE "\n"); pout("Register values returned from SMART Status command are:\n"); pout("ST =0x%02x\n",(int)buff[0]); pout("ERR=0x%02x\n",(int)buff[1]); pout("NS =0x%02x\n",(int)buff[2]); pout("SC =0x%02x\n",(int)buff[3]); pout("CL =0x%02x\n",(int)buff[4]); pout("CH =0x%02x\n",(int)buff[5]); pout("SEL=0x%02x\n",(int)buff[6]); return -1; } #if 1 // Note to people doing ports to other OSes -- don't worry about // this block -- you can safely ignore it. I have put it here // because under linux when you do IDENTIFY DEVICE to a packet // device, it generates an ugly kernel syslog error message. This // is harmless but frightens users. So this block detects packet // devices and make IDENTIFY DEVICE fail "nicely" without a syslog // error message. // // If you read only the ATA specs, it appears as if a packet device // *might* respond to the IDENTIFY DEVICE command. This is // misleading - it's because around the time that SFF-8020 was // incorporated into the ATA-3/4 standard, the ATA authors were // sloppy. See SFF-8020 and you will see that ATAPI devices have // *always* had IDENTIFY PACKET DEVICE as a mandatory part of their // command set, and return 'Command Aborted' to IDENTIFY DEVICE. if (command==IDENTIFY || command==PIDENTIFY){ unsigned short deviceid[256]; // check the device identity, as seen when the system was booted // or the device was FIRST registered. This will not be current // if the user has subsequently changed some of the parameters. If // device is a packet device, swap the command interpretations. if (!ioctl(get_fd(), HDIO_GET_IDENTITY, deviceid) && (deviceid[0] & 0x8000)) buff[0]=(command==IDENTIFY)?ATA_IDENTIFY_PACKET_DEVICE:ATA_IDENTIFY_DEVICE; } #endif // We are now doing the HDIO_DRIVE_CMD type ioctl. if ((ioctl(get_fd(), HDIO_DRIVE_CMD, buff))) return -1; // CHECK POWER MODE command returns information in the Sector Count // register (buff[3]). Copy to return data buffer. if (command==CHECK_POWER_MODE) buff[HDIO_DRIVE_CMD_OFFSET]=buff[2]; // if the command returns data then copy it back if (copydata) memcpy(data, buff+HDIO_DRIVE_CMD_OFFSET, copydata); return 0; } // >>>>>> Start of general SCSI specific linux code /* Linux specific code. * Historically smartmontools (and smartsuite before it) used the * SCSI_IOCTL_SEND_COMMAND ioctl which is available to all linux device * nodes that use the SCSI subsystem. A better interface has been available * via the SCSI generic (sg) driver but this involves the extra step of * mapping disk devices (e.g. /dev/sda) to the corresponding sg device * (e.g. /dev/sg2). In the linux kernel 2.6 series most of the facilities of * the sg driver have become available via the SG_IO ioctl which is available * on all SCSI devices (on SCSI tape devices from lk 2.6.6). * So the strategy below is to find out if the SG_IO ioctl is available and * if so use it; failing that use the older SCSI_IOCTL_SEND_COMMAND ioctl. * Should work in 2.0, 2.2, 2.4 and 2.6 series linux kernels. */ #define MAX_DXFER_LEN 1024 /* can be increased if necessary */ #define SEND_IOCTL_RESP_SENSE_LEN 16 /* ioctl limitation */ #define SG_IO_RESP_SENSE_LEN 64 /* large enough see buffer */ #define LSCSI_DRIVER_MASK 0xf /* mask out "suggestions" */ #define LSCSI_DRIVER_SENSE 0x8 /* alternate CHECK CONDITION indication */ #define LSCSI_DID_ERROR 0x7 /* Need to work around aacraid driver quirk */ #define LSCSI_DRIVER_TIMEOUT 0x6 #define LSCSI_DID_TIME_OUT 0x3 #define LSCSI_DID_BUS_BUSY 0x2 #define LSCSI_DID_NO_CONNECT 0x1 #ifndef SCSI_IOCTL_SEND_COMMAND #define SCSI_IOCTL_SEND_COMMAND 1 #endif #define SG_IO_PRESENT_UNKNOWN 0 #define SG_IO_PRESENT_YES 1 #define SG_IO_PRESENT_NO 2 static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report, int unknown); static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report); static int sg_io_state = SG_IO_PRESENT_UNKNOWN; /* Preferred implementation for issuing SCSI commands in linux. This * function uses the SG_IO ioctl. Return 0 if command issued successfully * (various status values should still be checked). If the SCSI command * cannot be issued then a negative errno value is returned. */ static int sg_io_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report, int unknown) { #ifndef SG_IO ARGUSED(dev_fd); ARGUSED(iop); ARGUSED(report); return -ENOTTY; #else struct sg_io_hdr io_hdr; if (report > 0) { int k, j; const unsigned char * ucp = iop->cmnd; const char * np; char buff[256]; const int sz = (int)sizeof(buff); np = scsi_get_opcode_name(ucp[0]); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " "data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((const char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); pout("%s", buff); } memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = iop->cmnd_len; io_hdr.mx_sb_len = iop->max_sense_len; io_hdr.dxfer_len = iop->dxfer_len; io_hdr.dxferp = iop->dxferp; io_hdr.cmdp = iop->cmnd; io_hdr.sbp = iop->sensep; /* sg_io_hdr interface timeout has millisecond units. Timeout of 0 defaults to 60 seconds. */ io_hdr.timeout = ((0 == iop->timeout) ? 60 : iop->timeout) * 1000; switch (iop->dxfer_dir) { case DXFER_NONE: io_hdr.dxfer_direction = SG_DXFER_NONE; break; case DXFER_FROM_DEVICE: io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; break; case DXFER_TO_DEVICE: io_hdr.dxfer_direction = SG_DXFER_TO_DEV; break; default: pout("do_scsi_cmnd_io: bad dxfer_dir\n"); return -EINVAL; } iop->resp_sense_len = 0; iop->scsi_status = 0; iop->resid = 0; if (ioctl(dev_fd, SG_IO, &io_hdr) < 0) { if (report && (! unknown)) pout(" SG_IO ioctl failed, errno=%d [%s]\n", errno, strerror(errno)); return -errno; } iop->resid = io_hdr.resid; iop->scsi_status = io_hdr.status; if (report > 0) { pout(" scsi_status=0x%x, host_status=0x%x, driver_status=0x%x\n" " info=0x%x duration=%d milliseconds resid=%d\n", io_hdr.status, io_hdr.host_status, io_hdr.driver_status, io_hdr.info, io_hdr.duration, io_hdr.resid); if (report > 1) { if (DXFER_FROM_DEVICE == iop->dxfer_dir) { int trunc, len; len = iop->dxfer_len - iop->resid; trunc = (len > 256) ? 1 : 0; if (len > 0) { pout(" Incoming data, len=%d%s:\n", len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((const char*)iop->dxferp, (trunc ? 256 : len), 1); } else pout(" Incoming data trimmed to nothing by resid\n"); } } } if (io_hdr.info & SG_INFO_CHECK) { /* error or warning */ int masked_driver_status = (LSCSI_DRIVER_MASK & io_hdr.driver_status); if (0 != io_hdr.host_status) { if ((LSCSI_DID_NO_CONNECT == io_hdr.host_status) || (LSCSI_DID_BUS_BUSY == io_hdr.host_status) || (LSCSI_DID_TIME_OUT == io_hdr.host_status)) return -ETIMEDOUT; else /* Check for DID_ERROR - workaround for aacraid driver quirk */ if (LSCSI_DID_ERROR != io_hdr.host_status) { return -EIO; /* catch all if not DID_ERR */ } } if (0 != masked_driver_status) { if (LSCSI_DRIVER_TIMEOUT == masked_driver_status) return -ETIMEDOUT; else if (LSCSI_DRIVER_SENSE != masked_driver_status) return -EIO; } if (LSCSI_DRIVER_SENSE == masked_driver_status) iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; iop->resp_sense_len = io_hdr.sb_len_wr; if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) && iop->sensep && (iop->resp_sense_len > 0)) { if (report > 1) { pout(" >>> Sense buffer, len=%d:\n", (int)iop->resp_sense_len); dStrHex((const char *)iop->sensep, iop->resp_sense_len , 1); } } if (report) { if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) { if ((iop->sensep[0] & 0x7f) > 0x71) pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[1] & 0xf, iop->sensep[2], iop->sensep[3]); else pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[2] & 0xf, iop->sensep[12], iop->sensep[13]); } else pout(" status=0x%x\n", iop->scsi_status); } } return 0; #endif } struct linux_ioctl_send_command { int inbufsize; int outbufsize; UINT8 buff[MAX_DXFER_LEN + 16]; }; /* The Linux SCSI_IOCTL_SEND_COMMAND ioctl is primitive and it doesn't * support: CDB length (guesses it from opcode), resid and timeout. * Patches in Linux 2.4.21 and 2.5.70 to extend SEND DIAGNOSTIC timeout * to 2 hours in order to allow long foreground extended self tests. */ static int sisc_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report) { struct linux_ioctl_send_command wrk; int status, buff_offset; size_t len; memcpy(wrk.buff, iop->cmnd, iop->cmnd_len); buff_offset = iop->cmnd_len; if (report > 0) { int k, j; const unsigned char * ucp = iop->cmnd; const char * np; char buff[256]; const int sz = (int)sizeof(buff); np = scsi_get_opcode_name(ucp[0]); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " "data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((const char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); pout("%s", buff); } switch (iop->dxfer_dir) { case DXFER_NONE: wrk.inbufsize = 0; wrk.outbufsize = 0; break; case DXFER_FROM_DEVICE: wrk.inbufsize = 0; if (iop->dxfer_len > MAX_DXFER_LEN) return -EINVAL; wrk.outbufsize = iop->dxfer_len; break; case DXFER_TO_DEVICE: if (iop->dxfer_len > MAX_DXFER_LEN) return -EINVAL; memcpy(wrk.buff + buff_offset, iop->dxferp, iop->dxfer_len); wrk.inbufsize = iop->dxfer_len; wrk.outbufsize = 0; break; default: pout("do_scsi_cmnd_io: bad dxfer_dir\n"); return -EINVAL; } iop->resp_sense_len = 0; iop->scsi_status = 0; iop->resid = 0; status = ioctl(dev_fd, SCSI_IOCTL_SEND_COMMAND, &wrk); if (-1 == status) { if (report) pout(" SCSI_IOCTL_SEND_COMMAND ioctl failed, errno=%d [%s]\n", errno, strerror(errno)); return -errno; } if (0 == status) { if (report > 0) pout(" status=0\n"); if (DXFER_FROM_DEVICE == iop->dxfer_dir) { memcpy(iop->dxferp, wrk.buff, iop->dxfer_len); if (report > 1) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((const char*)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } } return 0; } iop->scsi_status = status & 0x7e; /* bits 0 and 7 used to be for vendors */ if (LSCSI_DRIVER_SENSE == ((status >> 24) & 0xf)) iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; len = (SEND_IOCTL_RESP_SENSE_LEN < iop->max_sense_len) ? SEND_IOCTL_RESP_SENSE_LEN : iop->max_sense_len; if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) && iop->sensep && (len > 0)) { memcpy(iop->sensep, wrk.buff, len); iop->resp_sense_len = len; if (report > 1) { pout(" >>> Sense buffer, len=%d:\n", (int)len); dStrHex((const char *)wrk.buff, len , 1); } } if (report) { if (SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) { pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", status & 0xff, wrk.buff[2] & 0xf, wrk.buff[12], wrk.buff[13]); } else pout(" status=0x%x\n", status); } if (iop->scsi_status > 0) return 0; else { if (report > 0) pout(" ioctl status=0x%x but scsi status=0, fail with EIO\n", status); return -EIO; /* give up, assume no device there */ } } /* SCSI command transmission interface function, linux version. * Returns 0 if SCSI command successfully launched and response * received. Even when 0 is returned the caller should check * scsi_cmnd_io::scsi_status for SCSI defined errors and warnings * (e.g. CHECK CONDITION). If the SCSI command could not be issued * (e.g. device not present or timeout) or some other problem * (e.g. timeout) then returns a negative errno value */ static int do_normal_scsi_cmnd_io(int dev_fd, struct scsi_cmnd_io * iop, int report) { int res; /* implementation relies on static sg_io_state variable. If not * previously set tries the SG_IO ioctl. If that succeeds assume * that SG_IO ioctl functional. If it fails with an errno value * other than ENODEV (no device) or permission then assume * SCSI_IOCTL_SEND_COMMAND is the only option. */ switch (sg_io_state) { case SG_IO_PRESENT_UNKNOWN: /* ignore report argument */ if (0 == (res = sg_io_cmnd_io(dev_fd, iop, report, 1))) { sg_io_state = SG_IO_PRESENT_YES; return 0; } else if ((-ENODEV == res) || (-EACCES == res) || (-EPERM == res)) return res; /* wait until we see a device */ sg_io_state = SG_IO_PRESENT_NO; /* drop through by design */ case SG_IO_PRESENT_NO: return sisc_cmnd_io(dev_fd, iop, report); case SG_IO_PRESENT_YES: return sg_io_cmnd_io(dev_fd, iop, report, 0); default: pout(">>>> do_scsi_cmnd_io: bad sg_io_state=%d\n", sg_io_state); sg_io_state = SG_IO_PRESENT_UNKNOWN; return -EIO; /* report error and reset state */ } } // >>>>>> End of general SCSI specific linux code ///////////////////////////////////////////////////////////////////////////// /// Standard SCSI support class linux_scsi_device : public /*implements*/ scsi_device, public /*extends*/ linux_smart_device { public: linux_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type, bool scanning = false); virtual smart_device * autodetect_open(); virtual bool scsi_pass_through(scsi_cmnd_io * iop); private: bool m_scanning; ///< true if created within scan_smart_devices }; linux_scsi_device::linux_scsi_device(smart_interface * intf, const char * dev_name, const char * req_type, bool scanning /*= false*/) : smart_device(intf, dev_name, "scsi", req_type), // If opened with O_RDWR, a SATA disk in standby mode // may spin-up after device close(). linux_smart_device(O_RDONLY | O_NONBLOCK), m_scanning(scanning) { } bool linux_scsi_device::scsi_pass_through(scsi_cmnd_io * iop) { int status = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); if (status < 0) return set_err(-status); return true; } ///////////////////////////////////////////////////////////////////////////// /// LSI MegaRAID support class linux_megaraid_device : public /* implements */ scsi_device, public /* extends */ linux_smart_device { public: linux_megaraid_device(smart_interface *intf, const char *name, unsigned int bus, unsigned int tgt); virtual ~linux_megaraid_device() throw(); virtual smart_device * autodetect_open(); virtual bool open(); virtual bool close(); virtual bool scsi_pass_through(scsi_cmnd_io *iop); private: unsigned int m_disknum; unsigned int m_busnum; unsigned int m_hba; int m_fd; bool (linux_megaraid_device::*pt_cmd)(int cdblen, void *cdb, int dataLen, void *data, int senseLen, void *sense, int report, int direction); bool megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data, int senseLen, void *sense, int report, int direction); bool megadev_cmd(int cdbLen, void *cdb, int dataLen, void *data, int senseLen, void *sense, int report, int direction); }; linux_megaraid_device::linux_megaraid_device(smart_interface *intf, const char *dev_name, unsigned int bus, unsigned int tgt) : smart_device(intf, dev_name, "megaraid", "megaraid"), linux_smart_device(O_RDWR | O_NONBLOCK), m_disknum(tgt), m_busnum(bus), m_hba(0), m_fd(-1), pt_cmd(0) { set_info().info_name = strprintf("%s [megaraid_disk_%02d]", dev_name, m_disknum); set_info().dev_type = strprintf("megaraid,%d", tgt); } linux_megaraid_device::~linux_megaraid_device() throw() { if (m_fd >= 0) ::close(m_fd); } smart_device * linux_megaraid_device::autodetect_open() { int report = scsi_debugmode; // Open device if (!open()) return this; // The code below is based on smartd.cpp:SCSIFilterKnown() if (strcmp(get_req_type(), "megaraid")) return this; // Get INQUIRY unsigned char req_buff[64] = {0, }; int req_len = 36; if (scsiStdInquiry(this, req_buff, req_len)) { close(); set_err(EIO, "INQUIRY failed"); return this; } int avail_len = req_buff[4] + 5; int len = (avail_len < req_len ? avail_len : req_len); if (len < 36) return this; if (report) pout("Got MegaRAID inquiry.. %s\n", req_buff+8); // Use INQUIRY to detect type { // SAT? ata_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); if (newdev) // NOTE: 'this' is now owned by '*newdev' return newdev; } // Nothing special found return this; } bool linux_megaraid_device::open() { char line[128]; int mjr; int report = scsi_debugmode; if(sscanf(get_dev_name(),"/dev/bus/%d", &m_hba) == 0) { if (!linux_smart_device::open()) return false; /* Get device HBA */ struct sg_scsi_id sgid; if (ioctl(get_fd(), SG_GET_SCSI_ID, &sgid) == 0) { m_hba = sgid.host_no; } else if (ioctl(get_fd(), SCSI_IOCTL_GET_BUS_NUMBER, &m_hba) != 0) { int err = errno; linux_smart_device::close(); return set_err(err, "can't get bus number"); } // we dont need this device anymore linux_smart_device::close(); } /* Perform mknod of device ioctl node */ FILE * fp = fopen("/proc/devices", "r"); while (fgets(line, sizeof(line), fp) != NULL) { int n1 = 0; if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) { n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0)); if(report > 0) pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno); if (n1 >= 0 || errno == EEXIST) break; } else if (sscanf(line, "%d megadev%n", &mjr, &n1) == 1 && n1 == 11) { n1=mknod("/dev/megadev0", S_IFCHR, makedev(mjr, 0)); if(report > 0) pout("Creating /dev/megadev0 = %d\n", n1 >= 0 ? 0 : errno); if (n1 >= 0 || errno == EEXIST) break; } } fclose(fp); /* Open Device IOCTL node */ if ((m_fd = ::open("/dev/megaraid_sas_ioctl_node", O_RDWR)) >= 0) { pt_cmd = &linux_megaraid_device::megasas_cmd; } else if ((m_fd = ::open("/dev/megadev0", O_RDWR)) >= 0) { pt_cmd = &linux_megaraid_device::megadev_cmd; } else { int err = errno; linux_smart_device::close(); return set_err(err, "cannot open /dev/megaraid_sas_ioctl_node or /dev/megadev0"); } set_fd(m_fd); return true; } bool linux_megaraid_device::close() { if (m_fd >= 0) ::close(m_fd); m_fd = -1; m_hba = 0; pt_cmd = 0; set_fd(m_fd); return true; } bool linux_megaraid_device::scsi_pass_through(scsi_cmnd_io *iop) { int report = scsi_debugmode; if (report > 0) { int k, j; const unsigned char * ucp = iop->cmnd; const char * np; char buff[256]; const int sz = (int)sizeof(buff); np = scsi_get_opcode_name(ucp[0]); j = snprintf(buff, sz, " [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "%02x ", ucp[k]); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n Outgoing " "data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((const char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } else j += snprintf(&buff[j], (sz > j ? (sz - j) : 0), "]\n"); pout("%s", buff); } // Controller rejects Test Unit Ready if (iop->cmnd[0] == 0x00) return true; if (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 || iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16) { // Controller does not return ATA output registers in SAT sense data if (iop->cmnd[2] & (1 << 5)) // chk_cond return set_err(ENOSYS, "ATA return descriptor not supported by controller firmware"); } // SMART WRITE LOG SECTOR causing media errors if ((iop->cmnd[0] == SAT_ATA_PASSTHROUGH_16 // SAT16 WRITE LOG && iop->cmnd[14] == ATA_SMART_CMD && iop->cmnd[3]==0 && iop->cmnd[4] == ATA_SMART_WRITE_LOG_SECTOR) || (iop->cmnd[0] == SAT_ATA_PASSTHROUGH_12 // SAT12 WRITE LOG && iop->cmnd[9] == ATA_SMART_CMD && iop->cmnd[3] == ATA_SMART_WRITE_LOG_SECTOR)) { if(!failuretest_permissive) return set_err(ENOSYS, "SMART WRITE LOG SECTOR may cause problems, try with -T permissive to force"); } if (pt_cmd == NULL) return false; return (this->*pt_cmd)(iop->cmnd_len, iop->cmnd, iop->dxfer_len, iop->dxferp, iop->max_sense_len, iop->sensep, report, iop->dxfer_dir); } /* Issue passthrough scsi command to PERC5/6 controllers */ bool linux_megaraid_device::megasas_cmd(int cdbLen, void *cdb, int dataLen, void *data, int /*senseLen*/, void * /*sense*/, int /*report*/, int dxfer_dir) { struct megasas_pthru_frame *pthru; struct megasas_iocpacket uio; int rc; memset(&uio, 0, sizeof(uio)); pthru = &uio.frame.pthru; pthru->cmd = MFI_CMD_PD_SCSI_IO; pthru->cmd_status = 0xFF; pthru->scsi_status = 0x0; pthru->target_id = m_disknum; pthru->lun = 0; pthru->cdb_len = cdbLen; pthru->timeout = 0; switch (dxfer_dir) { case DXFER_NONE: pthru->flags = MFI_FRAME_DIR_NONE; break; case DXFER_FROM_DEVICE: pthru->flags = MFI_FRAME_DIR_READ; break; case DXFER_TO_DEVICE: pthru->flags = MFI_FRAME_DIR_WRITE; break; default: pout("megasas_cmd: bad dxfer_dir\n"); return set_err(EINVAL, "megasas_cmd: bad dxfer_dir\n"); } if (dataLen > 0) { pthru->sge_count = 1; pthru->data_xfer_len = dataLen; pthru->sgl.sge32[0].phys_addr = (intptr_t)data; pthru->sgl.sge32[0].length = (uint32_t)dataLen; } memcpy(pthru->cdb, cdb, cdbLen); uio.host_no = m_hba; if (dataLen > 0) { uio.sge_count = 1; uio.sgl_off = offsetof(struct megasas_pthru_frame, sgl); uio.sgl[0].iov_base = data; uio.sgl[0].iov_len = dataLen; } rc = 0; errno = 0; rc = ioctl(m_fd, MEGASAS_IOC_FIRMWARE, &uio); if (pthru->cmd_status || rc != 0) { if (pthru->cmd_status == 12) { return set_err(EIO, "megasas_cmd: Device %d does not exist\n", m_disknum); } return set_err((errno ? errno : EIO), "megasas_cmd result: %d.%d = %d/%d", m_hba, m_disknum, errno, pthru->cmd_status); } return true; } /* Issue passthrough scsi commands to PERC2/3/4 controllers */ bool linux_megaraid_device::megadev_cmd(int cdbLen, void *cdb, int dataLen, void *data, int /*senseLen*/, void * /*sense*/, int /*report*/, int /* dir */) { struct uioctl_t uio; int rc; /* Don't issue to the controller */ if (m_disknum == 7) return false; memset(&uio, 0, sizeof(uio)); uio.inlen = dataLen; uio.outlen = dataLen; memset(data, 0, dataLen); uio.ui.fcs.opcode = 0x80; // M_RD_IOCTL_CMD uio.ui.fcs.adapno = MKADAP(m_hba); uio.data.pointer = (uint8_t *)data; uio.mbox.cmd = MEGA_MBOXCMD_PASSTHRU; uio.mbox.xferaddr = (intptr_t)&uio.pthru; uio.pthru.ars = 1; uio.pthru.timeout = 2; uio.pthru.channel = 0; uio.pthru.target = m_disknum; uio.pthru.cdblen = cdbLen; uio.pthru.reqsenselen = MAX_REQ_SENSE_LEN; uio.pthru.dataxferaddr = (intptr_t)data; uio.pthru.dataxferlen = dataLen; memcpy(uio.pthru.cdb, cdb, cdbLen); rc=ioctl(m_fd, MEGAIOCCMD, &uio); if (uio.pthru.scsistatus || rc != 0) { return set_err((errno ? errno : EIO), "megadev_cmd result: %d.%d = %d/%d", m_hba, m_disknum, errno, uio.pthru.scsistatus); } return true; } ///////////////////////////////////////////////////////////////////////////// /// CCISS RAID support #ifdef HAVE_LINUX_CCISS_IOCTL_H class linux_cciss_device : public /*implements*/ scsi_device, public /*extends*/ linux_smart_device { public: linux_cciss_device(smart_interface * intf, const char * name, unsigned char disknum); virtual bool scsi_pass_through(scsi_cmnd_io * iop); private: unsigned char m_disknum; ///< Disk number. }; linux_cciss_device::linux_cciss_device(smart_interface * intf, const char * dev_name, unsigned char disknum) : smart_device(intf, dev_name, "cciss", "cciss"), linux_smart_device(O_RDWR | O_NONBLOCK), m_disknum(disknum) { set_info().info_name = strprintf("%s [cciss_disk_%02d]", dev_name, disknum); } bool linux_cciss_device::scsi_pass_through(scsi_cmnd_io * iop) { int status = cciss_io_interface(get_fd(), m_disknum, iop, scsi_debugmode); if (status < 0) return set_err(-status); return true; } #endif // HAVE_LINUX_CCISS_IOCTL_H ///////////////////////////////////////////////////////////////////////////// /// AMCC/3ware RAID support class linux_escalade_device : public /*implements*/ ata_device, public /*extends*/ linux_smart_device { public: enum escalade_type_t { AMCC_3WARE_678K, AMCC_3WARE_678K_CHAR, AMCC_3WARE_9000_CHAR, AMCC_3WARE_9700_CHAR }; linux_escalade_device(smart_interface * intf, const char * dev_name, escalade_type_t escalade_type, int disknum); virtual bool open(); virtual bool ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out); private: escalade_type_t m_escalade_type; ///< Controller type int m_disknum; ///< Disk number. }; linux_escalade_device::linux_escalade_device(smart_interface * intf, const char * dev_name, escalade_type_t escalade_type, int disknum) : smart_device(intf, dev_name, "3ware", "3ware"), linux_smart_device(O_RDONLY | O_NONBLOCK), m_escalade_type(escalade_type), m_disknum(disknum) { set_info().info_name = strprintf("%s [3ware_disk_%02d]", dev_name, disknum); } /* This function will setup and fix device nodes for a 3ware controller. */ #define MAJOR_STRING_LENGTH 3 #define DEVICE_STRING_LENGTH 32 #define NODE_STRING_LENGTH 16 static int setup_3ware_nodes(const char *nodename, const char *driver_name) { int tw_major = 0; int index = 0; char majorstring[MAJOR_STRING_LENGTH+1]; char device_name[DEVICE_STRING_LENGTH+1]; char nodestring[NODE_STRING_LENGTH]; struct stat stat_buf; FILE *file; int retval = 0; #ifdef WITH_SELINUX security_context_t orig_context = NULL; security_context_t node_context = NULL; int selinux_enabled = is_selinux_enabled(); int selinux_enforced = security_getenforce(); #endif /* First try to open up /proc/devices */ if (!(file = fopen("/proc/devices", "r"))) { pout("Error opening /proc/devices to check/create 3ware device nodes\n"); syserror("fopen"); return 0; // don't fail here: user might not have /proc ! } /* Attempt to get device major number */ while (EOF != fscanf(file, "%3s %32s", majorstring, device_name)) { majorstring[MAJOR_STRING_LENGTH]='\0'; device_name[DEVICE_STRING_LENGTH]='\0'; if (!strncmp(device_name, nodename, DEVICE_STRING_LENGTH)) { tw_major = atoi(majorstring); break; } } fclose(file); /* See if we found a major device number */ if (!tw_major) { pout("No major number for /dev/%s listed in /proc/devices. Is the %s driver loaded?\n", nodename, driver_name); return 2; } #ifdef WITH_SELINUX /* Prepare a database of contexts for files in /dev * and save the current context */ if (selinux_enabled) { if (matchpathcon_init_prefix(NULL, "/dev") < 0) pout("Error initializing contexts database for /dev"); if (getfscreatecon(&orig_context) < 0) { pout("Error retrieving original SELinux fscreate context"); if (selinux_enforced) matchpathcon_fini(); return 6; } } #endif /* Now check if nodes are correct */ for (index=0; index<16; index++) { snprintf(nodestring, sizeof(nodestring), "/dev/%s%d", nodename, index); #ifdef WITH_SELINUX /* Get context of the node and set it as the default */ if (selinux_enabled) { if (matchpathcon(nodestring, S_IRUSR | S_IWUSR, &node_context) < 0) { pout("Could not retrieve context for %s", nodestring); if (selinux_enforced) { retval = 6; break; } } if (setfscreatecon(node_context) < 0) { pout ("Error setting default fscreate context"); if (selinux_enforced) { retval = 6; break; } } } #endif /* Try to stat the node */ if ((stat(nodestring, &stat_buf))) { pout("Node %s does not exist and must be created. Check the udev rules.\n", nodestring); /* Create a new node if it doesn't exist */ if (mknod(nodestring, S_IFCHR|0600, makedev(tw_major, index))) { pout("problem creating 3ware device nodes %s", nodestring); syserror("mknod"); retval = 3; break; } else { #ifdef WITH_SELINUX if (selinux_enabled && node_context) { freecon(node_context); node_context = NULL; } #endif continue; } } /* See if nodes major and minor numbers are correct */ if ((tw_major != (int)(major(stat_buf.st_rdev))) || (index != (int)(minor(stat_buf.st_rdev))) || (!S_ISCHR(stat_buf.st_mode))) { pout("Node %s has wrong major/minor number and must be created anew." " Check the udev rules.\n", nodestring); /* Delete the old node */ if (unlink(nodestring)) { pout("problem unlinking stale 3ware device node %s", nodestring); syserror("unlink"); retval = 4; break; } /* Make a new node */ if (mknod(nodestring, S_IFCHR|0600, makedev(tw_major, index))) { pout("problem creating 3ware device nodes %s", nodestring); syserror("mknod"); retval = 5; break; } } #ifdef WITH_SELINUX if (selinux_enabled && node_context) { freecon(node_context); node_context = NULL; } #endif } #ifdef WITH_SELINUX if (selinux_enabled) { if(setfscreatecon(orig_context) < 0) { pout("Error re-setting original fscreate context"); if (selinux_enforced) retval = 6; } if(orig_context) freecon(orig_context); if(node_context) freecon(node_context); matchpathcon_fini(); } #endif return retval; } bool linux_escalade_device::open() { if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR || m_escalade_type == AMCC_3WARE_678K_CHAR) { // the device nodes for these controllers are dynamically assigned, // so we need to check that they exist with the correct major // numbers and if not, create them const char * node = (m_escalade_type == AMCC_3WARE_9700_CHAR ? "twl" : m_escalade_type == AMCC_3WARE_9000_CHAR ? "twa" : "twe" ); const char * driver = (m_escalade_type == AMCC_3WARE_9700_CHAR ? "3w-sas" : m_escalade_type == AMCC_3WARE_9000_CHAR ? "3w-9xxx" : "3w-xxxx" ); if (setup_3ware_nodes(node, driver)) return set_err((errno ? errno : ENXIO), "setup_3ware_nodes(\"%s\", \"%s\") failed", node, driver); } // Continue with default open return linux_smart_device::open(); } // TODO: Function no longer useful //void printwarning(smart_command_set command); // PURPOSE // This is an interface routine meant to isolate the OS dependent // parts of the code, and to provide a debugging interface. Each // different port and OS needs to provide it's own interface. This // is the linux interface to the 3ware 3w-xxxx driver. It allows ATA // commands to be passed through the SCSI driver. // DETAILED DESCRIPTION OF ARGUMENTS // fd: is the file descriptor provided by open() // disknum is the disk number (0 to 15) in the RAID array // escalade_type indicates the type of controller type, and if scsi or char interface is used // command: defines the different operations. // select: additional input data if needed (which log, which type of // self-test). // data: location to write output data, if needed (512 bytes). // Note: not all commands use all arguments. // RETURN VALUES // -1 if the command failed // 0 if the command succeeded, // STATUS_CHECK routine: // -1 if the command failed // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" /* 512 is the max payload size: increase if needed */ #define BUFFER_LEN_678K ( sizeof(TW_Ioctl) ) // 1044 unpacked, 1041 packed #define BUFFER_LEN_678K_CHAR ( sizeof(TW_New_Ioctl)+512-1 ) // 1539 unpacked, 1536 packed #define BUFFER_LEN_9000 ( sizeof(TW_Ioctl_Buf_Apache)+512-1 ) // 2051 unpacked, 2048 packed #define TW_IOCTL_BUFFER_SIZE ( MAX(MAX(BUFFER_LEN_678K, BUFFER_LEN_9000), BUFFER_LEN_678K_CHAR) ) bool linux_escalade_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_ok(in, true, // data_out_support false, // TODO: multi_sector_support true) // ata_48bit_support ) return false; // Used by both the SCSI and char interfaces TW_Passthru *passthru=NULL; char ioctl_buffer[TW_IOCTL_BUFFER_SIZE]; // only used for SCSI device interface TW_Ioctl *tw_ioctl=NULL; TW_Output *tw_output=NULL; // only used for 6000/7000/8000 char device interface TW_New_Ioctl *tw_ioctl_char=NULL; // only used for 9000 character device interface TW_Ioctl_Buf_Apache *tw_ioctl_apache=NULL; memset(ioctl_buffer, 0, TW_IOCTL_BUFFER_SIZE); // TODO: Handle controller differences by different classes if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) { tw_ioctl_apache = (TW_Ioctl_Buf_Apache *)ioctl_buffer; tw_ioctl_apache->driver_command.control_code = TW_IOCTL_FIRMWARE_PASS_THROUGH; tw_ioctl_apache->driver_command.buffer_length = 512; /* payload size */ passthru = (TW_Passthru *)&(tw_ioctl_apache->firmware_command.command.oldcommand); } else if (m_escalade_type==AMCC_3WARE_678K_CHAR) { tw_ioctl_char = (TW_New_Ioctl *)ioctl_buffer; tw_ioctl_char->data_buffer_length = 512; passthru = (TW_Passthru *)&(tw_ioctl_char->firmware_command); } else if (m_escalade_type==AMCC_3WARE_678K) { tw_ioctl = (TW_Ioctl *)ioctl_buffer; tw_ioctl->cdb[0] = TW_IOCTL; tw_ioctl->opcode = TW_ATA_PASSTHRU; tw_ioctl->input_length = 512; // correct even for non-data commands tw_ioctl->output_length = 512; // correct even for non-data commands tw_output = (TW_Output *)tw_ioctl; passthru = (TW_Passthru *)&(tw_ioctl->input_data); } else { return set_err(ENOSYS, "Unrecognized escalade_type %d in linux_3ware_command_interface(disk %d)\n" "Please contact " PACKAGE_BUGREPORT "\n", (int)m_escalade_type, m_disknum); } // Same for (almost) all commands - but some reset below passthru->byte0.opcode = TW_OP_ATA_PASSTHRU; passthru->request_id = 0xFF; passthru->unit = m_disknum; passthru->status = 0; passthru->flags = 0x1; // Set registers { const ata_in_regs_48bit & r = in.in_regs; passthru->features = r.features_16; passthru->sector_count = r.sector_count_16; passthru->sector_num = r.lba_low_16; passthru->cylinder_lo = r.lba_mid_16; passthru->cylinder_hi = r.lba_high_16; passthru->drive_head = r.device; passthru->command = r.command; } // Is this a command that reads or returns 512 bytes? // passthru->param values are: // 0x0 - non data command without TFR write check, // 0x8 - non data command with TFR write check, // 0xD - data command that returns data to host from device // 0xF - data command that writes data from host to device // passthru->size values are 0x5 for non-data and 0x07 for data bool readdata = false; if (in.direction == ata_cmd_in::data_in) { readdata=true; passthru->byte0.sgloff = 0x5; passthru->size = 0x7; // TODO: Other value for multi-sector ? passthru->param = 0xD; // For 64-bit to work correctly, up the size of the command packet // in dwords by 1 to account for the 64-bit single sgl 'address' // field. Note that this doesn't agree with the typedefs but it's // right (agree with kernel driver behavior/typedefs). if ((m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) && sizeof(long) == 8) passthru->size++; } else if (in.direction == ata_cmd_in::no_data) { // Non data command -- but doesn't use large sector // count register values. passthru->byte0.sgloff = 0x0; passthru->size = 0x5; passthru->param = 0x8; passthru->sector_count = 0x0; } else if (in.direction == ata_cmd_in::data_out) { if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) memcpy(tw_ioctl_apache->data_buffer, in.buffer, in.size); else if (m_escalade_type == AMCC_3WARE_678K_CHAR) memcpy(tw_ioctl_char->data_buffer, in.buffer, in.size); else { // COMMAND NOT SUPPORTED VIA SCSI IOCTL INTERFACE // memcpy(tw_output->output_data, data, 512); // printwarning(command); // TODO: Parameter no longer valid return set_err(ENOTSUP, "DATA OUT not supported for this 3ware controller type"); } passthru->byte0.sgloff = 0x5; passthru->size = 0x7; // TODO: Other value for multi-sector ? passthru->param = 0xF; // PIO data write if ((m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) && sizeof(long) == 8) passthru->size++; } else return set_err(EINVAL); // Now send the command down through an ioctl() int ioctlreturn; if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) ioctlreturn=ioctl(get_fd(), TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache); else if (m_escalade_type==AMCC_3WARE_678K_CHAR) ioctlreturn=ioctl(get_fd(), TW_CMD_PACKET_WITH_DATA, tw_ioctl_char); else ioctlreturn=ioctl(get_fd(), SCSI_IOCTL_SEND_COMMAND, tw_ioctl); // Deal with the different error cases if (ioctlreturn) { if (AMCC_3WARE_678K==m_escalade_type && in.in_regs.command==ATA_SMART_CMD && ( in.in_regs.features == ATA_SMART_AUTO_OFFLINE || in.in_regs.features == ATA_SMART_AUTOSAVE ) && in.in_regs.lba_low) { // error here is probably a kernel driver whose version is too old // printwarning(command); // TODO: Parameter no longer valid return set_err(ENOTSUP, "Probably kernel driver too old"); } return set_err(EIO); } // The passthru structure is valid after return from an ioctl if: // - we are using the character interface OR // - we are using the SCSI interface and this is a NON-READ-DATA command // For SCSI interface, note that we set passthru to a different // value after ioctl(). if (AMCC_3WARE_678K==m_escalade_type) { if (readdata) passthru=NULL; else passthru=(TW_Passthru *)&(tw_output->output_data); } // See if the ATA command failed. Now that we have returned from // the ioctl() call, if passthru is valid, then: // - passthru->status contains the 3ware controller STATUS // - passthru->command contains the ATA STATUS register // - passthru->features contains the ATA ERROR register // // Check bits 0 (error bit) and 5 (device fault) of the ATA STATUS // If bit 0 (error bit) is set, then ATA ERROR register is valid. // While we *might* decode the ATA ERROR register, at the moment it // doesn't make much sense: we don't care in detail why the error // happened. if (passthru && (passthru->status || (passthru->command & 0x21))) { return set_err(EIO); } // If this is a read data command, copy data to output buffer if (readdata) { if (m_escalade_type == AMCC_3WARE_9700_CHAR || m_escalade_type == AMCC_3WARE_9000_CHAR) memcpy(in.buffer, tw_ioctl_apache->data_buffer, in.size); else if (m_escalade_type==AMCC_3WARE_678K_CHAR) memcpy(in.buffer, tw_ioctl_char->data_buffer, in.size); else memcpy(in.buffer, tw_output->output_data, in.size); } // Return register values if (passthru) { ata_out_regs_48bit & r = out.out_regs; r.error = passthru->features; r.sector_count_16 = passthru->sector_count; r.lba_low_16 = passthru->sector_num; r.lba_mid_16 = passthru->cylinder_lo; r.lba_high_16 = passthru->cylinder_hi; r.device = passthru->drive_head; r.status = passthru->command; } // look for nonexistent devices/ports if ( in.in_regs.command == ATA_IDENTIFY_DEVICE && !nonempty(in.buffer, in.size)) { return set_err(ENODEV, "No drive on port %d", m_disknum); } return true; } ///////////////////////////////////////////////////////////////////////////// /// Areca RAID support /////////////////////////////////////////////////////////////////// // SATA(ATA) device behind Areca RAID Controller class linux_areca_ata_device : public /*implements*/ areca_ata_device, public /*extends*/ linux_smart_device { public: linux_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); virtual smart_device * autodetect_open(); virtual bool arcmsr_lock(); virtual bool arcmsr_unlock(); virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); }; /////////////////////////////////////////////////////////////////// // SAS(SCSI) device behind Areca RAID Controller class linux_areca_scsi_device : public /*implements*/ areca_scsi_device, public /*extends*/ linux_smart_device { public: linux_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum = 1); virtual smart_device * autodetect_open(); virtual bool arcmsr_lock(); virtual bool arcmsr_unlock(); virtual int arcmsr_do_scsi_io(struct scsi_cmnd_io * iop); }; // Looks in /proc/scsi to suggest correct areca devices static int find_areca_in_proc() { const char* proc_format_string="host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\tonline\n"; // check data formwat FILE *fp=fopen("/proc/scsi/sg/device_hdr", "r"); if (!fp) { pout("Unable to open /proc/scsi/sg/device_hdr for reading\n"); return 1; } // get line, compare to format char linebuf[256]; linebuf[255]='\0'; char *out = fgets(linebuf, 256, fp); fclose(fp); if (!out) { pout("Unable to read contents of /proc/scsi/sg/device_hdr\n"); return 2; } if (strcmp(linebuf, proc_format_string)) { // wrong format! // Fix this by comparing only tokens not white space!! pout("Unexpected format %s in /proc/scsi/sg/device_hdr\n", proc_format_string); return 3; } // Format is understood, now search for correct device fp=fopen("/proc/scsi/sg/devices", "r"); if (!fp) return 1; int host, chan, id, lun, type, opens, qdepth, busy, online; int dev=-1; int found=0; // search all lines of /proc/scsi/sg/devices while (9 == fscanf(fp, "%d %d %d %d %d %d %d %d %d", &host, &chan, &id, &lun, &type, &opens, &qdepth, &busy, &online)) { dev++; if (id == 16 && type == 3) { // devices with id=16 and type=3 might be Areca controllers pout("Device /dev/sg%d appears to be an Areca controller.\n", dev); found++; } } fclose(fp); return 0; } // Areca RAID Controller(SATA Disk) linux_areca_ata_device::linux_areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK) { set_disknum(disknum); set_encnum(encnum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } smart_device * linux_areca_ata_device::autodetect_open() { int is_ata = 1; // autodetect device type is_ata = arcmsr_get_dev_type(); if(is_ata < 0) { set_err(EIO); return this; } if(is_ata == 1) { // SATA device return this; } // SAS device smart_device_auto_ptr newdev(new linux_areca_scsi_device(smi(), get_dev_name(), get_disknum(), get_encnum())); close(); delete this; newdev->open(); // TODO: Can possibly pass open fd return newdev.release(); } int linux_areca_ata_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) { int ioctlreturn = 0; if(!is_open()) { if(!open()){ find_areca_in_proc(); } } ioctlreturn = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); if ( ioctlreturn || iop->scsi_status ) { // errors found return -1; } return ioctlreturn; } bool linux_areca_ata_device::arcmsr_lock() { return true; } bool linux_areca_ata_device::arcmsr_unlock() { return true; } // Areca RAID Controller(SAS Device) linux_areca_scsi_device::linux_areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), linux_smart_device(O_RDWR | O_EXCL | O_NONBLOCK) { set_disknum(disknum); set_encnum(encnum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } smart_device * linux_areca_scsi_device::autodetect_open() { return this; } int linux_areca_scsi_device::arcmsr_do_scsi_io(struct scsi_cmnd_io * iop) { int ioctlreturn = 0; if(!is_open()) { if(!open()){ find_areca_in_proc(); } } ioctlreturn = do_normal_scsi_cmnd_io(get_fd(), iop, scsi_debugmode); if ( ioctlreturn || iop->scsi_status ) { // errors found return -1; } return ioctlreturn; } bool linux_areca_scsi_device::arcmsr_lock() { return true; } bool linux_areca_scsi_device::arcmsr_unlock() { return true; } ///////////////////////////////////////////////////////////////////////////// /// Marvell support class linux_marvell_device : public /*implements*/ ata_device_with_command_set, public /*extends*/ linux_smart_device { public: linux_marvell_device(smart_interface * intf, const char * dev_name, const char * req_type); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); }; linux_marvell_device::linux_marvell_device(smart_interface * intf, const char * dev_name, const char * req_type) : smart_device(intf, dev_name, "marvell", req_type), linux_smart_device(O_RDONLY | O_NONBLOCK) { } int linux_marvell_device::ata_command_interface(smart_command_set command, int select, char * data) { typedef struct { int inlen; int outlen; char cmd[540]; } mvsata_scsi_cmd; int copydata = 0; mvsata_scsi_cmd smart_command; unsigned char *buff = (unsigned char *)&smart_command.cmd[6]; // See struct hd_drive_cmd_hdr in hdreg.h // buff[0]: ATA COMMAND CODE REGISTER // buff[1]: ATA SECTOR NUMBER REGISTER // buff[2]: ATA FEATURES REGISTER // buff[3]: ATA SECTOR COUNT REGISTER // clear out buff. Large enough for HDIO_DRIVE_CMD (4+512 bytes) memset(&smart_command, 0, sizeof(smart_command)); smart_command.inlen = 540; smart_command.outlen = 540; smart_command.cmd[0] = 0xC; //Vendor-specific code smart_command.cmd[4] = 6; //command length buff[0] = ATA_SMART_CMD; switch (command){ case CHECK_POWER_MODE: buff[0]=ATA_CHECK_POWER_MODE; break; case READ_VALUES: buff[2]=ATA_SMART_READ_VALUES; copydata=buff[3]=1; break; case READ_THRESHOLDS: buff[2]=ATA_SMART_READ_THRESHOLDS; copydata=buff[1]=buff[3]=1; break; case READ_LOG: buff[2]=ATA_SMART_READ_LOG_SECTOR; buff[1]=select; copydata=buff[3]=1; break; case IDENTIFY: buff[0]=ATA_IDENTIFY_DEVICE; copydata=buff[3]=1; break; case PIDENTIFY: buff[0]=ATA_IDENTIFY_PACKET_DEVICE; copydata=buff[3]=1; break; case ENABLE: buff[2]=ATA_SMART_ENABLE; buff[1]=1; break; case DISABLE: buff[2]=ATA_SMART_DISABLE; buff[1]=1; break; case STATUS: case STATUS_CHECK: // this command only says if SMART is working. It could be // replaced with STATUS_CHECK below. buff[2] = ATA_SMART_STATUS; break; case AUTO_OFFLINE: buff[2]=ATA_SMART_AUTO_OFFLINE; buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case AUTOSAVE: buff[2]=ATA_SMART_AUTOSAVE; buff[3]=select; // YET NOTE - THIS IS A NON-DATA COMMAND!! break; case IMMEDIATE_OFFLINE: buff[2]=ATA_SMART_IMMEDIATE_OFFLINE; buff[1]=select; break; default: pout("Unrecognized command %d in mvsata_os_specific_handler()\n", command); EXIT(1); break; } // There are two different types of ioctls(). The HDIO_DRIVE_TASK // one is this: // We are now doing the HDIO_DRIVE_CMD type ioctl. if (ioctl(get_fd(), SCSI_IOCTL_SEND_COMMAND, (void *)&smart_command)) return -1; if (command==CHECK_POWER_MODE) { // LEON -- CHECK THIS PLEASE. THIS SHOULD BE THE SECTOR COUNT // REGISTER, AND IT MIGHT BE buff[2] NOT buff[3]. Bruce data[0]=buff[3]; return 0; } // Always succeed on a SMART status, as a disk that failed returned // buff[4]=0xF4, buff[5]=0x2C, i.e. "Bad SMART status" (see below). if (command == STATUS) return 0; //Data returned is starting from 0 offset if (command == STATUS_CHECK) { // Cyl low and Cyl high unchanged means "Good SMART status" if (buff[4] == 0x4F && buff[5] == 0xC2) return 0; // These values mean "Bad SMART status" if (buff[4] == 0xF4 && buff[5] == 0x2C) return 1; // We haven't gotten output that makes sense; print out some debugging info syserror("Error SMART Status command failed"); pout("Please get assistance from %s\n",PACKAGE_BUGREPORT); pout("Register values returned from SMART Status command are:\n"); pout("CMD =0x%02x\n",(int)buff[0]); pout("FR =0x%02x\n",(int)buff[1]); pout("NS =0x%02x\n",(int)buff[2]); pout("SC =0x%02x\n",(int)buff[3]); pout("CL =0x%02x\n",(int)buff[4]); pout("CH =0x%02x\n",(int)buff[5]); pout("SEL=0x%02x\n",(int)buff[6]); return -1; } if (copydata) memcpy(data, buff, 512); return 0; } ///////////////////////////////////////////////////////////////////////////// /// Highpoint RAID support class linux_highpoint_device : public /*implements*/ ata_device_with_command_set, public /*extends*/ linux_smart_device { public: linux_highpoint_device(smart_interface * intf, const char * dev_name, unsigned char controller, unsigned char channel, unsigned char port); protected: virtual int ata_command_interface(smart_command_set command, int select, char * data); private: unsigned char m_hpt_data[3]; ///< controller/channel/port }; linux_highpoint_device::linux_highpoint_device(smart_interface * intf, const char * dev_name, unsigned char controller, unsigned char channel, unsigned char port) : smart_device(intf, dev_name, "hpt", "hpt"), linux_smart_device(O_RDONLY | O_NONBLOCK) { m_hpt_data[0] = controller; m_hpt_data[1] = channel; m_hpt_data[2] = port; set_info().info_name = strprintf("%s [hpt_disk_%u/%u/%u]", dev_name, m_hpt_data[0], m_hpt_data[1], m_hpt_data[2]); } // this implementation is derived from ata_command_interface with a header // packing for highpoint linux driver ioctl interface // // ioctl(fd,HPTIO_CTL,buff) // ^^^^^^^^^ // // structure of hpt_buff // +----+----+----+----+--------------------.....---------------------+ // | 1 | 2 | 3 | 4 | 5 | // +----+----+----+----+--------------------.....---------------------+ // // 1: The target controller [ int ( 4 Bytes ) ] // 2: The channel of the target controllee [ int ( 4 Bytes ) ] // 3: HDIO_ ioctl call [ int ( 4 Bytes ) ] // available from ${LINUX_KERNEL_SOURCE}/Documentation/ioctl/hdio // 4: the pmport that disk attached, [ int ( 4 Bytes ) ] // if no pmport device, set to 1 or leave blank // 5: data [ void * ( var leangth ) ] // #define STRANGE_BUFFER_LENGTH (4+512*0xf8) int linux_highpoint_device::ata_command_interface(smart_command_set command, int select, char * data) { unsigned char hpt_buff[4*sizeof(int) + STRANGE_BUFFER_LENGTH]; unsigned int *hpt = (unsigned int *)hpt_buff; unsigned char *buff = &hpt_buff[4*sizeof(int)]; int copydata = 0; const int HDIO_DRIVE_CMD_OFFSET = 4; memset(hpt_buff, 0, 4*sizeof(int) + STRANGE_BUFFER_LENGTH); hpt[0] = m_hpt_data[0]; // controller id hpt[1] = m_hpt_data[1]; // channel number hpt[3] = m_hpt_data[2]; // pmport number buff[0]=ATA_SMART_CMD; switch (command){ case CHECK_POWER_MODE: buff[0]=ATA_CHECK_POWER_MODE; copydata=1; break; case READ_VALUES: buff[2]=ATA_SMART_READ_VALUES; buff[3]=1; copydata=512; break; case READ_THRESHOLDS: buff[2]=ATA_SMART_READ_THRESHOLDS; buff[1]=buff[3]=1; copydata=512; break; case READ_LOG: buff[2]=ATA_SMART_READ_LOG_SECTOR; buff[1]=select; buff[3]=1; copydata=512; break; case WRITE_LOG: break; case IDENTIFY: buff[0]=ATA_IDENTIFY_DEVICE; buff[3]=1; copydata=512; break; case PIDENTIFY: buff[0]=ATA_IDENTIFY_PACKET_DEVICE; buff[3]=1; copydata=512; break; case ENABLE: buff[2]=ATA_SMART_ENABLE; buff[1]=1; break; case DISABLE: buff[2]=ATA_SMART_DISABLE; buff[1]=1; break; case STATUS: buff[2]=ATA_SMART_STATUS; break; case AUTO_OFFLINE: buff[2]=ATA_SMART_AUTO_OFFLINE; buff[3]=select; break; case AUTOSAVE: buff[2]=ATA_SMART_AUTOSAVE; buff[3]=select; break; case IMMEDIATE_OFFLINE: buff[2]=ATA_SMART_IMMEDIATE_OFFLINE; buff[1]=select; break; case STATUS_CHECK: buff[1]=ATA_SMART_STATUS; break; default: pout("Unrecognized command %d in linux_highpoint_command_interface()\n" "Please contact " PACKAGE_BUGREPORT "\n", command); errno=ENOSYS; return -1; } if (command==WRITE_LOG) { unsigned char task[4*sizeof(int)+sizeof(ide_task_request_t)+512]; unsigned int *hpt_tf = (unsigned int *)task; ide_task_request_t *reqtask = (ide_task_request_t *)(&task[4*sizeof(int)]); task_struct_t *taskfile = (task_struct_t *)reqtask->io_ports; int retval; memset(task, 0, sizeof(task)); hpt_tf[0] = m_hpt_data[0]; // controller id hpt_tf[1] = m_hpt_data[1]; // channel number hpt_tf[3] = m_hpt_data[2]; // pmport number hpt_tf[2] = HDIO_DRIVE_TASKFILE; // real hd ioctl taskfile->data = 0; taskfile->feature = ATA_SMART_WRITE_LOG_SECTOR; taskfile->sector_count = 1; taskfile->sector_number = select; taskfile->low_cylinder = 0x4f; taskfile->high_cylinder = 0xc2; taskfile->device_head = 0; taskfile->command = ATA_SMART_CMD; reqtask->data_phase = TASKFILE_OUT; reqtask->req_cmd = IDE_DRIVE_TASK_OUT; reqtask->out_size = 512; reqtask->in_size = 0; memcpy(task+sizeof(ide_task_request_t)+4*sizeof(int), data, 512); if ((retval=ioctl(get_fd(), HPTIO_CTL, task))) { if (retval==-EINVAL) pout("Kernel lacks HDIO_DRIVE_TASKFILE support; compile kernel with CONFIG_IDE_TASKFILE_IO set\n"); return -1; } return 0; } if (command==STATUS_CHECK){ int retval; unsigned const char normal_lo=0x4f, normal_hi=0xc2; unsigned const char failed_lo=0xf4, failed_hi=0x2c; buff[4]=normal_lo; buff[5]=normal_hi; hpt[2] = HDIO_DRIVE_TASK; if ((retval=ioctl(get_fd(), HPTIO_CTL, hpt_buff))) { if (retval==-EINVAL) { pout("Error SMART Status command via HDIO_DRIVE_TASK failed"); pout("Rebuild older linux 2.2 kernels with HDIO_DRIVE_TASK support added\n"); } else syserror("Error SMART Status command failed"); return -1; } if (buff[4]==normal_lo && buff[5]==normal_hi) return 0; if (buff[4]==failed_lo && buff[5]==failed_hi) return 1; syserror("Error SMART Status command failed"); pout("Please get assistance from " PACKAGE_HOMEPAGE "\n"); pout("Register values returned from SMART Status command are:\n"); pout("CMD=0x%02x\n",(int)buff[0]); pout("FR =0x%02x\n",(int)buff[1]); pout("NS =0x%02x\n",(int)buff[2]); pout("SC =0x%02x\n",(int)buff[3]); pout("CL =0x%02x\n",(int)buff[4]); pout("CH =0x%02x\n",(int)buff[5]); pout("SEL=0x%02x\n",(int)buff[6]); return -1; } #if 1 if (command==IDENTIFY || command==PIDENTIFY) { unsigned char deviceid[4*sizeof(int)+512*sizeof(char)]; unsigned int *hpt_id = (unsigned int *)deviceid; hpt_id[0] = m_hpt_data[0]; // controller id hpt_id[1] = m_hpt_data[1]; // channel number hpt_id[3] = m_hpt_data[2]; // pmport number hpt_id[2] = HDIO_GET_IDENTITY; if (!ioctl(get_fd(), HPTIO_CTL, deviceid) && (deviceid[4*sizeof(int)] & 0x8000)) buff[0]=(command==IDENTIFY)?ATA_IDENTIFY_PACKET_DEVICE:ATA_IDENTIFY_DEVICE; } #endif hpt[2] = HDIO_DRIVE_CMD; if ((ioctl(get_fd(), HPTIO_CTL, hpt_buff))) return -1; if (command==CHECK_POWER_MODE) buff[HDIO_DRIVE_CMD_OFFSET]=buff[2]; if (copydata) memcpy(data, buff+HDIO_DRIVE_CMD_OFFSET, copydata); return 0; } #if 0 // TODO: Migrate from 'smart_command_set' to 'ata_in_regs' OR remove the function // Utility function for printing warnings void printwarning(smart_command_set command){ static int printed[4]={0,0,0,0}; const char* message= "can not be passed through the 3ware 3w-xxxx driver. This can be fixed by\n" "applying a simple 3w-xxxx driver patch that can be found here:\n" PACKAGE_HOMEPAGE "\n" "Alternatively, upgrade your 3w-xxxx driver to version 1.02.00.037 or greater.\n\n"; if (command==AUTO_OFFLINE && !printed[0]) { printed[0]=1; pout("The SMART AUTO-OFFLINE ENABLE command (smartmontools -o on option/Directive)\n%s", message); } else if (command==AUTOSAVE && !printed[1]) { printed[1]=1; pout("The SMART AUTOSAVE ENABLE command (smartmontools -S on option/Directive)\n%s", message); } else if (command==STATUS_CHECK && !printed[2]) { printed[2]=1; pout("The SMART RETURN STATUS return value (smartmontools -H option/Directive)\n%s", message); } else if (command==WRITE_LOG && !printed[3]) { printed[3]=1; pout("The SMART WRITE LOG command (smartmontools -t selective) only supported via char /dev/tw[ae] interface\n"); } return; } #endif ///////////////////////////////////////////////////////////////////////////// /// SCSI open with autodetection support smart_device * linux_scsi_device::autodetect_open() { // Open device if (!open()) return this; // No Autodetection if device type was specified by user bool sat_only = false; if (*get_req_type()) { // Detect SAT if device object was created by scan_smart_devices(). if (!(m_scanning && !strcmp(get_req_type(), "sat"))) return this; sat_only = true; } // The code below is based on smartd.cpp:SCSIFilterKnown() // Get INQUIRY unsigned char req_buff[64] = {0, }; int req_len = 36; if (scsiStdInquiry(this, req_buff, req_len)) { // Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices // watch this spot ... other devices could lock up here req_len = 64; if (scsiStdInquiry(this, req_buff, req_len)) { // device doesn't like INQUIRY commands close(); set_err(EIO, "INQUIRY failed"); return this; } } int avail_len = req_buff[4] + 5; int len = (avail_len < req_len ? avail_len : req_len); if (len < 36) { if (sat_only) { close(); set_err(EIO, "INQUIRY too short for SAT"); } return this; } // Use INQUIRY to detect type if (!sat_only) { // 3ware ? if (!memcmp(req_buff + 8, "3ware", 5) || !memcmp(req_buff + 8, "AMCC", 4)) { close(); set_err(EINVAL, "AMCC/3ware controller, please try adding '-d 3ware,N',\n" "you may need to replace %s with /dev/twlN, /dev/twaN or /dev/tweN", get_dev_name()); return this; } // DELL? if (!memcmp(req_buff + 8, "DELL PERC", 12) || !memcmp(req_buff + 8, "MegaRAID", 8) || !memcmp(req_buff + 16, "PERC H700", 9) || !memcmp(req_buff + 8, "LSI\0",4) ) { close(); set_err(EINVAL, "DELL or MegaRaid controller, please try adding '-d megaraid,N'"); return this; } // Marvell ? if (len >= 42 && !memcmp(req_buff + 36, "MVSATA", 6)) { //pout("Device %s: using '-d marvell' for ATA disk with Marvell driver\n", get_dev_name()); close(); smart_device_auto_ptr newdev( new linux_marvell_device(smi(), get_dev_name(), get_req_type()) ); newdev->open(); // TODO: Can possibly pass open fd delete this; return newdev.release(); } } // SAT or USB ? { smart_device * newdev = smi()->autodetect_sat_device(this, req_buff, len); if (newdev) // NOTE: 'this' is now owned by '*newdev' return newdev; } // Nothing special found if (sat_only) { close(); set_err(EIO, "Not a SAT device"); } return this; } ////////////////////////////////////////////////////////////////////// // USB bridge ID detection // Read USB ID from /sys file static bool read_id(const std::string & path, unsigned short & id) { FILE * f = fopen(path.c_str(), "r"); if (!f) return false; int n = -1; bool ok = (fscanf(f, "%hx%n", &id, &n) == 1 && n == 4); fclose(f); return ok; } // Get USB bridge ID for "sdX" static bool get_usb_id(const char * name, unsigned short & vendor_id, unsigned short & product_id, unsigned short & version) { // Only "sdX" supported if (!(!strncmp(name, "sd", 2) && !strchr(name, '/'))) return false; // Start search at dir referenced by symlink "/sys/block/sdX/device" // -> "/sys/devices/.../usb*/.../host*/target*/..." std::string dir = strprintf("/sys/block/%s/device", name); // Stop search at "/sys/devices" struct stat st; if (stat("/sys/devices", &st)) return false; ino_t stop_ino = st.st_ino; // Search in parent directories until "idVendor" is found, // fail if "/sys/devices" reached or too many iterations int cnt = 0; do { dir += "/.."; if (!(++cnt < 10 && !stat(dir.c_str(), &st) && st.st_ino != stop_ino)) return false; } while (access((dir + "/idVendor").c_str(), 0)); // Read IDs if (!( read_id(dir + "/idVendor", vendor_id) && read_id(dir + "/idProduct", product_id) && read_id(dir + "/bcdDevice", version) )) return false; if (scsi_debugmode > 1) pout("USB ID = 0x%04x:0x%04x (0x%03x)\n", vendor_id, product_id, version); return true; } ////////////////////////////////////////////////////////////////////// /// Linux interface class linux_smart_interface : public /*implements*/ smart_interface { public: virtual std::string get_os_version_str(); virtual std::string get_app_examples(const char * appname); virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern = 0); protected: virtual ata_device * get_ata_device(const char * name, const char * type); virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); virtual smart_device * get_custom_smart_device(const char * name, const char * type); virtual std::string get_valid_custom_dev_types_str(); private: bool get_dev_list(smart_device_list & devlist, const char * pattern, bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect); bool get_dev_megasas(smart_device_list & devlist); smart_device * missing_option(const char * opt); int megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf, size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp); int megasas_pd_add_list(int bus_no, smart_device_list & devlist); }; std::string linux_smart_interface::get_os_version_str() { struct utsname u; if (!uname(&u)) return strprintf("%s-linux-%s", u.machine, u.release); else return SMARTMONTOOLS_BUILD_HOST; } std::string linux_smart_interface::get_app_examples(const char * appname) { if (!strcmp(appname, "smartctl")) return smartctl_examples; return ""; } // we are going to take advantage of the fact that Linux's devfs will only // have device entries for devices that exist. So if we get the equivalent of // ls /dev/hd[a-t], we have all the ATA devices on the system bool linux_smart_interface::get_dev_list(smart_device_list & devlist, const char * pattern, bool scan_ata, bool scan_scsi, const char * req_type, bool autodetect) { // Use glob to look for any directory entries matching the pattern glob_t globbuf; memset(&globbuf, 0, sizeof(globbuf)); int retglob = glob(pattern, GLOB_ERR, NULL, &globbuf); if (retglob) { // glob failed: free memory and return globfree(&globbuf); if (retglob==GLOB_NOMATCH){ pout("glob(3) found no matches for pattern %s\n", pattern); return true; } if (retglob==GLOB_NOSPACE) set_err(ENOMEM, "glob(3) ran out of memory matching pattern %s", pattern); #ifdef GLOB_ABORTED // missing in old versions of glob.h else if (retglob==GLOB_ABORTED) set_err(EINVAL, "glob(3) aborted matching pattern %s", pattern); #endif else set_err(EINVAL, "Unexplained error in glob(3) of pattern %s", pattern); return false; } // did we find too many paths? const int max_pathc = 32; int n = (int)globbuf.gl_pathc; if (n > max_pathc) { pout("glob(3) found %d > MAX=%d devices matching pattern %s: ignoring %d paths\n", n, max_pathc, pattern, n - max_pathc); n = max_pathc; } // now step through the list returned by glob. If not a link, copy // to list. If it is a link, evaluate it and see if the path ends // in "disc". for (int i = 0; i < n; i++){ // see if path is a link char linkbuf[1024]; int retlink = readlink(globbuf.gl_pathv[i], linkbuf, sizeof(linkbuf)-1); char tmpname[1024]={0}; const char * name = 0; bool is_scsi = scan_scsi; // if not a link (or a strange link), keep it if (retlink<=0 || retlink>1023) name = globbuf.gl_pathv[i]; else { // or if it's a link that points to a disc, follow it linkbuf[retlink] = 0; const char *p; if ((p=strrchr(linkbuf, '/')) && !strcmp(p+1, "disc")) // This is the branch of the code that gets followed if we are // using devfs WITH traditional compatibility links. In this // case, we add the traditional device name to the list that // is returned. name = globbuf.gl_pathv[i]; else { // This is the branch of the code that gets followed if we are // using devfs WITHOUT traditional compatibility links. In // this case, we check that the link to the directory is of // the correct type, and then append "disc" to it. bool match_ata = strstr(linkbuf, "ide"); bool match_scsi = strstr(linkbuf, "scsi"); if (((match_ata && scan_ata) || (match_scsi && scan_scsi)) && !(match_ata && match_scsi)) { is_scsi = match_scsi; snprintf(tmpname, sizeof(tmpname), "%s/disc", globbuf.gl_pathv[i]); name = tmpname; } } } if (name) { // Found a name, add device to list. smart_device * dev; if (autodetect) dev = autodetect_smart_device(name); else if (is_scsi) dev = new linux_scsi_device(this, name, req_type, true /*scanning*/); else dev = new linux_ata_device(this, name, req_type); if (dev) // autodetect_smart_device() may return nullptr. devlist.push_back(dev); } } // free memory globfree(&globbuf); return true; } // getting devices from LSI SAS MegaRaid, if available bool linux_smart_interface::get_dev_megasas(smart_device_list & devlist) { /* Scanning of disks on MegaRaid device */ /* Perform mknod of device ioctl node */ int mjr, n1; char line[128]; bool scan_megasas = false; FILE * fp = fopen("/proc/devices", "r"); while (fgets(line, sizeof(line), fp) != NULL) { n1=0; if (sscanf(line, "%d megaraid_sas_ioctl%n", &mjr, &n1) == 1 && n1 == 22) { scan_megasas = true; n1=mknod("/dev/megaraid_sas_ioctl_node", S_IFCHR, makedev(mjr, 0)); if(scsi_debugmode > 0) pout("Creating /dev/megaraid_sas_ioctl_node = %d\n", n1 >= 0 ? 0 : errno); if (n1 >= 0 || errno == EEXIST) break; } } fclose(fp); if(!scan_megasas) return false; // getting bus numbers with megasas devices struct dirent *ep; unsigned int host_no = 0; char sysfsdir[256]; /* we are using sysfs to get list of all scsi hosts */ DIR * dp = opendir ("/sys/class/scsi_host/"); if (dp != NULL) { while ((ep = readdir (dp)) != NULL) { if (!sscanf(ep->d_name, "host%d", &host_no)) continue; /* proc_name should be megaraid_sas */ snprintf(sysfsdir, sizeof(sysfsdir) - 1, "/sys/class/scsi_host/host%d/proc_name", host_no); if((fp = fopen(sysfsdir, "r")) == NULL) continue; if(fgets(line, sizeof(line), fp) != NULL && !strncmp(line,"megaraid_sas",12)) { megasas_pd_add_list(host_no, devlist); } fclose(fp); } (void) closedir (dp); } else { /* sysfs not mounted ? */ for(unsigned i = 0; i <=16; i++) // trying to add devices on first 16 buses megasas_pd_add_list(i, devlist); } return true; } bool linux_smart_interface::scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern /*= 0*/) { if (pattern) { set_err(EINVAL, "DEVICESCAN with pattern not implemented yet"); return false; } if (!type) type = ""; bool scan_ata = (!*type || !strcmp(type, "ata" )); // "sat" detection will be later handled in linux_scsi_device::autodetect_open() bool scan_scsi = (!*type || !strcmp(type, "scsi") || !strcmp(type, "sat")); if (!(scan_ata || scan_scsi)) return true; if (scan_ata) get_dev_list(devlist, "/dev/hd[a-t]", true, false, type, false); if (scan_scsi) { bool autodetect = !*type; // Try USB autodetection if no type specifed get_dev_list(devlist, "/dev/sd[a-z]", false, true, type, autodetect); // Support up to 104 devices get_dev_list(devlist, "/dev/sd[a-c][a-z]", false, true, type, autodetect); // get device list from the megaraid device get_dev_megasas(devlist); } // if we found traditional links, we are done if (devlist.size() > 0) return true; // else look for devfs entries without traditional links // TODO: Add udev support return get_dev_list(devlist, "/dev/discs/disc*", scan_ata, scan_scsi, type, false); } ata_device * linux_smart_interface::get_ata_device(const char * name, const char * type) { return new linux_ata_device(this, name, type); } scsi_device * linux_smart_interface::get_scsi_device(const char * name, const char * type) { return new linux_scsi_device(this, name, type); } smart_device * linux_smart_interface::missing_option(const char * opt) { set_err(EINVAL, "requires option '%s'", opt); return 0; } int linux_smart_interface::megasas_dcmd_cmd(int bus_no, uint32_t opcode, void *buf, size_t bufsize, uint8_t *mbox, size_t mboxlen, uint8_t *statusp) { struct megasas_iocpacket ioc; if ((mbox != NULL && (mboxlen == 0 || mboxlen > MFI_MBOX_SIZE)) || (mbox == NULL && mboxlen != 0)) { errno = EINVAL; return (-1); } bzero(&ioc, sizeof(ioc)); struct megasas_dcmd_frame * dcmd = &ioc.frame.dcmd; ioc.host_no = bus_no; if (mbox) bcopy(mbox, dcmd->mbox.w, mboxlen); dcmd->cmd = MFI_CMD_DCMD; dcmd->timeout = 0; dcmd->flags = 0; dcmd->data_xfer_len = bufsize; dcmd->opcode = opcode; if (bufsize > 0) { dcmd->sge_count = 1; dcmd->data_xfer_len = bufsize; dcmd->sgl.sge32[0].phys_addr = (intptr_t)buf; dcmd->sgl.sge32[0].length = (uint32_t)bufsize; ioc.sge_count = 1; ioc.sgl_off = offsetof(struct megasas_dcmd_frame, sgl); ioc.sgl[0].iov_base = buf; ioc.sgl[0].iov_len = bufsize; } int fd; if ((fd = ::open("/dev/megaraid_sas_ioctl_node", O_RDWR)) <= 0) { return (errno); } int r = ioctl(fd, MEGASAS_IOC_FIRMWARE, &ioc); if (r < 0) { return (r); } if (statusp != NULL) *statusp = dcmd->cmd_status; else if (dcmd->cmd_status != MFI_STAT_OK) { fprintf(stderr, "command %x returned error status %x\n", opcode, dcmd->cmd_status); errno = EIO; return (-1); } return (0); } int linux_smart_interface::megasas_pd_add_list(int bus_no, smart_device_list & devlist) { /* * Keep fetching the list in a loop until we have a large enough * buffer to hold the entire list. */ megasas_pd_list * list = 0; for (unsigned list_size = 1024; ; ) { list = (megasas_pd_list *)realloc(list, list_size); if (!list) throw std::bad_alloc(); bzero(list, list_size); if (megasas_dcmd_cmd(bus_no, MFI_DCMD_PD_GET_LIST, list, list_size, NULL, 0, NULL) < 0) { free(list); return (-1); } if (list->size <= list_size) break; list_size = list->size; } // adding all SCSI devices for (unsigned i = 0; i < list->count; i++) { if(list->addr[i].scsi_dev_type) continue; /* non disk device found */ char line[128]; snprintf(line, sizeof(line) - 1, "/dev/bus/%d", bus_no); smart_device * dev = new linux_megaraid_device(this, line, 0, list->addr[i].device_id); devlist.push_back(dev); } free(list); return (0); } // Return kernel release as integer ("2.6.31" -> 206031) static unsigned get_kernel_release() { struct utsname u; if (uname(&u)) return 0; unsigned x = 0, y = 0, z = 0; if (!(sscanf(u.release, "%u.%u.%u", &x, &y, &z) == 3 && x < 100 && y < 100 && z < 1000 )) return 0; return x * 100000 + y * 1000 + z; } // Guess device type (ata or scsi) based on device name (Linux // specific) SCSI device name in linux can be sd, sr, scd, st, nst, // osst, nosst and sg. smart_device * linux_smart_interface::autodetect_smart_device(const char * name) { const char * test_name = name; // Dereference symlinks struct stat st; std::string pathbuf; if (!lstat(name, &st) && S_ISLNK(st.st_mode)) { char * p = realpath(name, (char *)0); if (p) { pathbuf = p; free(p); test_name = pathbuf.c_str(); } } // Remove the leading /dev/... if it's there static const char dev_prefix[] = "/dev/"; if (str_starts_with(test_name, dev_prefix)) test_name += strlen(dev_prefix); // form /dev/h* or h* if (str_starts_with(test_name, "h")) return new linux_ata_device(this, name, ""); // form /dev/ide/* or ide/* if (str_starts_with(test_name, "ide/")) return new linux_ata_device(this, name, ""); // form /dev/s* or s* if (str_starts_with(test_name, "s")) { // Try to detect possible USB->(S)ATA bridge unsigned short vendor_id = 0, product_id = 0, version = 0; if (get_usb_id(test_name, vendor_id, product_id, version)) { const char * usbtype = get_usb_dev_type_by_id(vendor_id, product_id, version); if (!usbtype) return 0; // Kernels before 2.6.29 do not support the sense data length // required for SAT ATA PASS-THROUGH(16) if (!strcmp(usbtype, "sat") && get_kernel_release() < 206029) usbtype = "sat,12"; // Return SAT/USB device for this type // (Note: linux_scsi_device::autodetect_open() will not be called in this case) return get_sat_device(usbtype, new linux_scsi_device(this, name, "")); } // No USB bridge found, assume regular SCSI device return new linux_scsi_device(this, name, ""); } // form /dev/scsi/* or scsi/* if (str_starts_with(test_name, "scsi/")) return new linux_scsi_device(this, name, ""); // form /dev/ns* or ns* if (str_starts_with(test_name, "ns")) return new linux_scsi_device(this, name, ""); // form /dev/os* or os* if (str_starts_with(test_name, "os")) return new linux_scsi_device(this, name, ""); // form /dev/nos* or nos* if (str_starts_with(test_name, "nos")) return new linux_scsi_device(this, name, ""); // form /dev/tw[ael]* or tw[ael]* if (str_starts_with(test_name, "tw") && strchr("ael", test_name[2])) return missing_option("-d 3ware,N"); // form /dev/cciss/* or cciss/* if (str_starts_with(test_name, "cciss/")) return missing_option("-d cciss,N"); // we failed to recognize any of the forms return 0; } smart_device * linux_smart_interface::get_custom_smart_device(const char * name, const char * type) { // Marvell ? if (!strcmp(type, "marvell")) return new linux_marvell_device(this, name, type); // 3Ware ? int disknum = -1, n1 = -1, n2 = -1; if (sscanf(type, "3ware,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { if (n2 != (int)strlen(type)) { set_err(EINVAL, "Option -d 3ware,N requires N to be a non-negative integer"); return 0; } if (!(0 <= disknum && disknum <= 127)) { set_err(EINVAL, "Option -d 3ware,N (N=%d) must have 0 <= N <= 127", disknum); return 0; } if (!strncmp(name, "/dev/twl", 8)) return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_9700_CHAR, disknum); else if (!strncmp(name, "/dev/twa", 8)) return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_9000_CHAR, disknum); else if (!strncmp(name, "/dev/twe", 8)) return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_678K_CHAR, disknum); else return new linux_escalade_device(this, name, linux_escalade_device::AMCC_3WARE_678K, disknum); } // Areca? disknum = n1 = n2 = -1; int encnum = 1; if (sscanf(type, "areca,%n%d/%d%n", &n1, &disknum, &encnum, &n2) >= 1 || n1 == 6) { if (!(1 <= disknum && disknum <= 128)) { set_err(EINVAL, "Option -d areca,N/E (N=%d) must have 1 <= N <= 128", disknum); return 0; } if (!(1 <= encnum && encnum <= 8)) { set_err(EINVAL, "Option -d areca,N/E (E=%d) must have 1 <= E <= 8", encnum); return 0; } return new linux_areca_ata_device(this, name, disknum, encnum); } // Highpoint ? int controller = -1, channel = -1; disknum = 1; n1 = n2 = -1; int n3 = -1; if (sscanf(type, "hpt,%n%d/%d%n/%d%n", &n1, &controller, &channel, &n2, &disknum, &n3) >= 2 || n1 == 4) { int len = strlen(type); if (!(n2 == len || n3 == len)) { set_err(EINVAL, "Option '-d hpt,L/M/N' supports 2-3 items"); return 0; } if (!(1 <= controller && controller <= 8)) { set_err(EINVAL, "Option '-d hpt,L/M/N' invalid controller id L supplied"); return 0; } if (!(1 <= channel && channel <= 128)) { set_err(EINVAL, "Option '-d hpt,L/M/N' invalid channel number M supplied"); return 0; } if (!(1 <= disknum && disknum <= 15)) { set_err(EINVAL, "Option '-d hpt,L/M/N' invalid pmport number N supplied"); return 0; } return new linux_highpoint_device(this, name, controller, channel, disknum); } #ifdef HAVE_LINUX_CCISS_IOCTL_H // CCISS ? disknum = n1 = n2 = -1; if (sscanf(type, "cciss,%n%d%n", &n1, &disknum, &n2) == 1 || n1 == 6) { if (n2 != (int)strlen(type)) { set_err(EINVAL, "Option -d cciss,N requires N to be a non-negative integer"); return 0; } if (!(0 <= disknum && disknum <= 127)) { set_err(EINVAL, "Option -d cciss,N (N=%d) must have 0 <= N <= 127", disknum); return 0; } return get_sat_device("sat,auto", new linux_cciss_device(this, name, disknum)); } #endif // HAVE_LINUX_CCISS_IOCTL_H // MegaRAID ? if (sscanf(type, "megaraid,%d", &disknum) == 1) { return new linux_megaraid_device(this, name, 0, disknum); } return 0; } std::string linux_smart_interface::get_valid_custom_dev_types_str() { return "marvell, areca,N/E, 3ware,N, hpt,L/M/N, megaraid,N" #ifdef HAVE_LINUX_CCISS_IOCTL_H ", cciss,N" #endif ; } } // namespace ///////////////////////////////////////////////////////////////////////////// /// Initialize platform interface and register with smi() void smart_interface::init() { static os_linux::linux_smart_interface the_interface; smart_interface::set(&the_interface); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/dev_areca.cpp��������������������������������������������������������0000644�0000000�0000000�00000047656�12172554337�017531� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * dev_areca.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2012 Hank Wu <hank@areca.com.tw> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "config.h" #include "int64.h" #include "dev_interface.h" #include "dev_areca.h" const char * dev_areca_cpp_cvsid = "$Id: dev_areca.cpp 3835 2013-07-20 18:37:19Z chrfranke $" DEV_ARECA_H_CVSID; #include "atacmds.h" #include "scsicmds.h" #include <errno.h> #if 0 // For debugging areca code static void dumpdata(unsigned char *block, int len) { int ln = (len / 16) + 1; // total line# unsigned char c; int pos = 0; printf(" Address = %p, Length = (0x%x)%d\n", block, len, len); printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F ASCII \n"); printf("=====================================================================\n"); for ( int l = 0; l < ln && len; l++ ) { // printf the line# and the HEX data // if a line data length < 16 then append the space to the tail of line to reach 16 chars printf("%02X | ", l); for ( pos = 0; pos < 16 && len; pos++, len-- ) { c = block[l*16+pos]; printf("%02X ", c); } if ( pos < 16 ) { for ( int loop = pos; loop < 16; loop++ ) { printf(" "); } } // print ASCII char for ( int loop = 0; loop < pos; loop++ ) { c = block[l*16+loop]; if ( c >= 0x20 && c <= 0x7F ) { printf("%c", c); } else { printf("."); } } printf("\n"); } printf("=====================================================================\n"); } #endif generic_areca_device::generic_areca_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca"), m_disknum(disknum), m_encnum(encnum) { set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } generic_areca_device::~generic_areca_device() throw() { } // PURPOSE // This is an interface routine meant to isolate the OS dependent // parts of the code, and to provide a debugging interface. Each // different port and OS needs to provide it's own interface. This // is the Windows interface to the Areca "arcmsr" driver. It allows ATA // commands to be passed through the SCSI driver. // DETAILED DESCRIPTION OF ARGUMENTS // fd: is the file descriptor provided by open() // disknum is the disk number (0 to 127) in the RAID array // command: defines the different operations. // select: additional input data if needed (which log, which type of // self-test). // data: location to write output data, if needed (512 bytes). // Note: not all commands use all arguments. // RETURN VALUES // -1 if the command failed // 0 if the command succeeded, // STATUS_CHECK routine: // -1 if the command failed // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" int generic_areca_device::arcmsr_command_handler(unsigned long arcmsr_cmd, unsigned char *data, int data_len) { unsigned int cmds[] = { ARCMSR_IOCTL_READ_RQBUFFER, ARCMSR_IOCTL_WRITE_WQBUFFER, ARCMSR_IOCTL_CLEAR_RQBUFFER, ARCMSR_IOCTL_CLEAR_WQBUFFER, ARCMSR_IOCTL_RETURN_CODE_3F }; int ioctlreturn = 0; sSRB_BUFFER sBuf; struct scsi_cmnd_io iop; int dir = DXFER_TO_DEVICE; UINT8 cdb[10]={0}; UINT8 sense[32]={0}; unsigned char *areca_return_packet; int total = 0; int expected = -1; unsigned char return_buff[2048]={0}; unsigned char *ptr = &return_buff[0]; memset((unsigned char *)&sBuf, 0, sizeof(sBuf)); memset(&iop, 0, sizeof(iop)); sBuf.srbioctl.HeaderLength = sizeof(sARCMSR_IO_HDR); memcpy(sBuf.srbioctl.Signature, ARECA_SIG_STR, strlen(ARECA_SIG_STR)); sBuf.srbioctl.Timeout = 10000; sBuf.srbioctl.ControlCode = cmds[arcmsr_cmd]; if(arcmsr_cmd >= ARCMSR_CMD_TOTAL) { return -1; } switch ( arcmsr_cmd ) { // command for writing data to driver case ARCMSR_WRITE_WQBUFFER: if ( data && data_len ) { sBuf.srbioctl.Length = data_len; memcpy((unsigned char *)sBuf.ioctldatabuffer, (unsigned char *)data, data_len); } // commands for clearing related buffer of driver case ARCMSR_CLEAR_RQBUFFER: case ARCMSR_CLEAR_WQBUFFER: cdb[0] = 0x3B; //SCSI_WRITE_BUF command; break; // command for reading data from driver case ARCMSR_READ_RQBUFFER: // command for identifying driver case ARCMSR_RETURN_CODE_3F: cdb[0] = 0x3C; //SCSI_READ_BUF command; dir = DXFER_FROM_DEVICE; break; default: // unknown arcmsr commands return -1; } cdb[1] = 0x01; cdb[2] = 0xf0; cdb[5] = cmds[arcmsr_cmd] >> 24; cdb[6] = cmds[arcmsr_cmd] >> 16; cdb[7] = cmds[arcmsr_cmd] >> 8; cdb[8] = cmds[arcmsr_cmd] & 0x0F; iop.dxfer_dir = dir; iop.dxfer_len = sizeof(sBuf); iop.dxferp = (unsigned char *)&sBuf; iop.cmnd = cdb; iop.cmnd_len = sizeof(cdb); iop.sensep = sense; iop.max_sense_len = sizeof(sense); iop.timeout = SCSI_TIMEOUT_DEFAULT; while ( 1 ) { ioctlreturn = arcmsr_do_scsi_io(&iop); if(ioctlreturn || iop.scsi_status) { break; } if ( arcmsr_cmd != ARCMSR_READ_RQBUFFER ) { // if succeeded, just returns the length of outgoing data return data_len; } if ( sBuf.srbioctl.Length ) { memcpy(ptr, &sBuf.ioctldatabuffer[0], sBuf.srbioctl.Length); ptr += sBuf.srbioctl.Length; total += sBuf.srbioctl.Length; // the returned bytes enough to compute payload length ? if ( expected < 0 && total >= 5 ) { areca_return_packet = (unsigned char *)&return_buff[0]; if ( areca_return_packet[0] == 0x5E && areca_return_packet[1] == 0x01 && areca_return_packet[2] == 0x61 ) { // valid header, let's compute the returned payload length, // we expected the total length is // payload + 3 bytes header + 2 bytes length + 1 byte checksum expected = areca_return_packet[4] * 256 + areca_return_packet[3] + 6; } } if ( total >= 7 && total >= expected ) { //printf("total bytes received = %d, expected length = %d\n", total, expected); // ------ Okay! we received enough -------- break; } } } // Deal with the different error cases if ( arcmsr_cmd == ARCMSR_RETURN_CODE_3F ) { // Silence the ARCMSR_IOCTL_RETURN_CODE_3F's error, no pout(...) return -4; } if ( ioctlreturn ) { pout("do_scsi_cmnd_io with write buffer failed code = %x\n", ioctlreturn); return -2; } if ( iop.scsi_status ) { pout("io_hdr.scsi_status with write buffer failed code = %x\n", iop.scsi_status); return -3; } if ( data ) { memcpy(data, return_buff, total); } return total; } bool generic_areca_device::arcmsr_probe() { if(!is_open()) { open(); } if(arcmsr_command_handler(ARCMSR_RETURN_CODE_3F, NULL, 0) != 0) { return false; } return true; } int generic_areca_device::arcmsr_ui_handler(unsigned char *areca_packet, int areca_packet_len, unsigned char *result) { int expected = 0; unsigned char return_buff[2048]; unsigned char cs = 0; int cs_pos = 0; // ----- ADD CHECKSUM ----- cs_pos = areca_packet_len - 1; for(int i = 3; i < cs_pos; i++) { areca_packet[cs_pos] += areca_packet[i]; } if(!arcmsr_lock()) { return -1; } expected = arcmsr_command_handler(ARCMSR_CLEAR_RQBUFFER, NULL, 0); if (expected==-3) { return set_err(EIO); } expected = arcmsr_command_handler(ARCMSR_CLEAR_WQBUFFER, NULL, 0); expected = arcmsr_command_handler(ARCMSR_WRITE_WQBUFFER, areca_packet, areca_packet_len); if ( expected > 0 ) { expected = arcmsr_command_handler(ARCMSR_READ_RQBUFFER, return_buff, sizeof(return_buff)); } if ( expected < 0 ) { return -1; } if(!arcmsr_unlock()) { return -1; } // ----- VERIFY THE CHECKSUM ----- cs = 0; for ( int loop = 3; loop < expected - 1; loop++ ) { cs += return_buff[loop]; } if ( return_buff[expected - 1] != cs ) { return -1; } memcpy(result, return_buff, expected); return expected; } int generic_areca_device::arcmsr_get_controller_type() { int expected = 0; unsigned char return_buff[2048]; unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x01, 0x00, 0x23, 0x00}; memset(return_buff, 0, sizeof(return_buff)); expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff); if ( expected < 0 ) { return -1; } return return_buff[0xc2]; } int generic_areca_device::arcmsr_get_dev_type() { int expected = 0; unsigned char return_buff[2048]; int ctlr_type = -1; int encnum = get_encnum(); int disknum = get_disknum(); unsigned char areca_packet[] = {0x5E, 0x01, 0x61, 0x03, 0x00, 0x22, (unsigned char)(disknum - 1), (unsigned char)(encnum - 1), 0x00}; memset(return_buff, 0, sizeof(return_buff)); expected = arcmsr_ui_handler(areca_packet, sizeof(areca_packet), return_buff); if ( expected < 0 ) { return -1; } ctlr_type = arcmsr_get_controller_type(); if( ctlr_type < 0 ) { return ctlr_type; } if( ctlr_type == 0x02/* SATA Controllers */ || (ctlr_type == 0x03 /* SAS Controllers */ && return_buff[0x52] & 0x01 /* SATA devices behind SAS Controller */) ) { // SATA device return 1; } // SAS device return 0; } bool generic_areca_device::arcmsr_ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { // ATA input registers typedef struct _ATA_INPUT_REGISTERS { unsigned char features; unsigned char sector_count; unsigned char sector_number; unsigned char cylinder_low; unsigned char cylinder_high; unsigned char device_head; unsigned char command; unsigned char reserved[8]; unsigned char data[512]; // [in/out] buffer for outgoing/incoming data } sATA_INPUT_REGISTERS; // ATA output registers // Note: The output registers is re-sorted for areca internal use only typedef struct _ATA_OUTPUT_REGISTERS { unsigned char error; unsigned char status; unsigned char sector_count; unsigned char sector_number; unsigned char cylinder_low; unsigned char cylinder_high; } sATA_OUTPUT_REGISTERS; // Areca packet format for outgoing: // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 // B[3~4] : 2 bytes command length + variant data length, little endian // B[5] : 1 bytes areca defined command code, ATA passthrough command code is 0x1c // B[6~last-1] : variant bytes payload data // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) // // // header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte // +--------------------------------------------------------------------------------+ // + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 | // +--------------------------------------------------------------------------------+ // //Areca packet format for incoming: // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 // B[3~4] : 2 bytes payload length, little endian // B[5~last-1] : variant bytes returned payload data // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) // // // header 3 bytes length 2 bytes payload data x bytes cs 1 byte // +-------------------------------------------------------------------+ // + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 | // +-------------------------------------------------------------------+ unsigned char areca_packet[640]; int areca_packet_len = sizeof(areca_packet); unsigned char return_buff[2048]; int expected = 0; sATA_INPUT_REGISTERS *ata_cmd; // For debugging #if 0 memset(sInq, 0, sizeof(sInq)); scsiStdInquiry(fd, (unsigned char *)sInq, (int)sizeof(sInq)); dumpdata((unsigned char *)sInq, sizeof(sInq)); #endif memset(areca_packet, 0, areca_packet_len); // ----- BEGIN TO SETUP HEADERS ------- areca_packet[0] = 0x5E; areca_packet[1] = 0x01; areca_packet[2] = 0x61; areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff); areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff); areca_packet[5] = 0x1c; // areca defined code for ATA passthrough command // ----- BEGIN TO SETUP PAYLOAD DATA ----- memcpy(&areca_packet[7], "SmrT", 4); // areca defined password ata_cmd = (sATA_INPUT_REGISTERS *)&areca_packet[12]; // Set registers { const ata_in_regs & r = in.in_regs; ata_cmd->features = r.features; ata_cmd->sector_count = r.sector_count; ata_cmd->sector_number = r.lba_low; ata_cmd->cylinder_low = r.lba_mid; ata_cmd->cylinder_high = r.lba_high; ata_cmd->device_head = r.device; ata_cmd->command = r.command; } bool readdata = false; if (in.direction == ata_cmd_in::data_in) { readdata = true; // the command will read data areca_packet[6] = 0x13; } else if ( in.direction == ata_cmd_in::no_data ) { // the commands will return no data areca_packet[6] = 0x15; } else if (in.direction == ata_cmd_in::data_out) { // the commands will write data memcpy(ata_cmd->data, in.buffer, in.size); areca_packet[6] = 0x14; } else { // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE return set_err(ENOSYS); } areca_packet[11] = get_disknum() - 1; // disk# areca_packet[19] = get_encnum() - 1; // enc# // ----- BEGIN TO SEND TO ARECA DRIVER ------ expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff); if ( expected < 0 ) { return set_err(EIO); } sATA_OUTPUT_REGISTERS *ata_out = (sATA_OUTPUT_REGISTERS *)&return_buff[5] ; if ( ata_out->status ) { if ( in.in_regs.command == ATA_IDENTIFY_DEVICE && !nonempty((unsigned char *)in.buffer, in.size)) { return set_err(ENODEV, "No drive on port %d", get_disknum()); } } // returns with data if (readdata) { memcpy(in.buffer, &return_buff[7], in.size); } // Return register values { ata_out_regs & r = out.out_regs; r.error = ata_out->error; r.sector_count = ata_out->sector_count; r.lba_low = ata_out->sector_number; r.lba_mid = ata_out->cylinder_low; r.lba_high = ata_out->cylinder_high; r.status = ata_out->status; } return true; } bool generic_areca_device::arcmsr_scsi_pass_through(struct scsi_cmnd_io * iop) { // Areca packet format for outgoing: // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 // B[3~4] : 2 bytes command length + variant data length, little endian // B[5] : 1 bytes areca defined command code // B[6~last-1] : variant bytes payload data // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) // // // header 3 bytes length 2 bytes cmd 1 byte payload data x bytes cs 1 byte // +--------------------------------------------------------------------------------+ // + 0x5E 0x01 0x61 | 0x00 0x00 | 0x1c | .................... | 0x00 | // +--------------------------------------------------------------------------------+ // //Areca packet format for incoming: // B[0~2] : 3 bytes header, fixed value 0x5E, 0x01, 0x61 // B[3~4] : 2 bytes payload length, little endian // B[5~last-1] : variant bytes returned payload data // B[last] : 1 byte checksum, simply sum(B[3] ~ B[last -1]) // // // header 3 bytes length 2 bytes payload data x bytes cs 1 byte // +-------------------------------------------------------------------+ // + 0x5E 0x01 0x61 | 0x00 0x00 | .................... | 0x00 | // +-------------------------------------------------------------------+ unsigned char areca_packet[640]; int areca_packet_len = sizeof(areca_packet); unsigned char return_buff[2048]; int expected = 0; if (iop->cmnd_len > 16) { set_err(EINVAL, "cmnd_len too large"); return false; } memset(areca_packet, 0, areca_packet_len); // ----- BEGIN TO SETUP HEADERS ------- areca_packet[0] = 0x5E; areca_packet[1] = 0x01; areca_packet[2] = 0x61; areca_packet[3] = (unsigned char)((areca_packet_len - 6) & 0xff); areca_packet[4] = (unsigned char)(((areca_packet_len - 6) >> 8) & 0xff); areca_packet[5] = 0x1c; // ----- BEGIN TO SETUP PAYLOAD DATA ----- areca_packet[6] = 0x16; // scsi pass through memcpy(&areca_packet[7], "SmrT", 4); // areca defined password areca_packet[12] = iop->cmnd_len; // cdb length memcpy( &areca_packet[35], iop->cmnd, iop->cmnd_len); // cdb areca_packet[15] = (unsigned char)iop->dxfer_len; // 15(LSB) ~ 18(MSB): data length ( max=512 bytes) areca_packet[16] = (unsigned char)(iop->dxfer_len >> 8); areca_packet[17] = (unsigned char)(iop->dxfer_len >> 16); areca_packet[18] = (unsigned char)(iop->dxfer_len >> 24); if(iop->dxfer_dir == DXFER_TO_DEVICE) { areca_packet[13] |= 0x01; memcpy(&areca_packet[67], iop->dxferp, iop->dxfer_len); } else if (iop->dxfer_dir == DXFER_FROM_DEVICE) { } else if( iop->dxfer_dir == DXFER_NONE) { } else { // COMMAND NOT SUPPORTED VIA ARECA IOCTL INTERFACE return set_err(ENOSYS); } areca_packet[11] = get_disknum() - 1; // disk# areca_packet[19] = get_encnum() - 1; // enc# // ----- BEGIN TO SEND TO ARECA DRIVER ------ expected = arcmsr_ui_handler(areca_packet, areca_packet_len, return_buff); if (expected < 0) return set_err(EIO, "arcmsr_scsi_pass_through: I/O error"); if (expected < 15) // 7 bytes if port is empty return set_err(EIO, "arcmsr_scsi_pass_through: missing data (%d bytes, expected %d)", expected, 15); int scsi_status = return_buff[5]; int in_data_len = return_buff[11] | return_buff[12] << 8 | return_buff[13] << 16 | return_buff[14] << 24; if (iop->dxfer_dir == DXFER_FROM_DEVICE) { memset(iop->dxferp, 0, iop->dxfer_len); // need? memcpy(iop->dxferp, &return_buff[15], in_data_len); } if(scsi_status == 0xE1 /* Underrun, actual data length < requested data length */) { // don't care, just ignore scsi_status = 0x0; } if(scsi_status != 0x00 && scsi_status != SCSI_STATUS_CHECK_CONDITION) { return set_err(EIO); } if(scsi_status == SCSI_STATUS_CHECK_CONDITION) { // check condition iop->scsi_status = SCSI_STATUS_CHECK_CONDITION; iop->resp_sense_len = 4; iop->sensep[0] = return_buff[7]; iop->sensep[1] = return_buff[8]; iop->sensep[2] = return_buff[9]; iop->sensep[3] = return_buff[10]; } return true; } ///////////////////////////////////////////////////////////// areca_ata_device::areca_ata_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca") { set_encnum(encnum); set_disknum(disknum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } areca_ata_device::~areca_ata_device() throw() { } bool areca_ata_device::ata_pass_through(const ata_cmd_in & in, ata_cmd_out & out) { if (!ata_cmd_is_supported(in, ata_device::supports_data_out | ata_device::supports_output_regs | //ata_device::supports_multi_sector | // TODO ata_device::supports_48bit_hi_null, "Areca") ) return false; return arcmsr_ata_pass_through(in, out); } ///////////////////////////////////////////////////////////// areca_scsi_device::areca_scsi_device(smart_interface * intf, const char * dev_name, int disknum, int encnum) : smart_device(intf, dev_name, "areca", "areca") { set_encnum(encnum); set_disknum(disknum); set_info().info_name = strprintf("%s [areca_disk#%02d_enc#%02d]", dev_name, disknum, encnum); } areca_scsi_device::~areca_scsi_device() throw() { } bool areca_scsi_device::scsi_pass_through(struct scsi_cmnd_io * iop) { return arcmsr_scsi_pass_through(iop); } ����������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/WARNINGS�������������������������������������������������������������0000644�0000000�0000000�00000012175�12155132206�016237� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������$Id: WARNINGS 3817 2013-06-09 16:59:50Z chrfranke $ The most recent version of this file can be found here: http://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/WARNINGS The following are reports of serious problems (eg system lockup) which were due to smartmontools. There are DARWIN, LINUX, FREEBSD, SOLARIS and WINDOWS sections below. LINUX ----- You may also wish to search the linux-kernel mailing list for problem reports concerning smartmontools. Here is the URL: http://groups.google.com/groups?as_q=smartmontools&safe=images&ie=UTF-8&oe=UTF-8&as_ugroup=linux.kernel&lr=&num=100&hl=en SYSTEM: Any system with USB ports and USB storage devices PROBLEM: Using smartd/smartctl on USB "SCSI" storage devices can cause kernel hang REPORTER: see link below LINK: https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=107615 NOTE: USB storage devices are handled as SCSI devices by the kernel. But many of these devices do not comply with SCSI specs, and can cause the kernel to hang. Avoid using smartd/smartctl on these devices (they don't do SMART anyway). In particular, the use of smartd DEVICESCAN in /etc/smartd.conf can cause these devices (typically represented by /dev/sda or /dev/sdb) to hang, and the kernel to lock up. FIXED: This problem should be fixed in smartmontools-5.25 and greater. SYSTEM: Intel 875WP1-E motherboard with SATA drives on motherboard's SATA ports PROBLEM: smartd makes NTP time drift REPORTER: nohez@cmie.com LINK: http://groups.google.de/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=Pine.LNX.4.33.0310111545530.1047-100000%40venus.cmie.ernet.in.lucky.linux.kernel NOTE: When using SATA disks, linux kernel k_smp-2.4.21-108 (SMP because of hyper-threading) and xntp-4.1.1-177, the server time went out of sync with system time. Problem goes away when SATA disks removed. SYSTEM: Dell servers using AACRAID (SCSI) PROBLEM: Locked up, needed to be rebooted REPORTER: drew@eastvan.bc.ca LINK: http://sourceforge.net/mailarchive/forum.php?thread_id=1311313&forum_id=12495 SYSTEM: Box with Promise 20265 IDE-controller (pdc202xx-driver) and > 2.4.18 kernel with ide-taskfile support PROBLEM: Smartctl locks system solid when used on /dev/hd[ef]. REPORTER: Georg Acher <acher@in.tum.de> LINK: http://sourceforge.net/mailarchive/forum.php?thread_id=1457979&forum_id=12495 NOTE: Lockup doesn't happen with 2.4.18 kernel, and doesn't affect /dev/hd[a-d] This appears to be a problem with the pdc202xx-driver and has been reported to the pdcx maintainers. If you enable the Promise-BIOS (ATA100-BIOS) then everything will work fine. But if you disable it, then the machine will hang. SYSTEM: Box with Promise 20262 IDE-controller PROBLEM: Smartctl locks system solid REPORTER: Ben Low <ben@bdlow.net> LINK: http://sourceforge.net/mailarchive/message.php?msg_id=5074201 NOTE: Similar to previous report: Promise Ultra66 2-port card (20262) which, with linux 2.4.20, suffers from the lockups reported above. But it was impossible to enable the Promiste BIOS. A kernel patch is referenced to fix the problem. SYSTEM: Promise 20265 IDE-controller PROBLEM: Smartctl locks system solid when used on CDROM/DVD device REPORTER: see link below LINK: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208964 NOTE: Problem seems to affect kernel 2.4.21 only. SYSTEM: Promise IDE-controllers and perhaps others also PROBLEM: System freezes under heavy load, perhaps when running SMART commands REPORTER: Mario 'BitKoenig' Holbe Mario.Holbe@RZ.TU-Ilmenau.DE LINK: http://groups.google.de/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=1wUXW-2FA-9%40gated-at.bofh.it NOTE: Before freezing, SYSLOG shows the following message(s) kernel: hdf: dma timer expiry: dma status == 0xXX where XX is two hexidecimal digits. This may be a kernel bug or an underlying hardware problem. It's not clear if smartmontools plays a role in provoking this problem. FINAL NOTE: Problem was COMPLETELY resolved by replacing the power supply. See URL above, entry on May 29, 2004 by Holbe. Other things to try are exchanging cables, and cleaning PCI slots. FREEBSD ------- [No problem reports yet.] SOLARIS ------- [No problem reports yet.] CYGWIN and WINDOWS ------------------ [No problem reports yet.] DARWIN ------ SYSTEM: Any system before Tiger PROBLEM: Can't switch off SMART, can't switch off auto-save, can't run short tests. REPORTER: Geoff Keating <geoffk@geoffk.org> NOTE: There's a bug in the system library: when you ask it to do any of these things, it does the inverse (switches on, runs extended tests). Radar 3727283. SYSTEM: All known systems PROBLEM: When drive is asleep, SMART commands fail REPORTER: Geoff Keating <geoffk@geoffk.org> NOTE: You can prevent the drive from sleeping by saying pmset -a disksleep 0 or by unchecking the 'Put the hard disk(s) to sleep when possible' checkbox in the Energy Saver preferences. Radar 4094403. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartd.conf.5.in�����������������������������������������������������0000644�0000000�0000000�00000200102�12172522764�017775� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.ig Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net> $Id: smartd.conf.5.in 3833 2013-07-20 15:00:04Z chrfranke $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License (for example COPYING); If not, see <http://www.gnu.org/licenses/>. This code was originally developed as a Senior Thesis by Michael Cornwell 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 SMARTD.CONF 5 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .SH NAME \fBsmartd.conf\fP \- SMART Disk Monitoring Daemon Configuration File\fP .\" %IF NOT OS Windows .SH FULL PATH .B /usr/local/etc/smartd.conf .\" %ENDIF NOT OS Windows .SH PACKAGE VERSION CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV .SH DESCRIPTION .\" %IF NOT OS ALL .\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools. .\"! It does not contain info specific to other platforms.] .\"! .PP .\" %ENDIF NOT OS ALL \fB/usr/local/etc/smartd.conf\fP is the configuration file for the \fBsmartd\fP daemon. If the configuration file \fB/usr/local/etc/smartd.conf\fP is present, \fBsmartd\fP reads it at startup, before \fBfork\fP(2)ing into the background. If \fBsmartd\fP subsequently receives a \fBHUP\fP signal, it will then re-read the configuration file. If \fBsmartd\fP is running in debug mode, then an \fBINT\fP signal will also make it re-read the configuration file. This signal can be generated by typing \fB\<CONTROL-C\>\fP in the terminal window where \fBsmartd\fP is running. In the absence of a configuration file \fBsmartd\fP will try to open all available devices (see \fBsmartd\fP(8) man page). A configuration file with a single line \fB\'DEVICESCAN \-a'\fP would have the same effect. This can be annoying if you have an ATA or SCSI device that hangs or misbehaves when receiving SMART commands. Even if this causes no problems, you may be annoyed by the string of error log messages about devices that can\'t be opened. One can avoid this problem, and gain more control over the types of events monitored by \fBsmartd\fP, by using the configuration file .B /usr/local/etc/smartd.conf. This file contains a list of devices to monitor, with one device per line. An example file is included with the .B smartmontools distribution. You will find this sample configuration file in \fB/usr/local/share/doc/smartmontools/\fP. For security, the configuration file should not be writable by anyone but root. The syntax of the file is as follows: .IP \(bu 4 There should be one device listed per line, although you may have lines that are entirely comments or white space. .IP \(bu 4 Any text following a hash sign \'#\' and up to the end of the line is taken to be a comment, and ignored. .IP \(bu 4 Lines may be continued by using a backslash \'\e\' as the last non-whitespace or non-comment item on a line. .IP \(bu 4 Note: a line whose first character is a hash sign \'#\' is treated as a white-space blank line, \fBnot\fP as a non-existent line, and will \fBend\fP a continuation line. .PP 0 .fi Here is an example configuration file. It\'s for illustrative purposes only; please don\'t copy it onto your system without reading to the end of the .B DIRECTIVES Section below! .nf .B ################################################ .B # This is an example smartd startup config file .B # /usr/local/etc/smartd.conf for monitoring three .B # ATA disks, three SCSI disks, six ATA disks .B # behind two 3ware controllers, three SATA disks .B # directly connected to the HighPoint Rocket- .B # RAID controller, two SATA disks connected to .B # the HighPoint RocketRAID controller via a pmport .B # device, four SATA disks connected to an Areca .B # RAID controller, and one SATA disk. .B # .nf .B # First ATA disk on two different interfaces. On .B # the second disk, start a long self-test every .B # Sunday between 3 and 4 am. .B # .B \ \ /dev/hda -a -m admin@example.com,root@localhost .B \ \ /dev/hdc -a -I 194 -I 5 -i 12 -s L/../../7/03 .B # .nf .B # SCSI disks. Send a TEST warning email to admin on .B # startup. .B # .B \ \ /dev/sda .B \ \ /dev/sdb -m admin@example.com -M test .B # .nf .B # Strange device. It\'s SCSI. Start a scheduled .B # long self test between 5 and 6 am Monday/Thursday .B \ \ /dev/weird -d scsi -s L/../../(1|4)/05 .B # .nf .B # An ATA disk may appear as a SCSI device to the .B # OS. If a SCSI to ATA Translation (SAT) layer .B # is between the OS and the device then this can be .B # flagged with the '-d sat' option. This situation .B # may become common with SATA disks in SAS and FC .B # environments. .B \ \ /dev/sda -a -d sat .B # .nf .\" %IF OS Linux .B # Three disks connected to a MegaRAID controller .B # Start short self-tests daily between 1-2, 2-3, and .B # 3-4 am. .B \ \ /dev/sda -d megaraid,0 -a -s S/../.././01 .B \ \ /dev/sda -d megaraid,1 -a -s S/../.././02 .B \ \ /dev/sda -d megaraid,2 -a -s S/../.././03 .B \ \ /dev/bus/0 -d megaraid,2 -a -s S/../.././03 .B .B # .\" %ENDIF OS Linux .nf .B # Four ATA disks on a 3ware 6/7/8000 controller. .B # Start short self-tests daily between midnight and 1am, .B # 1-2, 2-3, and 3-4 am. Starting with the Linux 2.6 .B # kernel series, /dev/sdX is deprecated in favor of .B # /dev/tweN. For example replace /dev/sdc by /dev/twe0 .B # and /dev/sdd by /dev/twe1. .B \ \ /dev/sdc -d 3ware,0 -a -s S/../.././00 .B \ \ /dev/sdc -d 3ware,1 -a -s S/../.././01 .B \ \ /dev/sdd -d 3ware,2 -a -s S/../.././02 .B \ \ /dev/sdd -d 3ware,3 -a -s S/../.././03 .B # .nf .B # Two ATA disks on a 3ware 9000 controller. .B # Start long self-tests Sundays between midnight and .B # 1am and 2-3 am .B \ \ /dev/twa0 -d 3ware,0 -a -s L/../../7/00 .B \ \ /dev/twa0 -d 3ware,1 -a -s L/../../7/02 .B # .nf .B # Two SATA (not SAS) disks on a 3ware 9750 controller. .B # Start long self-tests Sundays between midnight and .B # 1am and 2-3 am .\" %IF OS Linux .B \ \ /dev/twl0 -d 3ware,0 -a -s L/../../7/00 .B \ \ /dev/twl0 -d 3ware,1 -a -s L/../../7/02 .\" %ENDIF OS Linux .\" %IF OS FreeBSD .B \ \ /dev/tws0 -d 3ware,0 -a -s L/../../7/00 .B \ \ /dev/tws0 -d 3ware,1 -a -s L/../../7/02 .\" %ENDIF OS FreeBSD .B # .nf .B # Three SATA disks on a HighPoint RocketRAID controller. .B # Start short self-tests daily between 1-2, 2-3, and .B # 3-4 am. .\" %IF OS Linux .B # under Linux .B \ \ /dev/sde -d hpt,1/1 -a -s S/../.././01 .B \ \ /dev/sde -d hpt,1/2 -a -s S/../.././02 .B \ \ /dev/sde -d hpt,1/3 -a -s S/../.././03 .\" %ENDIF OS Linux .\" %IF OS FreeBSD .B # under FreeBSD .B /dev/hptrr -d hpt,1/1 -a -s S/../.././01 .B /dev/hptrr -d hpt,1/2 -a -s S/../.././02 .B /dev/hptrr -d hpt,1/3 -a -s S/../.././03 .\" %ENDIF OS FreeBSD .B # .nf .B # Two SATA disks connected to a HighPoint RocketRAID .B # via a pmport device. Start long self-tests Sundays .B # between midnight and 1am and 2-3 am. .\" %IF OS Linux .B # under Linux .B \ \ /dev/sde -d hpt,1/4/1 -a -s L/../../7/00 .B \ \ /dev/sde -d hpt,1/4/2 -a -s L/../../7/02 .\" %ENDIF OS Linux .\" %IF OS FreeBSD .B # under FreeBSD .B \ \ /dev/hptrr -d hpt,1/4/1 -a -s L/../../7/00 .B \ \ /dev/hptrr -d hpt,1/4/2 -a -s L/../../7/02 .B # .\" %ENDIF OS FreeBSD .nf .B # Three SATA disks connected to an Areca .B # RAID controller. Start long self-tests Sundays .B # between midnight and 3 am. .\" %IF OS Linux .B \ \ /dev/sg2 -d areca,1 -a -s L/../../7/00 .B \ \ /dev/sg2 -d areca,2 -a -s L/../../7/01 .B \ \ /dev/sg2 -d areca,3 -a -s L/../../7/02 .\" %ENDIF OS Linux .\" %IF OS FreeBSD .B \ \ /dev/arcmsr0 -d areca,1 -a -s L/../../7/00 .B \ \ /dev/arcmsr0 -d areca,2 -a -s L/../../7/01 .B \ \ /dev/arcmsr0 -d areca,3 -a -s L/../../7/02 .\" %ENDIF OS FreeBSD .B # .nf .B # The following line enables monitoring of the .B # ATA Error Log and the Self-Test Error Log. .B # It also tracks changes in both Prefailure .B # and Usage Attributes, apart from Attributes .B # 9, 194, and 231, and shows continued lines: .B # .B \ \ /dev/hdd\ -l\ error\ \e .B \ \ \ \ \ \ \ \ \ \ \ -l\ selftest\ \e .B \ \ \ \ \ \ \ \ \ \ \ -t\ \e\ \ \ \ \ \ # Attributes not tracked: .B \ \ \ \ \ \ \ \ \ \ \ -I\ 194\ \e\ \ # temperature .B \ \ \ \ \ \ \ \ \ \ \ -I\ 231\ \e\ \ # also temperature .B \ \ \ \ \ \ \ \ \ \ \ -I 9\ \ \ \ \ \ # power-on hours .B # .B ################################################ .fi .PP .SH CONFIGURATION FILE DIRECTIVES .PP If a non-comment entry in the configuration file is the text string .B DEVICESCAN in capital letters, then \fBsmartd\fP will ignore any remaining lines in the configuration file, and will scan for devices. .B DEVICESCAN may optionally be followed by Directives that will apply to all devices that are found in the scan. Please see below for additional details. [NEW EXPERIMENTAL SMARTD FEATURE] If an entry in the configuration file starts with .B DEFAULT instead of a device name, then all directives in this entry are set as defaults for the next device entries. This configuration: .nf \ \ DEFAULT -a -R5! -W 2,40,45 -I 194 -s L/../../7/00 -m admin@example.com \ \ /dev/sda \ \ /dev/sdb \ \ /dev/sdc \ \ DEFAULT -H -m admin@example.com \ \ /dev/sdd \ \ /dev/sde -d removable .fi has the same effect as: .nf \ \ /dev/sda -a -R5! -W 2,40,45 -I 194 -s L/../../7/00 -m admin@example.com \ \ /dev/sdb -a -R5! -W 2,40,45 -I 194 -s L/../../7/00 -m admin@example.com \ \ /dev/sdc -a -R5! -W 2,40,45 -I 194 -s L/../../7/00 -m admin@example.com \ \ /dev/sdd -H -m admin@example.com \ \ /dev/sde -d removable -H -m admin@example.com .fi .sp 2 The following are the Directives that may appear following the device name or .B DEVICESCAN or .B DEFAULT on any line of the .B /usr/local/etc/smartd.conf configuration file. Note that .B these are NOT command-line options for \fBsmartd\fP. The Directives below may appear in any order, following the device name. .B For an ATA device, if no Directives appear, then the device will be monitored as if the \'\-a\' Directive (monitor all SMART properties) had been given. .B If a SCSI disk is listed, it will be monitored at the maximum implemented level: roughly equivalent to using the \'\-H \-l selftest\' options for an ATA disk. So with the exception of \'\-d\', \'\-m\', \'\-l selftest\', \'\-s\', and \'\-M\', the Directives below are ignored for SCSI disks. For SCSI disks, the \'\-m\' Directive sends a warning email if the SMART status indicates a disk failure or problem, if the SCSI inquiry about disk status fails, or if new errors appear in the self-test log. .B If a 3ware controller is used then the corresponding SCSI (/dev/sd?) or character device (/dev/twe?, /dev/twa?, /dev/twl? or /dev/tws?) must be listed, along with the \'\-d 3ware,N\' Directive (see below). The individual ATA disks hosted by the 3ware controller appear to \fBsmartd\fP as normal ATA devices. Hence all the ATA directives can be used for these disks (but see note below). .\" %IF OS Linux FreeBSD .B If an Areca controller is used then the corresponding device (SCSI /dev/sg? on Linux or /dev/arcmsr0 on FreeBSD) must be listed, along with the \'\-d areca,N\' Directive (see below). The individual SATA disks hosted by the Areca controller appear to \fBsmartd\fP as normal ATA devices. Hence all the ATA directives can be used for these disks. Areca firmware version 1.46 or later which supports smartmontools must be used; Please see the \fBsmartctl\fP(8) man page for further details. .\" %ENDIF OS Linux FreeBSD .TP .B \-d TYPE Specifies the type of the device. The valid arguments to this directive are: .I auto \- attempt to guess the device type from the device name or from controller type info provided by the operating system or from a matching USB ID entry in the drive database. This is the default. .I ata \- the device type is ATA. This prevents \fBsmartd\fP from issuing SCSI commands to an ATA device. .\" %IF NOT OS Darwin .I scsi \- the device type is SCSI. This prevents \fBsmartd\fP from issuing ATA commands to a SCSI device. .I sat[,auto][,N] \- the device type is SCSI to ATA Translation (SAT). This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer (SATL) between the disk and the operating system. SAT defines two ATA PASS THROUGH SCSI commands, one 12 bytes long and the other 16 bytes long. The default is the 16 byte variant which can be overridden with either \'\-d sat,12\' or \'\-d sat,16\'. If \'\-d sat,auto\' is specified, device type SAT (for ATA/SATA disks) is only used if the SCSI INQUIRY data reports a SATL (VENDOR: "ATA "). Otherwise device type SCSI (for SCSI/SAS disks) is used. .I usbcypress \- this device type is for ATA disks that are behind a Cypress USB to PATA bridge. This will use the ATACB proprietary scsi pass through command. The default SCSI operation code is 0x24, but although it can be overridden with \'\-d usbcypress,0xN\', where N is the scsi operation code, you're running the risk of damage to the device or filesystems on it. .I usbjmicron[,p][,x][,PORT] \- this device type is for SATA disks that are behind a JMicron USB to PATA/SATA bridge. The 48-bit ATA commands (required e.g. for \'\-l xerror\', see below) do not work with all of these bridges and are therefore disabled by default. These commands can be enabled by \'\-d usbjmicron,x\'. If two disks are connected to a bridge with two ports, an error message is printed if no PORT is specified. The port can be specified by \'\-d usbjmicron[,x],PORT\' where PORT is 0 (master) or 1 (slave). This is not necessary if the device uses a port multiplier to connect multiple disks to one port. The disks appear under separate /dev/ice names then. CAUTION: Specifying \',x\' for a device which does not support it results in I/O errors and may disconnect the drive. The same applies if the specified PORT does not exist or is not connected to a disk. [NEW EXPERIMENTAL SMARTD FEATURE] The Prolific PL2507/3507 USB bridges with older firmware support a pass-through command similar to JMicron and work with \'\-d usbjmicron,0\'. Newer Prolific firmware requires a modified command which can be selected by \'\-d usbjmicron,p\'. Note that this does not yet support the SMART status command. .I usbsunplus \- this device type is for SATA disks that are behind a SunplusIT USB to SATA bridge. .\" %ENDIF NOT OS Darwin .\" %IF OS Linux .I marvell \- [Linux only] interact with SATA disks behind Marvell chip-set controllers (using the Marvell rather than libata driver). .I megaraid,N \- [Linux only] the device consists of one or more SCSI/SAS disks connected to a MegaRAID controller. The non-negative integer N (in the range of 0 to 127 inclusive) denotes which disk on the controller is monitored. This interface will also work for Dell PERC controllers. In log files and email messages this disk will be identified as megaraid_disk_XXX with XXX in the range from 000 to 127 inclusive. It is possible to set RAID device name as /dev/bus/N, where N is a SCSI bus number. Please see the \fBsmartctl\fP(8) man page for further details. .\" %ENDIF OS Linux .\" %IF OS FreeBSD Linux .I 3ware,N \- [FreeBSD and Linux only] the device consists of one or more ATA disks connected to a 3ware RAID controller. The non-negative integer N (in the range from 0 to 127 inclusive) denotes which disk on the controller is monitored. In log files and email messages this disk will be identified as 3ware_disk_XXX with XXX in the range from 000 to 127 inclusive. Note that while you may use \fBany\fP of the 3ware SCSI logical devices /dev/tw* to address \fBany\fP of the physical disks (3ware ports), error and log messages will make the most sense if you always list the 3ware SCSI logical device corresponding to the particular physical disks. Please see the \fBsmartctl\fP(8) man page for further details. .\" %ENDIF OS FreeBSD Linux .\" %IF OS FreeBSD Linux Windows Cygwin .I areca,N \- [FreeBSD, Linux, Windows and Cygwin only] the device consists of one or more SATA disks connected to an Areca SATA RAID controller. The positive integer N (in the range from 1 to 24 inclusive) denotes which disk on the controller is monitored. In log files and email messages this disk will be identifed as areca_disk_XX with XX in the range from 01 to 24 inclusive. Please see the \fBsmartctl\fP(8) man page for further details. .I areca,N/E \- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTD FEATURE] the device consists of one or more SATA or SAS disks connected to an Areca SAS RAID controller. The integer N (range 1 to 128) denotes the channel (slot) and E (range 1 to 8) denotes the enclosure. Important: This requires Areca SAS controller firmware version 1.51 or later. .\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS FreeBSD Linux .I cciss,N \- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS or SATA disks connected to a cciss RAID controller. The non-negative integer N (in the range from 0 to 15 inclusive) denotes which disk on the controller is monitored. In log files and email messages this disk will be identified as cciss_disk_XX with XX in the range from 00 to 15 inclusive. Please see the \fBsmartctl\fP(8) man page for further details. .I hpt,L/M/N \- [FreeBSD and Linux only] the device consists of one or more ATA disks connected to a HighPoint RocketRAID controller. The integer L is the controller id, the integer M is the channel number, and the integer N is the PMPort number if it is available. The allowed values of L are from 1 to 4 inclusive, M are from 1 to 128 inclusive and N from 1 to 4 if PMPort available. And also these values are limited by the model of the HighPoint RocketRAID controller. In log files and email messages this disk will be identified as hpt_X/X/X and X/X/X is the same as L/M/N, note if no N indicated, N set to the default value 1. Please see the \fBsmartctl\fP(8) man page for further details. .\" %ENDIF OS FreeBSD Linux .I ignore \- [NEW EXPERIMENTAL SMARTD FEATURE] the device specified by this configuration entry should be ignored. This allows to ignore specific devices which are detected by a following DEVICESCAN configuration line. It may also be used to temporary disable longer multi-line configuration entries. This Directive may be used in conjunction with the other \'\-d\' Directives. .I removable \- the device or its media is removable. This indicates to \fBsmartd\fP that it should continue (instead of exiting, which is the default behavior) if the device does not appear to be present when \fBsmartd\fP is started. This Directive may be used in conjunction with the other \'\-d\' Directives. .TP .B \-n POWERMODE[,N][,q] [ATA only] This \'nocheck\' Directive is used to prevent a disk from being spun-up when it is periodically polled by \fBsmartd\fP. ATA disks have five different power states. In order of increasing power consumption they are: \'OFF\', \'SLEEP\', \'STANDBY\', \'IDLE\', and \'ACTIVE\'. Typically in the OFF, SLEEP, and STANDBY modes the disk\'s platters are not spinning. But usually, in response to SMART commands issued by \fBsmartd\fP, the disk platters are spun up. So if this option is not used, then a disk which is in a low-power mode may be spun up and put into a higher-power mode when it is periodically polled by \fBsmartd\fP. Note that if the disk is in SLEEP mode when \fBsmartd\fP is started, then it won't respond to \fBsmartd\fP commands, and so the disk won't be registered as a device for \fBsmartd\fP to monitor. If a disk is in any other low-power mode, then the commands issued by \fBsmartd\fP to register the disk will probably cause it to spin-up. The \'\fB\-n\fP\' (nocheck) Directive specifies if \fBsmartd\fP\'s periodic checks should still be carried out when the device is in a low-power mode. It may be used to prevent a disk from being spun-up by periodic \fBsmartd\fP polling. The allowed values of POWERMODE are: .I never \- \fBsmartd\fP will poll (check) the device regardless of its power mode. This may cause a disk which is spun-down to be spun-up when \fBsmartd\fP checks it. This is the default behavior if the '\-n' Directive is not given. .I sleep \- check the device unless it is in SLEEP mode. .I standby \- check the device unless it is in SLEEP or STANDBY mode. In these modes most disks are not spinning, so if you want to prevent a laptop disk from spinning up each time that \fBsmartd\fP polls, this is probably what you want. .I idle \- check the device unless it is in SLEEP, STANDBY or IDLE mode. In the IDLE state, most disks are still spinning, so this is probably not what you want. Maximum number of skipped checks (in a row) can be specified by appending positive number \',N\' to POWERMODE (like \'\-n standby,15\'). After N checks are skipped in a row, powermode is ignored and the check is performed anyway. When a periodic test is skipped, \fBsmartd\fP normally writes an informal log message. The message can be suppressed by appending the option \',q\' to POWERMODE (like \'\-n standby,q\'). This prevents a laptop disk from spinning up due to this message. Both \',N\' and \',q\' can be specified together. .TP .B \-T TYPE Specifies how tolerant \fBsmartd\fP should be of SMART command failures. The valid arguments to this Directive are: .I normal \- do not try to monitor the disk if a mandatory SMART command fails, but continue if an optional SMART command fails. This is the default. .I permissive \- try to monitor the disk even if it appears to lack SMART capabilities. This may be required for some old disks (prior to ATA-3 revision 4) that implemented SMART before the SMART standards were incorporated into the ATA/ATAPI Specifications. [Please see the \fBsmartctl \-T\fP command-line option.] .TP .B \-o VALUE [ATA only] Enables or disables SMART Automatic Offline Testing when \fBsmartd\fP starts up and has no further effect. The valid arguments to this Directive are \fIon\fP and \fIoff\fP. The delay between tests is vendor-specific, but is typically four hours. Note that SMART Automatic Offline Testing is \fBnot\fP part of the ATA Specification. Please see the .B smartctl \-o command-line option documentation for further information about this feature. .TP .B \-S VALUE Enables or disables Attribute Autosave when \fBsmartd\fP starts up and has no further effect. The valid arguments to this Directive are \fIon\fP and \fIoff\fP. Also affects SCSI devices. [Please see the \fBsmartctl \-S\fP command-line option.] .TP .B \-H [ATA only] Check the SMART health status of the disk. If any Prefailure Attributes are less than or equal to their threshold values, then disk failure is predicted in less than 24 hours, and a message at loglevel .B \'LOG_CRIT\' will be logged to syslog. [Please see the .B smartctl \-H command-line option.] .TP .B \-l TYPE Reports increases in the number of errors in one of three SMART logs. The valid arguments to this Directive are: .I error \- [ATA only] report if the number of ATA errors reported in the Summary SMART error log has increased since the last check. .I xerror \- [ATA only] report if the number of ATA errors reported in the Extended Comprehensive SMART error log has increased since the last check. If both \'\-l error\' and \'\-l xerror\' are specified, smartd checks the maximum of both values. [Please see the \fBsmartctl \-l xerror\fP command-line option.] .I selftest \- report if the number of failed tests reported in the SMART Self-Test Log has increased since the last check, or if the timestamp associated with the most recent failed test has increased. Note that such errors will \fBonly\fP be logged if you run self-tests on the disk (and it fails a test!). Self-Tests can be run automatically by \fBsmartd\fP: please see the \fB\'\-s\'\fP Directive below. Self-Tests can also be run manually by using the \fB\'\-t\ short\'\fP and \fB\'\-t\ long\'\fP options of \fBsmartctl\fP and the results of the testing can be observed using the \fBsmartctl \'\-l\ selftest\'\fP command-line option. [Please see the \fBsmartctl \-l\fP and \fB\-t\fP command-line options.] [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored. The warning email counter is reset if the number of failed self tests dropped to 0. This typically happens when an extended self-test is run after all bad sectors have been reallocated. .I offlinests[,ns] \- [ATA only] report if the Offline Data Collection status has changed since the last check. The report will be logged as LOG_CRIT if the new status indicates an error. With some drives the status often changes, therefore \'\-l offlinests\' is not enabled by '\-a\' Directive. .\" %IF NOT OS Cygwin Windows .\"! Appending \',ns\' (no standby) to this directive is not implemented .\"! on OS_MAN_FILTER. .\" %ENDIF NOT OS Cygwin Windows .\" %IF OS Cygwin Windows [Windows and Cygwin only] If \',ns\' (no standby) is appended to this directive, smartd disables system auto standby as long as an Offline Data Collection is in progress. See \'\-l selfteststs,ns\' below. .\" %ENDIF OS Cygwin Windows .I selfteststs[,ns] \- [ATA only] report if the Self-Test execution status has changed since the last check. The report will be logged as LOG_CRIT if the new status indicates an error. .\" %IF NOT OS Cygwin Windows .\"! Appending \',ns\' (no standby) to this directive is not implemented .\"! on OS_MAN_FILTER. .\" %ENDIF NOT OS Cygwin Windows .\" %IF OS Cygwin Windows [Windows and Cygwin only] If \',ns\' (no standby) is appended to this directive, smartd disables system auto standby as long as a Self-Test is in progress. This prevents that a Self-Test is aborted because the OS sets the system to a standby/sleep mode when idle. Smartd check interval (\'\-i\' option) should be shorter than the configured idle timeout. Auto standby is not disabled if the system is running on battery. .\" %ENDIF OS Cygwin Windows .I scterc,READTIME,WRITETIME \- [ATA only] sets the SCT Error Recovery Control settings to the specified values (deciseconds) when \fBsmartd\fP starts up and has no further effect. Values of 0 disable the feature, other values less than 65 are probably not supported. For RAID configurations, this is typically set to 70,70 deciseconds. [Please see the \fBsmartctl \-l scterc\fP command-line option.] .TP .B \-e NAME[,VALUE] Sets non-SMART device settings when \fBsmartd\fP starts up and has no further effect. [Please see the \fBsmartctl \-\-set\fP command-line option.] Valid arguments are: .I aam,[N|off] \- [ATA only] Sets the Automatic Acoustic Management (AAM) feature. .I apm,[N|off] \- [ATA only] Sets the Advanced Power Management (APM) feature. .I lookahead,[on|off] \- [ATA only] Sets the read look-ahead feature. .I security-freeze \- [ATA only] Sets ATA Security feature to frozen mode. .I standby,[N|off] \- [ATA only] Sets the standby (spindown) timer and places the drive in the IDLE mode. .I wcache,[on|off] \- [ATA only] Sets the volatile write cache feature. .TP .B \-s REGEXP Run Self-Tests or Offline Immediate Tests, at scheduled times. A Self- or Offline Immediate Test will be run at the end of periodic device polling, if all 12 characters of the string \fBT/MM/DD/d/HH\fP match the extended regular expression \fBREGEXP\fP. Here: .RS 7 .IP \fBT\fP 4 is the type of the test. The values that \fBsmartd\fP will try to match (in turn) are: \'L\' for a \fBL\fPong Self-Test, \'S\' for a \fBS\fPhort Self-Test, \'C\' for a \fBC\fPonveyance Self-Test (ATA only), and \'O\' for an \fBO\fPffline Immediate Test (ATA only). As soon as a match is found, the test will be started and no additional matches will be sought for that device and that polling cycle. To run scheduled Selective Self-Tests, use \'n\' for \fBn\fPext span, \'r\' to \fBr\fPedo last span, or \'c\' to \fBc\fPontinue with next span or redo last span based on status of last test. The LBA range is based on the first span from the last test. See the \fBsmartctl \-t select,[next|redo|cont]\fP options for further info. Some disks (e.g. WD) do not preserve the selective self test log accross power cycles. If state persistence (\'\-s\' option) is enabled, the last test span is preserved by smartd and used if (and only if) the selective self test log is empty. .IP \fBMM\fP 4 is the month of the year, expressed with two decimal digits. The range is from 01 (January) to 12 (December) inclusive. Do \fBnot\fP use a single decimal digit or the match will always fail! .IP \fBDD\fP 4 is the day of the month, expressed with two decimal digits. The range is from 01 to 31 inclusive. Do \fBnot\fP use a single decimal digit or the match will always fail! .IP \fBd\fP 4 is the day of the week, expressed with one decimal digit. The range is from 1 (Monday) to 7 (Sunday) inclusive. .IP \fBHH\fP 4 is the hour of the day, written with two decimal digits, and given in hours after midnight. The range is 00 (midnight to just before 1am) to 23 (11pm to just before midnight) inclusive. Do \fBnot\fP use a single decimal digit or the match will always fail! .RE .\" The following two lines are a workaround for a man2html bug. Please leave them. .\" They define a non-existent option; useful because man2html can't correctly reset the margins. .TP .B \& Some examples follow. In reading these, keep in mind that in extended regular expressions a dot \fB\'.\'\fP matches any single character, and a parenthetical expression such as \fB\'(A|B|C)\'\fP denotes any one of the three possibilities \fBA\fP, \fBB\fP, or \fBC\fP. To schedule a short Self-Test between 2-3am every morning, use: .nf \fB \-s S/../.././02\fP .fi To schedule a long Self-Test between 4-5am every Sunday morning, use: .nf \fB \-s L/../../7/04\fP .fi To schedule a long Self-Test between 10-11pm on the first and fifteenth day of each month, use: .nf \fB \-s L/../(01|15)/./22\fP .fi To schedule an Offline Immediate test after every midnight, 6am, noon,and 6pm, plus a Short Self-Test daily at 1-2am and a Long Self-Test every Saturday at 3-4am, use: .nf \fB \-s (O/../.././(00|06|12|18)|S/../.././01|L/../../6/03)\fP .fi If Long Self-Tests of a large disks take longer than the system uptime, a full disk test can be performed by several Selective Self-Tests. To setup a full test of a 1TB disk within 20 days (one 50GB span each day), run this command once: .nf smartctl -t select,0-99999999 /dev/sda .fi To run the next test spans on Monday-Friday between 12-13am, run smartd with this directive: .nf \fB \-s n/../../[1-5]/12\fP .fi Scheduled tests are run immediately following the regularly-scheduled device polling, if the current local date, time, and test type, match \fBREGEXP\fP. By default the regularly-scheduled device polling occurs every thirty minutes after starting \fBsmartd\fP. Take caution if you use the \'\-i\' option to make this polling interval more than sixty minutes: the poll times may fail to coincide with any of the testing times that you have specified with \fBREGEXP\fP. In this case the test will be run following the next device polling. Before running an offline or self-test, \fBsmartd\fP checks to be sure that a self-test is not already running. If a self-test \fBis\fP already running, then this running self test will \fBnot\fP be interrupted to begin another test. \fBsmartd\fP will not attempt to run \fBany\fP type of test if another test was already started or run in the same hour. To avoid performance problems during system boot, \fBsmartd\fP will not attempt to run any scheduled tests following the very first device polling (unless \'\-q onecheck\' is specified). Each time a test is run, \fBsmartd\fP will log an entry to SYSLOG. You can use these or the '-q showtests' command-line option to verify that you constructed \fBREGEXP\fP correctly. The matching order (\fBL\fP before \fBS\fP before \fBC\fP before \fBO\fP) ensures that if multiple test types are all scheduled for the same hour, the longer test type has precedence. This is usually the desired behavior. If the scheduled tests are used in conjunction with state persistence (\'\-s\' option), smartd will also try to match the hours since last shutdown (or 90 days at most). If any test would have been started during downtime, the longest (see above) of these tests is run after second device polling. If the \'\-n\' directive is used and any test would have been started during disk standby time, the longest of these tests is run when the disk is active again. Unix users: please beware that the rules for extended regular expressions [regex(7)] are \fBnot\fP the same as the rules for file-name pattern matching by the shell [glob(7)]. \fBsmartd\fP will issue harmless informational warning messages if it detects characters in \fBREGEXP\fP that appear to indicate that you have made this mistake. .TP .B \-m ADD Send a warning email to the email address \fBADD\fP if the \'\-H\', \'\-l\', \'\-f\', \'\-C\', or \'\-O\' Directives detect a failure or a new error, or if a SMART command to the disk fails. This Directive only works in conjunction with these other Directives (or with the equivalent default \'\-a\' Directive). To prevent your email in-box from getting filled up with warning messages, by default only a single warning will be sent for each of the enabled alert types, \'\-H\', \'\-l\', \'\-f\', \'\-C\', or \'\-O\' even if more than one failure or error is detected or if the failure or error persists. [This behavior can be modified; see the \'\-M\' Directive below.] To send email to more than one user, please use the following "comma separated" form for the address: \fBuser1@add1,user2@add2,...,userN@addN\fP (with no spaces). To test that email is being sent correctly, use the \'\-M test\' Directive described below to send one test email message on \fBsmartd\fP startup. By default, email is sent using the system .B mail command. In order that \fBsmartd\fP find the mail command (normally /bin/mail) an executable named .B \'mail\' must be in the path of the shell or environment from which \fBsmartd\fP was started. If you wish to specify an explicit path to the mail executable (for example /usr/local/bin/mail) or a custom script to run, please use the \'\-M exec\' Directive below. .\" %IF OS Solaris Note that by default under Solaris, in the previous paragraph, \'\fBmailx\fP\' and \'\fB/bin/mailx\fP\' are used, since Solaris \'/bin/mail\' does not accept a \'\-s\' (Subject) command-line argument. .\" %ENDIF OS Solaris .\" %IF OS Windows On Windows, the \'\fBBlat\fP\' mailer (\fBhttp://blat.sourceforge.net/\fP) is used by default. This mailer uses a different command line syntax, see \'\-M exec\' below. .\" %ENDIF OS Windows Note also that there is a special argument .B <nomailer> which can be given to the \'\-m\' Directive in conjunction with the \'\-M exec\' Directive. Please see below for an explanation of its effect. If the mailer or the shell running it produces any STDERR/STDOUT output, then a snippet of that output will be copied to SYSLOG. The remainder of the output is discarded. If problems are encountered in sending mail, this should help you to understand and fix them. If you have mail problems, we recommend running \fBsmartd\fP in debug mode with the \'-d\' flag, using the \'-M test\' Directive described below. .\" %IF NOT OS Windows [NEW EXPERIMENTAL SMARTD FEATURE] If a word of the comma separated list has the form \'@plugin\', a custom script /usr/local/etc/smartd_warning.d/plugin is run and the word is removed from the list before sending mail. The string \'plugin\' may be any valid name except \'ALL\'. If \'@ALL\' is specified, all scripts in /usr/local/etc/smartd_warning.d/* are run instead. This is handled by the script /usr/local/etc/smartd_warning.sh (see also \'\-M exec\' below). .\" %ENDIF NOT OS Windows .\" %IF OS Windows [Windows only] [NEW EXPERIMENTAL SMARTD FEATURE] If one of the following words are used as the first address in the comma separated list, warning messages are sent via WTSSendMessage(). This displays message boxes on the desktops of the selected sessions. Address \'\fBconsole\fP\' specifies the console session only, \'\fBactive\fP\' specifies the console session and all active remote sessions, and \'\fBconnected\fP\' specifies the console session and all connected (active or waiting for login) remote sessions. This is handled by the script EXEDIR/smartd_warning.cmd which runs the tool EXEDIR/wtssendmsg.exe (see also \'\-M exec\' below). The addresses \'\fBmsgbox\fP\' and \'\fBsysmsgbox\fP\' are now deprecated and have the same effect as \'\fBconsole\fP\'. .\" %ENDIF OS Windows .TP .B \-M TYPE These Directives modify the behavior of the \fBsmartd\fP email warnings enabled with the \'\-m\' email Directive described above. These \'\-M\' Directives only work in conjunction with the \'\-m\' Directive and can not be used without it. Multiple \-M Directives may be given. If more than one of the following three \-M Directives are given (example: \-M once \-M daily) then the final one (in the example, \-M daily) is used. The valid arguments to the \-M Directive are (one of the following three): .I once \- send only one warning email for each type of disk problem detected. This is the default unless state persistence (\'\-s\' option) is enabled. .I daily \- send additional warning reminder emails, once per day, for each type of disk problem detected. This is the default if state persistence (\'\-s\' option) is enabled. .I diminishing \- send additional warning reminder emails, after a one-day interval, then a two-day interval, then a four-day interval, and so on for each type of disk problem detected. Each interval is twice as long as the previous interval. If a disk problem is no longer detected, the internal email counter is reset. If the problem reappears a new warning email is sent immediately. In addition, one may add zero or more of the following Directives: .I test \- send a single test email immediately upon \fBsmartd\fP startup. This allows one to verify that email is delivered correctly. Note that if this Directive is used, \fBsmartd\fP will also send the normal email warnings that were enabled with the \'\-m\' Directive, in addition to the single test email! .I exec PATH \- run the executable PATH instead of the default mail command, when \fBsmartd\fP needs to send email. PATH must point to an executable binary file or script. .\" %IF OS Windows [Windows only] The PATH may contain space characters. Then it must be included in double quotes. .\" %ENDIF OS Windows By setting PATH to point to a customized script, you can make \fBsmartd\fP perform useful tricks when a disk problem is detected (beeping the console, shutting down the machine, broadcasting warnings to all logged-in users, etc.) But please be careful. \fBsmartd\fP will \fBblock\fP until the executable PATH returns, so if your executable hangs, then \fBsmartd\fP will also hang. .\" %IF NOT OS Windows Some sample scripts are included in /usr/local/share/doc/smartmontools/examplescripts/. .\" %ENDIF NOT OS Windows The return status of the executable is recorded by \fBsmartd\fP in SYSLOG. The executable is not expected to write to STDOUT or STDERR. If it does, then this is interpreted as indicating that something is going wrong with your executable, and a fragment of this output is logged to SYSLOG to help you to understand the problem. Normally, if you wish to leave some record behind, the executable should send mail or write to a file or device. Before running the executable, \fBsmartd\fP sets a number of environment variables. These environment variables may be used to control the executable\'s behavior. The environment variables exported by \fBsmartd\fP are: .RS 7 .IP \fBSMARTD_MAILER\fP 4 is set to the argument of \-M exec, if present or else to \'mail\' (examples: /bin/mail, mail). .IP \fBSMARTD_DEVICE\fP 4 is set to the device path (examples: /dev/hda, /dev/sdb). .IP \fBSMARTD_DEVICETYPE\fP 4 is set to the device type specified by \'-d\' directive or \'auto\' if none. .IP \fBSMARTD_DEVICESTRING\fP 4 is set to the device description. For SMARTD_DEVICETYPE of ata or scsi, this is the same as SMARTD_DEVICE. For 3ware RAID controllers, the form used is \'/dev/sdc [3ware_disk_01]\'. For HighPoint RocketRAID controller, the form is \'/dev/sdd [hpt_1/1/1]\' under Linux or \'/dev/hptrr [hpt_1/1/1]\' under FreeBSD. For Areca controllers, the form is \'/dev/sg2 [areca_disk_09]\' on Linux or \'/dev/arcmsr0 [areca_disk_09]\' on FreeBSD. In these cases the device string contains a space and is NOT quoted. So to use $SMARTD_DEVICESTRING in a bash script you should probably enclose it in double quotes. .IP \fBSMARTD_DEVICEINFO\fP 4 is set to device identify information. It includes most of the info printed by \fBsmartctl \-i\fP but uses a brief single line format. This device info is also logged when \fBsmartd\fP starts up. The string contains space characters and is NOT quoted. .IP \fBSMARTD_FAILTYPE\fP 4 gives the reason for the warning or message email. The possible values that it takes and their meanings are: .nf .fi \fIEmailTest\fP: this is an email test message. .nf .fi \fIHealth\fP: the SMART health status indicates imminent failure. .nf .fi \fIUsage\fP: a usage Attribute has failed. .nf .fi \fISelfTest\fP: the number of self-test failures has increased. .nf .fi \fIErrorCount\fP: the number of errors in the ATA error log has increased. .nf .fi \fICurrentPendingSector\fP: one of more disk sectors could not be read and are marked to be reallocated (replaced with spare sectors). .nf .fi \fIOfflineUncorrectableSector\fP: during off-line testing, or self-testing, one or more disk sectors could not be read. .nf .fi \fITemperature\fP: Temperature reached critical limit (see \-W directive). .nf .fi \fIFailedHealthCheck\fP: the SMART health status command failed. .nf .fi \fIFailedReadSmartData\fP: the command to read SMART Attribute data failed. .nf .fi \fIFailedReadSmartErrorLog\fP: the command to read the SMART error log failed. .nf .fi \fIFailedReadSmartSelfTestLog\fP: the command to read the SMART self-test log failed. .nf .fi \fIFailedOpenDevice\fP: the open() command to the device failed. .IP \fBSMARTD_ADDRESS\fP 4 is determined by the address argument ADD of the \'\-m\' Directive. If ADD is \fB<nomailer>\fP, then \fBSMARTD_ADDRESS\fP is not set. Otherwise, it is set to the comma-separated-list of email addresses given by the argument ADD, with the commas replaced by spaces (example:admin@example.com root). If more than one email address is given, then this string will contain space characters and is NOT quoted, so to use it in a bash script you may want to enclose it in double quotes. .\" %IF OS Windows .IP \fBSMARTD_ADDRCSV\fP 4 [Windows only] is set to a comma-separated list of the addresses from SMARTD_ADDRESS. .\" %ENDIF OS Windows .IP \fBSMARTD_MESSAGE\fP 4 is set to the one sentence summary warning email message string from \fBsmartd\fP. This message string contains space characters and is NOT quoted. So to use $SMARTD_MESSAGE in a bash script you should probably enclose it in double quotes. .\" %IF NOT OS Windows .IP \fBSMARTD_FULLMESSAGE\fP 4 is set to the contents of the entire email warning message string from \fBsmartd\fP. This message string contains space and return characters and is NOT quoted. So to use $SMARTD_FULLMESSAGE in a bash script you should probably enclose it in double quotes. .\" %ENDIF NOT OS Windows .\" %IF OS Windows .IP \fBSMARTD_FULLMSGFILE\fP 4 [Windows only] is the path to a temporary file containing the full message. The path may contain space characters and is NOT quoted. The file is created by the smartd_warning.cmd script and removed when the mailer or command exits. .\" %ENDIF OS Windows .IP \fBSMARTD_TFIRST\fP 4 is a text string giving the time and date at which the first problem of this type was reported. This text string contains space characters and no newlines, and is NOT quoted. For example: .nf .fi Sun Feb 9 14:58:19 2003 CST .IP \fBSMARTD_TFIRSTEPOCH\fP 4 is an integer, which is the unix epoch (number of seconds since Jan 1, 1970) for \fBSMARTD_TFIRST\fP. .IP \fBSMARTD_PREVCNT\fP 4 is an integer specifying the number of previous messages sent. It is set to \'0\' for the first message. .IP \fBSMARTD_NEXTDAYS\fP 4 is an integer specifying the number of days until the next message will be sent. It it set to empty on \'\-M once\' and set to \'1\' on \'\-M daily\'. .RE .\" The following two lines are a workaround for a man2html bug. Please leave them. .\" They define a non-existent option; useful because man2html can't correctly reset the margins. .TP .B \& The shell which is used to run PATH is system-dependent. For vanilla Linux/glibc it\'s bash. For other systems, the man page for \fBpopen\fP(3) should say what shell is used. If the \'\-m ADD\' Directive is given with a normal address argument, then the executable pointed to by PATH will be run in a shell with STDIN receiving the body of the email message, and with the same command-line arguments: .nf -s "$SMARTD_SUBJECT" $SMARTD_ADDRESS .fi that would normally be provided to \'mail\'. Examples include: .nf .B -m user@home -M exec /bin/mail .B -m admin@work -M exec /usr/local/bin/mailto .B -m root -M exec /Example_1/bash/script/below .fi .\" %IF OS Windows [Windows only] On Windows, the syntax of the \'\fBBlat\fP\' mailer is used: .nf - -q -subject "%SMARTD_SUBJECT%" -to %SMARTD_ADDRCSV% .fi .\" %ENDIF OS Windows If the \'\-m ADD\' Directive is given with the special address argument .B <nomailer> then the executable pointed to by PATH is run in a shell with .B no STDIN and .B no command-line arguments, for example: .nf .B -m <nomailer> -M exec /Example_2/bash/script/below .fi If the executable produces any STDERR/STDOUT output, then \fBsmartd\fP assumes that something is going wrong, and a snippet of that output will be copied to SYSLOG. The remainder of the output is then discarded. Some EXAMPLES of scripts that can be used with the \'\-M exec\' Directive are given below. .\" %IF NOT OS Windows Some sample scripts are also included in /usr/local/share/doc/smartmontools/examplescripts/. .\" %ENDIF NOT OS Windows [NEW EXPERIMENTAL SMARTD FEATURE] The executable is run by the script .\" %IF NOT OS Windows /usr/local/etc/smartd_warning.sh. .\" %ENDIF NOT OS Windows .\" %IF OS ALL (Windows: EXEDIR/smartd_warning.cmd) .\" %ENDIF OS ALL .\" %IF OS Windows .\"! EXEDIR/smartd_warning.cmd. .\" %ENDIF OS Windows This script formats subject and full message based on SMARTD_MESSAGE and other environment variables set by \fBsmartd\fP. The environment variables .\" %IF NOT OS Windows SMARTD_SUBJECT and SMARTD_FULLMESSAGE .\" %ENDIF NOT OS Windows .\" %IF OS ALL (Windows: SMARTD_SUBJECT, SMARTD_FULLMSGFILE and SMARTD_ADDRCSV) .\" %ENDIF OS ALL .\" %IF OS Windows .\"! SMARTD_SUBJECT, SMARTD_FULLMSGFILE and SMARTD_ADDRCSV .\" %ENDIF OS Windows are set by the script before running the executable. .TP .B \-f [ATA only] Check for \'failure\' of any Usage Attributes. If these Attributes are less than or equal to the threshold, it does NOT indicate imminent disk failure. It "indicates an advisory condition where the usage or age of the device has exceeded its intended design life period." [Please see the \fBsmartctl \-A\fP command-line option.] .TP .B \-p [ATA only] Report anytime that a Prefail Attribute has changed its value since the last check. [Please see the .B smartctl \-A command-line option.] .TP .B \-u [ATA only] Report anytime that a Usage Attribute has changed its value since the last check. [Please see the .B smartctl \-A command-line option.] .TP .B \-t [ATA only] Equivalent to turning on the two previous flags \'\-p\' and \'\-u\'. Tracks changes in \fIall\fP device Attributes (both Prefailure and Usage). [Please see the \fBsmartctl\fP \-A command-line option.] .TP .B \-i ID [ATA only] Ignore device Attribute number \fBID\fP when checking for failure of Usage Attributes. \fBID\fP must be a decimal integer in the range from 1 to 255. This Directive modifies the behavior of the \'\-f\' Directive and has no effect without it. This is useful, for example, if you have a very old disk and don\'t want to keep getting messages about the hours-on-lifetime Attribute (usually Attribute 9) failing. This Directive may appear multiple times for a single device, if you want to ignore multiple Attributes. .TP .B \-I ID [ATA only] Ignore device Attribute \fBID\fP when tracking changes in the Attribute values. \fBID\fP must be a decimal integer in the range from 1 to 255. This Directive modifies the behavior of the \'\-p\', \'\-u\', and \'\-t\' tracking Directives and has no effect without one of them. This is useful, for example, if one of the device Attributes is the disk temperature (usually Attribute 194 or 231). It\'s annoying to get reports each time the temperature changes. This Directive may appear multiple times for a single device, if you want to ignore multiple Attributes. .TP .B \-r ID[!] [ATA only] When tracking, report the \fIRaw\fP value of Attribute \fBID\fP along with its (normally reported) \fINormalized\fP value. \fBID\fP must be a decimal integer in the range from 1 to 255. This Directive modifies the behavior of the \'\-p\', \'\-u\', and \'\-t\' tracking Directives and has no effect without one of them. This Directive may be given multiple times. A common use of this Directive is to track the device Temperature (often ID=194 or 231). If the optional flag \'!\' is appended, a change of the Normalized value is considered critical. The report will be logged as LOG_CRIT and a warning email will be sent if \'\-m\' is specified. .TP .B \-R ID[!] [ATA only] When tracking, report whenever the \fIRaw\fP value of Attribute \fBID\fP changes. (Normally \fBsmartd\fP only tracks/reports changes of the \fINormalized\fP Attribute values.) \fBID\fP must be a decimal integer in the range from 1 to 255. This Directive modifies the behavior of the \'\-p\', \'\-u\', and \'\-t\' tracking Directives and has no effect without one of them. This Directive may be given multiple times. If this Directive is given, it automatically implies the \'\-r\' Directive for the same Attribute, so that the Raw value of the Attribute is reported. A common use of this Directive is to track the device Temperature (often ID=194 or 231). It is also useful for understanding how different types of system behavior affects the values of certain Attributes. If the optional flag \'!\' is appended, a change of the Raw value is considered critical. The report will be logged as LOG_CRIT and a warning email will be sent if \'\-m\' is specified. An example is \'-R 5!\' to warn when new sectors are reallocated. .TP .B \-C ID[+] [ATA only] Report if the current number of pending sectors is non-zero. Here \fBID\fP is the id number of the Attribute whose raw value is the Current Pending Sector count. The allowed range of \fBID\fP is 0 to 255 inclusive. To turn off this reporting, use ID\ =\ 0. If the \fB\-C ID\fP option is not given, then it defaults to \fB\-C 197\fP (since Attribute 197 is generally used to monitor pending sectors). If the name of this Attribute is changed by a \'\-v 197,FORMAT,NAME\' directive, the default is changed to \fB\-C 0\fP. If \'+\' is specified, a report is only printed if the number of sectors has increased between two check cycles. Some disks do not reset this attribute when a bad sector is reallocated. See also \'\-v 197,increasing\' below. The warning email counter is reset if the number of pending sectors dropped to 0. This typically happens when all pending sectors have been reallocated or could be read again. A pending sector is a disk sector (containing 512 bytes of your data) which the device would like to mark as ``bad" and reallocate. Typically this is because your computer tried to read that sector, and the read failed because the data on it has been corrupted and has inconsistent Error Checking and Correction (ECC) codes. This is important to know, because it means that there is some unreadable data on the disk. The problem of figuring out what file this data belongs to is operating system and file system specific. You can typically force the sector to reallocate by writing to it (translation: make the device substitute a spare good sector for the bad one) but at the price of losing the 512 bytes of data stored there. .TP .B \-U ID[+] [ATA only] Report if the number of offline uncorrectable sectors is non-zero. Here \fBID\fP is the id number of the Attribute whose raw value is the Offline Uncorrectable Sector count. The allowed range of \fBID\fP is 0 to 255 inclusive. To turn off this reporting, use ID\ =\ 0. If the \fB\-U ID\fP option is not given, then it defaults to \fB\-U 198\fP (since Attribute 198 is generally used to monitor offline uncorrectable sectors). If the name of this Attribute is changed by a \'\-v 198,FORMAT,NAME\' (except \'\-v 198,FORMAT,Offline_Scan_UNC_SectCt\'), directive, the default is changed to \fB\-U 0\fP. If \'+\' is specified, a report is only printed if the number of sectors has increased since the last check cycle. Some disks do not reset this attribute when a bad sector is reallocated. See also \'\-v 198,increasing\' below. The warning email counter is reset if the number of offline uncorrectable sectors dropped to 0. This typically happens when all offline uncorrectable sectors have been reallocated or could be read again. An offline uncorrectable sector is a disk sector which was not readable during an off-line scan or a self-test. This is important to know, because if you have data stored in this disk sector, and you need to read it, the read will fail. Please see the previous \'\-C\' option for more details. .TP .B \-W DIFF[,INFO[,CRIT]] Report if the current temperature had changed by at least \fBDIFF\fP degrees since last report, or if new min or max temperature is detected. Report or Warn if the temperature is greater or equal than one of \fBINFO\fP or \fBCRIT\fP degrees Celsius. If the limit \fBCRIT\fP is reached, a message with loglevel \fB\'LOG_CRIT\'\fP will be logged to syslog and a warning email will be send if \'\-m\' is specified. If only the limit \fBINFO\fP is reached, a message with loglevel \fB\'LOG_INFO\'\fP will be logged. The warning email counter is reset if the temperature dropped below \fBINFO\fP or \fBCRIT\fP-5 if \fBINFO\fP is not specified. If this directive is used in conjunction with state persistence (\'\-s\' option), the min and max temperature values are preserved across boot cycles. The minimum temperature value is not updated during the first 30 minutes after startup. To disable any of the 3 reports, set the corresponding limit to 0. Trailing zero arguments may be omitted. By default, all temperature reports are disabled (\'-W 0\'). To track temperature changes of at least 2 degrees, use: .nf .B \-W 2 .fi To log informal messages on temperatures of at least 40 degrees, use: .nf .B \-W 0,40 .fi For warning messages/mails on temperatures of at least 45 degrees, use: .nf .B \-W 0,0,45 .fi To combine all of the above reports, use: .nf .B \-W 2,40,45 .fi For ATA devices, smartd interprets Attribute 194 or 190 as Temperature Celsius by default. This can be changed to Attribute 9 or 220 by the drive database or by the \'\-v 9,temp\' or \'\-v 220,temp\' directive. .TP .B \-F TYPE [ATA only] Modifies the behavior of \fBsmartd\fP to compensate for some known and understood device firmware bug. This directive may be used multiple times. The valid arguments are: .I none \- Assume that the device firmware obeys the ATA specifications. This is the default, unless the device has presets for \'\-F\' in the drive database. Using this directive will over-ride any preset values. .I nologdir \- Suppresses read attempts of SMART or GP Log Directory. Support for all standard logs is assumed without an actual check. Some Intel SSDs may freeze if log address 0 is read. .I samsung \- In some Samsung disks (example: model SV4012H Firmware Version: RM100-08) some of the two- and four-byte quantities in the SMART data structures are byte-swapped (relative to the ATA specification). Enabling this option tells \fBsmartd\fP to evaluate these quantities in byte-reversed order. Some signs that your disk needs this option are (1) no self-test log printed, even though you have run self-tests; (2) very large numbers of ATA errors reported in the ATA error log; (3) strange and impossible values for the ATA error log timestamps. .I samsung2 \- In some Samsung disks the number of ATA errors reported is byte swapped. Enabling this option tells \fBsmartd\fP to evaluate this quantity in byte-reversed order. .I samsung3 \- Some Samsung disks (at least SP2514N with Firmware VF100-37) report a self-test still in progress with 0% remaining when the test was already completed. If this directive is specified, \fBsmartd\fP will not skip the next scheduled self-test (see Directive \'\-s\' above) in this case. .I xerrorlba \- This only affects \fBsmartctl\fP. [Please see the \fBsmartctl \-F\fP command-line option.] .TP .B \-v ID,FORMAT[:BYTEORDER][,NAME] [ATA only] Sets a vendor-specific raw value print FORMAT, an optional BYTEORDER and an optional NAME for Attribute ID. This directive may be used multiple times. Please see \fBsmartctl -v\fP command-line option for further details. The following arguments affect smartd warning output: .I 197,increasing \- Raw Attribute number 197 (Current Pending Sector Count) is not reset if uncorrectable sectors are reallocated. This sets \'-C 197+\' if no other \'-C\' directive is specified. .I 198,increasing \- Raw Attribute number 198 (Offline Uncorrectable Sector Count) is not reset if uncorrectable sector are reallocated. This sets \'-U 198+\' if no other \'-U\' directive is specified. .TP .B \-P TYPE [ATA only] Specifies whether \fBsmartd\fP should use any preset options that are available for this drive. The valid arguments to this Directive are: .I use \- use any presets that are available for this drive. This is the default. .I ignore \- do not use any presets for this drive. .I show \- show the presets listed for this drive in the database. .I showall \- show the presets that are available for all drives and then exit. [Please see the .B smartctl \-P command-line option.] .TP .B \-a Equivalent to turning on all of the following Directives: .B \'\-H\' to check the SMART health status, .B \'\-f\' to report failures of Usage (rather than Prefail) Attributes, .B \'\-t\' to track changes in both Prefailure and Usage Attributes, .B \'\-l\ error\' to report increases in the number of ATA errors, .B \'\-l\ selftest\' to report increases in the number of Self-Test Log errors, .B \'\-l\ selfteststs\' to report changes of Self-Test execution status, .B \'\-C 197\' to report nonzero values of the current pending sector count, and .B \'\-U 198\' to report nonzero values of the offline pending sector count. Note that \-a is the default for ATA devices. If none of these other Directives is given, then \-a is assumed. .TP .B # Comment: ignore the remainder of the line. .TP .B \e Continuation character: if this is the last non-white or non-comment character on a line, then the following line is a continuation of the current one. .PP If you are not sure which Directives to use, I suggest experimenting for a few minutes with .B smartctl to see what SMART functionality your disk(s) support(s). If you do not like voluminous syslog messages, a good choice of \fBsmartd\fP configuration file Directives might be: .nf .B \-H \-l\ selftest \-l\ error \-f. .fi If you want more frequent information, use: .B -a. .TP .B ADDITIONAL DETAILS ABOUT DEVICESCAN If a non-comment entry in the configuration file is the text string \fBDEVICESCAN\fP in capital letters, then \fBsmartd\fP will ignore any remaining lines in the configuration file, and will scan for devices (see also \fBsmartd\fP(8) man page). If \fBDEVICESCAN\fP is not followed by any Directives, then smartd will scan for both ATA and SCSI devices, and will monitor all possible SMART properties of any devices that are found. \fBDEVICESCAN\fP may optionally be followed by any valid Directives, which will be applied to all devices that are found in the scan. For example .nf .B DEVICESCAN -m root@example.com .fi will scan for all devices, and then monitor them. It will send one email warning per device for any problems that are found. .nf .B DEVICESCAN -d ata -m root@example.com .fi will do the same, but restricts the scan to ATA devices only. .nf .B DEVICESCAN -H -d ata -m root@example.com .fi will do the same, but only monitors the SMART health status of the devices, (rather than the default \-a, which monitors all SMART properties). [NEW EXPERIMENTAL SMARTD FEATURE] Configuration entries for specific devices may precede the \fBDEVICESCAN\fP entry. For example .nf .B DEFAULT -m root@example.com .B /dev/sda -s S/../.././02 .B /dev/sdc -d ignore .B DEVICESCAN -s L/../.././02 .fi will scan for all devices except /dev/sda and /dev/sdc, monitor them, and run a long test between 2-3am every morning. Device /dev/sda will also be monitored, but only a short test will be run. Device /dev/sdc will be ignored. Warning emails will be sent for all monitored devices. .TP .B EXAMPLES OF SHELL SCRIPTS FOR \'\-M exec\' These are two examples of shell scripts that can be used with the \'\-M exec PATH\' Directive described previously. The paths to these scripts and similar executables is the PATH argument to the \'\-M exec PATH\' Directive. Example 1: This script is for use with \'\-m ADDRESS -M exec PATH\'. It appends the output of .B smartctl -a to the output of the smartd email warning message and sends it to ADDRESS. .nf \fB #! /bin/bash # Save the email message (STDIN) to a file: cat > /root/msg # Append the output of smartctl -a to the message: /usr/local/sbin/smartctl -a -d $SMART_DEVICETYPE $SMARTD_DEVICE >> /root/msg # Now email the message to the user at address ADD: /bin/mail -s "$SMARTD_SUBJECT" $SMARTD_ADDRESS < /root/msg \fP .fi Example 2: This script is for use with \'\-m <nomailer> \-M exec PATH\'. It warns all users about a disk problem, waits 30 seconds, and then powers down the machine. .nf \fB #! /bin/bash # Warn all users of a problem wall \'Problem detected with disk: \' "$SMARTD_DEVICESTRING" wall \'Warning message from smartd is: \' "$SMARTD_MESSAGE" wall \'Shutting down machine in 30 seconds... \' # Wait half a minute sleep 30 # Power down the machine /sbin/shutdown -hf now \fP .fi Some example scripts are distributed with the smartmontools package, in /usr/local/share/doc/smartmontools/examplescripts/. Please note that these scripts typically run as root, so any files that they read/write should not be writable by ordinary users or reside in directories like /tmp that are writable by ordinary users and may expose your system to symlink attacks. As previously described, if the scripts write to STDOUT or STDERR, this is interpreted as indicating that there was an internal error within the script, and a snippet of STDOUT/STDERR is logged to SYSLOG. The remainder is flushed. .PP .SH AUTHORS \fBBruce Allen\fP .br University of Wisconsin \- Milwaukee Physics Department .br \fBChristian Franke\fP (Windows interface, C++ redesign, most enhancements since 2009) .br \fBsmartmontools\-support@lists.sourceforge.net\fP .PP .SH CONTRIBUTORS The following have made large contributions to smartmontools: .nf \fBCasper Dik\fP (Solaris SCSI interface) \fBDouglas Gilbert\fP (SCSI subsystem) \fBGuido Guenther\fP (Autoconf/Automake packaging) \fBGeoffrey Keating\fP (Darwin ATA interface) \fBEduard Martinescu\fP (FreeBSD interface) \fBFr\['e]d\['e]ric L. W. Meunier\fP (Web site and Mailing list) \fBGabriele Pohl\fP (Web site and Wiki, conversion from CVS to SVN) \fBKeiji Sawada\fP (Solaris ATA interface) \fBManfred Schwarb\fP (Drive database) \fBSergey Svishchev\fP (NetBSD interface) \fBDavid Snyder and Sergey Svishchev\fP (OpenBSD interface) \fBPhil Williams\fP (User interface and drive database) \fBShengfeng Zhou\fP (Linux/FreeBSD HighPoint RocketRAID interface) .fi Many other individuals have made smaller contributions and corrections. .PP .SH CREDITS .fi This code was derived from the smartsuite package, written by Michael Cornwell, and from the previous UCSC smartsuite package. It extends these to cover ATA-5 disks. This code was originally developed as a Senior Thesis by Michael Cornwell at the Concurrent Systems Laboratory (now part of the Storage Systems Research Center), Jack Baskin School of Engineering, University of California, Santa Cruz. \fBhttp://ssrc.soe.ucsc.edu/\fP . .SH HOME PAGE FOR SMARTMONTOOLS: .fi Please see the following web site for updates, further documentation, bug reports and patches: \fBhttp://smartmontools.sourceforge.net/\fP .SH SEE ALSO: \fBsmartd\fP(8), \fBsmartctl\fP(8), \fBsyslogd\fP(8), \fBsyslog.conf\fP(5), \fBbadblocks\fP(8), \fBide\-smart\fP(8), \fBregex\fP(7). .SH SVN ID OF THIS PAGE: $Id: smartd.conf.5.in 3833 2013-07-20 15:00:04Z chrfranke $ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/Makefile.am����������������������������������������������������������0000644�0000000�0000000�00000062537�12101043146�017122� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������## Process this file with automake to produce Makefile.in # # $Id: Makefile.am 3759 2013-01-26 21:11:02Z chrfranke $ # @SET_MAKE@ ACLOCAL_AMFLAGS = -I m4 # Make sure .cpp takes precedence to avoid compiling old .c file SUFFIXES = .cpp .c .s .o # BUILD_INFO can be provided by package maintainers (see INSTALL file) BUILD_INFO= "(local build)" AM_CPPFLAGS = -DBUILD_INFO='$(BUILD_INFO)' -DSMARTMONTOOLS_SYSCONFDIR='"$(sysconfdir)"' if ENABLE_DRIVEDB AM_CPPFLAGS += -DSMARTMONTOOLS_DRIVEDBDIR='"$(drivedbdir)"' endif if ENABLE_SAVESTATES AM_CPPFLAGS += -DSMARTMONTOOLS_SAVESTATES='"$(savestates)"' endif if ENABLE_ATTRIBUTELOG AM_CPPFLAGS += -DSMARTMONTOOLS_ATTRIBUTELOG='"$(attributelog)"' endif if OS_WIN32_MINGW AM_CPPFLAGS += -I$(srcdir)/os_win32 endif if NEED_GETOPT_LONG AM_CPPFLAGS += -I$(srcdir)/getopt -DHAVE_GETOPT_LONG -D__GNU_LIBRARY__ endif if NEED_REGEX AM_CPPFLAGS += -I$(srcdir)/regex endif sbin_PROGRAMS = \ smartctl \ smartd if ENABLE_DRIVEDB if OS_WIN32_MINGW else sbin_SCRIPTS = update-smart-drivedb endif endif smartctl_SOURCES = \ smartctl.cpp \ smartctl.h \ atacmdnames.cpp \ atacmdnames.h \ atacmds.cpp \ atacmds.h \ ataidentify.cpp \ ataidentify.h \ ataprint.cpp \ ataprint.h \ dev_ata_cmd_set.cpp \ dev_ata_cmd_set.h \ dev_interface.cpp \ dev_interface.h \ dev_tunnelled.h \ drivedb.h \ int64.h \ knowndrives.cpp \ knowndrives.h \ scsicmds.cpp \ scsicmds.h \ scsiata.cpp \ scsiprint.cpp \ scsiprint.h \ utility.cpp \ utility.h smartctl_LDADD = @os_deps@ @os_libs@ smartctl_DEPENDENCIES = @os_deps@ EXTRA_smartctl_SOURCES = \ os_darwin.cpp \ os_darwin.h \ os_linux.cpp \ os_linux.h \ os_freebsd.cpp \ os_freebsd.h \ os_netbsd.cpp \ os_netbsd.h \ os_openbsd.cpp \ os_openbsd.h \ os_qnxnto.cpp \ os_qnxnto.h \ os_solaris.cpp \ os_solaris.h \ os_solaris_ata.s \ os_win32.cpp \ os_generic.cpp \ os_generic.h \ cciss.cpp \ cciss.h \ cissio_freebsd.h \ dev_areca.cpp \ dev_areca.h \ dev_legacy.cpp \ megaraid.h if OS_WIN32_MINGW smartctl_LDADD += smartctl_res.o smartctl_DEPENDENCIES += smartctl_res.o endif smartd_SOURCES = \ smartd.cpp \ atacmdnames.cpp \ atacmdnames.h \ atacmds.cpp \ atacmds.h \ dev_ata_cmd_set.cpp \ dev_ata_cmd_set.h \ dev_interface.cpp \ dev_interface.h \ dev_tunnelled.h \ drivedb.h \ int64.h \ knowndrives.cpp \ knowndrives.h \ scsicmds.cpp \ scsicmds.h \ scsiata.cpp \ utility.cpp \ utility.h smartd_LDADD = @os_deps@ @os_libs@ @CAPNG_LDADD@ smartd_DEPENDENCIES = @os_deps@ EXTRA_smartd_SOURCES = \ os_darwin.cpp \ os_darwin.h \ os_linux.cpp \ os_linux.h \ os_freebsd.cpp \ os_freebsd.h \ os_netbsd.cpp \ os_netbsd.h \ os_openbsd.cpp \ os_openbsd.h \ os_qnxnto.cpp \ os_qnxnto.h \ os_solaris.cpp \ os_solaris.h \ os_solaris_ata.s \ os_win32.cpp \ os_generic.cpp \ os_generic.h \ cciss.cpp \ cciss.h \ cissio_freebsd.h \ dev_areca.cpp \ dev_areca.h \ dev_legacy.cpp \ megaraid.h if OS_WIN32_MINGW smartd_SOURCES += \ os_win32/daemon_win32.cpp \ os_win32/daemon_win32.h \ os_win32/syslog_win32.cpp \ os_win32/syslog.h smartd_LDADD += smartd_res.o smartd_DEPENDENCIES += smartd_res.o endif if NEED_GETOPT_LONG smartctl_SOURCES += \ getopt/getopt.c \ getopt/getopt.h \ getopt/getopt1.c smartd_SOURCES += \ getopt/getopt.c \ getopt/getopt.h \ getopt/getopt1.c endif if NEED_REGEX smartctl_SOURCES += \ regex/regex.c \ regex/regex.h \ regex/regex_internal.h smartd_SOURCES += \ regex/regex.c \ regex/regex.h \ regex/regex_internal.h # Included by regex.c: EXTRA_smartctl_SOURCES += \ regex/regcomp.c \ regex/regexec.c \ regex/regex_internal.c EXTRA_smartd_SOURCES += \ regex/regcomp.c \ regex/regexec.c \ regex/regex_internal.c endif if OS_WIN32 smartctl_SOURCES += \ csmisas.h \ os_win32/wmiquery.cpp \ os_win32/wmiquery.h smartd_SOURCES += \ csmisas.h \ os_win32/wmiquery.cpp \ os_win32/wmiquery.h smartctl_LDADD += -lole32 -loleaut32 smartd_LDADD += -lole32 -loleaut32 endif if OS_SOLARIS # This block is required because Solaris uses manual page section 1m # for administrative command (linux/freebsd use section 8) and Solaris # uses manual page section 4 for file formats (linux/freebsd use # section 5). Automake can deal cleanly with man page sections 1-8 # and n, but NOT with sections of the form 1m. extra_MANS = smartd.conf.4 \ smartctl.1m \ smartd.1m install-man: $(extra_MANS) @$(NORMAL_INSTALL) $(mkinstalldirs) $(DESTDIR)$(mandir)/man4 $(mkinstalldirs) $(DESTDIR)$(mandir)/man1m for i in $(extra_MANS); do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$$ext/$$inst"; \ $(INSTALL_DATA) $$file $(DESTDIR)$(mandir)/man$$ext/$$inst; \ done uninstall-man: @$(NORMAL_UNINSTALL) for i in $(extra_MANS); do \ if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ else file=$$i; fi; \ ext=`echo $$i | sed -e 's/^.*\\.//'`; \ inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ inst=`echo $$inst | sed -e 's/^.*\///'`; \ inst=`echo $$inst | sed '$(transform)'`.$$ext; \ echo " rm -f $(DESTDIR)$(mandir)/man$$ext/$$inst"; \ rm -f $(DESTDIR)$(mandir)/man$$ext/$$inst; \ done %.1m: %.8 awk '/^.TH/ {$$3="1m"} {print}' < $< | \ sed -e 's/smartd\.conf\(.*\)(5)/smartd.conf\1(4)/g' \ -e 's/syslog\.conf\(.*\)(5)/syslog.conf\1(4)/g' \ -e 's/smartctl\(.*\)(8)/smartctl\1(1m)/g' \ -e 's/syslogd\(.*\)(8)/syslogd\1(1m)/g' \ -e 's|/var/log/messages|/var/adm/messages|g' \ -e 's/smartd\(.*\)(8)/smartd\1(1m)/g' > $@ %.4: %.5 awk '/^.TH/ {$$3="4"} {print}' < $< | \ sed -e 's/smartd\.conf\(.*\)(5)/smartd.conf\1(4)/g' \ -e 's/syslog\.conf\(.*\)(5)/syslog.conf\1(4)/g' \ -e 's/smartctl\(.*\)(8)/smartdctl\1(1m)/g' \ -e 's/syslogd\(.*\)(8)/syslogd\1(1m)/g' \ -e 's|/var/log/messages|/var/adm/messages|g' \ -e 's/smartd\(.*\)(8)/smartd\1(1m)/g' > $@ else # For systems that adopts traditional manner man_MANS = smartd.conf.5 \ smartctl.8 \ smartd.8 endif docsdir=$(docdir) docs_DATA = \ AUTHORS \ ChangeLog \ ChangeLog-5.0-6.0 \ COPYING \ INSTALL \ NEWS \ README \ TODO \ WARNINGS \ smartd.conf examplesdir=$(exampledir) examples_DATA = \ examplescripts/README examples_SCRIPTS = \ examplescripts/Example1 \ examplescripts/Example2 \ examplescripts/Example3 \ examplescripts/Example4 sysconf_DATA = smartd.conf # If modified smartd.conf exists install smartd.conf.sample instead install-sysconfDATA: $(sysconf_DATA) $(mkinstalldirs) $(DESTDIR)$(sysconfdir) @s="$(srcdir)/smartd.conf"; \ f="$(DESTDIR)$(sysconfdir)/smartd.conf$(smartd_suffix)"; \ if test -z "$(smartd_suffix)" && test -f "$$f"; then \ if cmp "$$s" "$$f" >/dev/null 2>/dev/null; then :; else \ echo "************************************************************"; \ echo "*** $$f preserved"; \ echo "*** installing smartd.conf.sample instead"; \ echo "************************************************************"; \ f="$$f".sample; \ fi; \ fi; \ echo " $(INSTALL_DATA) $$s $$f"; \ $(INSTALL_DATA) "$$s" "$$f" # If smartd.conf.sample exists preserve smartd.conf uninstall-sysconfDATA: @f="$(DESTDIR)$(sysconfdir)/smartd.conf$(smartd_suffix)"; \ if test -z "$(smartd_suffix)" && test -f "$$f".sample; then \ echo "************************************************************"; \ echo "*** $$f preserved"; \ echo "*** removing smartd.conf.sample instead"; \ echo "************************************************************"; \ f="$$f".sample; \ fi; \ echo " rm -f $$f"; \ rm -f "$$f" # automake does not allow 'sysconf_SCRIPTS' sysscriptdir = $(sysconfdir) sysscript_SCRIPTS = smartd_warning.sh EXTRA_DIST = \ autogen.sh \ smartd.initd.in \ smartd.freebsd.initd.in \ smartd.8.in \ smartctl.8.in \ smartd.conf.5.in \ smartd.conf \ smartd.service.in \ smartd_warning.sh.in \ update-smart-drivedb.in \ m4/pkg.m4 \ os_darwin/SMART.in \ os_darwin/StartupParameters.plist \ os_darwin/English_Localizable.strings \ os_win32/installer.nsi \ os_win32/runcmd.c \ os_win32/runcmda.exe.manifest \ os_win32/runcmdu.exe.manifest \ os_win32/smartctl_res.rc.in \ os_win32/smartd_res.rc.in \ os_win32/smartd_warning.cmd \ os_win32/syslogevt.mc \ os_win32/update-smart-drivedb.nsi \ os_win32/wbemcli_small.h \ os_win32/wtssendmsg.c \ $(docs_DATA) \ $(examples_DATA) \ $(examples_SCRIPTS) CLEANFILES = \ smartd.conf.5 \ smartd.conf.4 \ smartd.8 \ smartd.1m \ smartd.8.html \ smartd.8.txt \ smartctl.8 \ smartctl.1m \ smartctl.8.html \ smartctl.8.txt \ smartd.conf.5.html \ smartd.conf.5.txt \ smartd.initd \ smartd.freebsd.initd \ smartd.service \ smartd_warning.sh \ svnversion.h \ update-smart-drivedb \ SMART # 'make maintainer-clean' also removes files generated by './autogen.sh' MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in \ $(srcdir)/aclocal.m4 \ $(srcdir)/configure \ $(srcdir)/config.guess \ $(srcdir)/config.h.in \ $(srcdir)/config.h.in~ \ $(srcdir)/config.sub \ $(srcdir)/depcomp \ $(srcdir)/install-sh \ $(srcdir)/missing \ $(srcdir)/mkinstalldirs \ $(srcdir)/m4/pkg.m4 utility.o: svnversion.h if IS_SVN_BUILD # Get version info from SVN svnversion.h: ChangeLog Makefile $(svn_deps) echo '/* svnversion.h. Generated by Makefile from svn info. */' > $@ (cd $(srcdir) \ && svnversion 2>/dev/null | sed -n 's,^\([0-9].*\),REV "\1",p' \ && TZ= LC_ALL=C svn info 2>/dev/null \ | sed -n 'h;s,^.* Date: *\([^ ]*\) .*$$,DATE "\1",p;g;s,^.* Date: *[^ ]* *\([^ ]*\) .*$$,TIME "\1",p') \ | sed 's,^,#define SMARTMONTOOLS_SVN_,' >> $@ else # SVN not available, guess version info from Id strings svnversion.h: ChangeLog Makefile echo '/* svnversion.h. Generated by Makefile from Id strings. */' > $@ (cd $(srcdir) && cat ChangeLog Makefile.am configure.ac smart*.in *.cpp *.h *.s) \ | sed -n 's,^.*\$$[I][d]: [^ ]* \([0-9][0-9]* [0-9][-0-9]* [0-9][:0-9]*\)[^:0-9][^$$]*\$$.*$$,\1,p' \ | sort -n -r \ | sed -n 'h;s,^\([^ ]*\) .*$$,REV "\1",p;g;s,^[^ ]* \([^ ]*\) .*$$,DATE "\1",p;g;s,^[^ ]* [^ ]* \([^ ]*\)$$,TIME "\1",p;q' \ | sed 's,^,#define SMARTMONTOOLS_SVN_,' >> $@ endif if ENABLE_DRIVEDB drivedb_DATA = drivedb.h endif if ENABLE_SAVESTATES # Create $(savestatesdir) only savestates_DATA = endif if ENABLE_ATTRIBUTELOG # Create $(attributelogdir) only attributelog_DATA = endif update-smart-drivedb: update-smart-drivedb.in config.status $(SHELL) ./config.status --file=$@ chmod +x $@ smartd_warning.sh: smartd_warning.sh.in config.status $(SHELL) ./config.status --file=$@ chmod +x $@ if INSTALL_INITSCRIPT if OS_DARWIN initd_DATA = SMART \ os_darwin/StartupParameters.plist \ os_darwin/English_Localizable.strings initd_install_name = SMART initd_DATA_install = install-initdDATA-darwin initd_DATA_uninstall = uninstall-initdDATA-darwin SMART : os_darwin/SMART.in sed "s|/usr/sbin/|$(sbindir)/|" $< > $@ install-initdDATA-darwin: $(initd_DATA) $(mkinstalldirs) $(DESTDIR)$(initddir) $(mkinstalldirs) $(DESTDIR)$(initddir)/SMART $(mkinstalldirs) $(DESTDIR)$(initddir)/SMART/Resources $(INSTALL_SCRIPT) $(top_builddir)/SMART $(DESTDIR)$(initddir)/SMART $(INSTALL_DATA) $(srcdir)/os_darwin/StartupParameters.plist \ $(DESTDIR)$(initddir)/SMART/StartupParameters.plist for i in English ; do \ RDIR=$(DESTDIR)$(initddir)/SMART/Resources/$${i}.lproj ; \ $(mkinstalldirs) $$RDIR ;\ $(INSTALL_DATA) $(srcdir)/os_darwin/$${i}_Localizable.strings \ $$RDIR/Localizable.strings ; \ done uninstall-initdDATA-darwin: rm -rf $(DESTDIR)$(initddir)/$(initd_install_name) else initd_DATA = @initdfile@ @initdfile@: $(srcdir)/@initdfile@.in Makefile sed "s|/usr/local/sbin/|$(sbindir)/|g" $(srcdir)/@initdfile@.in > $@ initd_install_name = smartd$(smartd_suffix) initd_DATA_install = install-initdDATA-generic initd_DATA_uninstall = uninstall-initdDATA-generic install-initdDATA-generic: $(initd_DATA) $(mkinstalldirs) $(DESTDIR)$(initddir) $(INSTALL_SCRIPT) $(top_builddir)/@initdfile@ $(DESTDIR)$(initddir)/smartd$(smartd_suffix) uninstall-initdDATA-generic: rm -rf $(DESTDIR)$(initddir)/$(initd_install_name) endif else initd_DATA_install = install-initdDATA-null initd_DATA_uninstall = uninstall-initdDATA-null install-initdDATA-null: uninstall-initdDATA-null: endif install-initdDATA : $(initd_DATA_install) uninstall-initdDATA: $(initd_DATA_uninstall) if INSTALL_SYSTEMDUNIT systemdsystemunit_DATA = smartd.service endif smartd.service: smartd.service.in Makefile sed -e 's|/usr/local/sbin/smartd|$(sbindir)/smartd|g' \ -e 's|/usr/local/etc/sysconfig/smartmontools|$(sysconfdir)/sysconfig/smartmontools|g' \ $(srcdir)/smartd.service.in > $@ if ENABLE_CAPABILITIES MAN_CAPABILITIES = cat else MAN_CAPABILITIES = sed '/^\.\\" %IF ENABLE_CAPABILITIES/,/^\.\\" %ENDIF ENABLE_CAPABILITIES/ s,^,.\\"\# ,' endif if ENABLE_DRIVEDB MAN_DRIVEDB = sed "s|/usr/local/share/smartmontools/drivedb\\.h|$(drivedbdir)/drivedb.h|g" else MAN_DRIVEDB = sed '/^\.\\" %IF ENABLE_DRIVEDB/,/^\.\\" %ENDIF ENABLE_DRIVEDB/ s,^,.\\"\# ,' endif if ENABLE_SAVESTATES MAN_SAVESTATES = sed "s|/usr/local/var/lib/smartmontools/smartd\\.|$(savestates)|g" else MAN_SAVESTATES = sed '/^\.\\" %IF ENABLE_SAVESTATES/,/^\.\\" %ENDIF ENABLE_SAVESTATES/ s,^,.\\"\# ,' endif if ENABLE_ATTRIBUTELOG MAN_ATTRIBUTELOG = sed "s|/usr/local/var/lib/smartmontools/attrlog\\.|$(attributelog)|g" else MAN_ATTRIBUTELOG = sed '/^\.\\" %IF ENABLE_ATTRIBUTELOG/,/^\.\\" %ENDIF ENABLE_ATTRIBUTELOG/ s,^,.\\"\# ,' endif MAN_FILTER = \ sed -e 's|CURRENT_SVN_VERSION|$(releaseversion)|g' \ -e "s|CURRENT_SVN_DATE|`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`|g" \ -e "s|CURRENT_SVN_REV|`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h`|g" \ -e 's|/usr/local/share/man/|$(mandir)/|g' \ -e 's|/usr/local/sbin/|$(sbindir)/|g' \ -e 's|/usr/local/etc/rc\.d/init.d/|$(initddir)/|g' \ -e 's|/usr/local/share/doc/smartmontools/examplescripts/|!exampledir!|g' \ -e 's|/usr/local/share/doc/smartmontools/|$(docsdir)/|g' \ -e 's|!exampledir!|$(exampledir)/|g' \ -e 's|/usr/local/etc/smartd\.conf|$(sysconfdir)/smartd.conf|g' \ -e 's|/usr/local/etc/smartd_warning\.|$(sysconfdir)/smartd_warning.|g' \ -e 's|/usr/local/etc/smart_drivedb\.h|$(sysconfdir)/smart_drivedb.h|g' | \ $(MAN_ATTRIBUTELOG) | \ $(MAN_CAPABILITIES) | \ $(MAN_DRIVEDB) | \ $(MAN_SAVESTATES) | \ if test -n '$(os_man_filter)'; then \ sed -e 's,OS_MAN_FILTER,$(os_man_filter),g' \ -e '/^\.\\" %IF NOT OS .*$(os_man_filter)/,/^.\\" %ENDIF NOT OS .*$(os_man_filter)/ s,^,.\\"\# ,' \ -e '/^\.\\" %IF OS .*$(os_man_filter)/,/^\.\\" %ENDIF OS .*$(os_man_filter)/ s,^,!!,' \ -e '/^\.\\" %IF OS ./,/^\.\\" %ENDIF OS ./ s,^,.\\"\# ,' \ -e '/^!*\.\\" %IF NOT OS ./,/^!*\.\\" %ENDIF NOT OS ./ s,^,!!,' \ -e 's,^!!!*\.\\"! \(.*\)$$,\1 \\"\#,' \ -e 's,^!!!*,,' ; \ else \ cat; \ fi # Implicit rule 'smart%: smart%.in ...' does not work with BSD make smartctl.8: smartctl.8.in Makefile svnversion.h cat $(srcdir)/smartctl.8.in | $(MAN_FILTER) > $@ smartd.8: smartd.8.in Makefile svnversion.h cat $(srcdir)/smartd.8.in | $(MAN_FILTER) > $@ smartd.conf.5: smartd.conf.5.in Makefile svnversion.h cat $(srcdir)/smartd.conf.5.in | $(MAN_FILTER) > $@ # Commands to convert man pages into .html and .txt # TODO: configure MAN2HTML = man2html #MAN2HTML = groff -man -Thtml MAN2TXT = groff -man -Tascii -P'-bcou' # Remove HTTP header and fix links in man2html output FIXHTML = sed -e '1s,^Content-type.*,,' \ -e 's,<A HREF="[^"]*/man2html?\([1-8]\)+\(smart[cd][.a-z]*\)">,<A HREF="\2.\1.html">,g' \ -e 's,<A HREF="[^"]*/man2html">,<A HREF=".">,g' \ -e 's,<A HREF="[^"]*/man2html?[^"]*">\([^<]*\)</A>,\1,g' \ -e 's,<A HREF="mailto:[^s][^m][^a][^"]*">\([^<]*\)</A>,\1,g' # Convert man pages into .html and .txt htmlman: smartctl.8.html smartd.8.html smartd.conf.5.html txtman: smartctl.8.txt smartd.8.txt smartd.conf.5.txt if OS_WIN32_MINGW %.5.html: %.5 $(DOS2UNIX) < $< | $(MAN2HTML) | $(FIXHTML) > $@ %.8.html: %.8 $(DOS2UNIX) < $< | $(MAN2HTML) | $(FIXHTML) > $@ else %.5.html: %.5 $(MAN2HTML) $< | $(FIXHTML) > $@ %.8.html: %.8 $(MAN2HTML) $< | $(FIXHTML) > $@ endif %.5.txt: %.5 $(MAN2TXT) $< > $@ %.8.txt: %.8 $(MAN2TXT) $< > $@ # Check drive database syntax check: @if ./smartctl -B $(srcdir)/drivedb.h -P showall >/dev/null; then \ echo "$(srcdir)/drivedb.h: OK"; \ else \ echo "$(srcdir)/drivedb.h: Syntax check failed"; exit 1; \ fi if OS_WIN32_MINGW # Windows resources smartctl_res.o: smartctl_res.rc $(WINDRES) $< $@ smartd_res.o: smartd_res.rc syslogevt.rc $(WINDRES) -I. $< $@ # Convert version for VERSIONINFO resource: 6.1 r3754 -> 6.1.0.3754 WIN_RC_FILTER = \ ( ver=`echo '$(PACKAGE_VERSION).0' | sed -n 's,^\([0-9]*\.[0-9]*\.[0-9]*\).*$$,\1,p'`; \ rev=`sed -n 's,^.*REV[^"]*"\([0-9]*\).*$$,\1,p' svnversion.h`; \ txtver="$${ver:-0.0.0}.$${rev:-0}"; binver=`echo "$$txtver" | sed 's|\.|,|g'`; \ sed -e "s|@BINARY_VERSION@|$$binver|g" -e "s|@TEXT_VERSION@|$$txtver|g"; ) smartctl_res.rc: os_win32/smartctl_res.rc.in Makefile svnversion.h cat $< | $(WIN_RC_FILTER) > $@ smartd_res.rc: os_win32/smartd_res.rc.in Makefile svnversion.h cat $< | $(WIN_RC_FILTER) > $@ syslogevt.rc: os_win32/syslogevt.mc $(WINDMC) -b $< # Definitions for Windows distribution if OS_WIN64 win_bits = 64 else win_bits = 32 endif distdir_win32 = $(PACKAGE)-$(VERSION).win$(win_bits) distzip_win32 = $(PACKAGE)-$(VERSION).win$(win_bits).zip distinst_win32 = $(PACKAGE)-$(VERSION).win$(win_bits)-setup.exe exedir_win32 = $(distdir_win32)/bin docdir_win32 = $(distdir_win32)/doc EXEFILES_WIN32 = \ $(exedir_win32)/smartctl.exe \ $(exedir_win32)/smartctl-nc.exe \ $(exedir_win32)/smartd.exe \ $(exedir_win32)/smartd_warning.cmd \ $(exedir_win32)/runcmda.exe \ $(exedir_win32)/runcmdu.exe \ $(exedir_win32)/wtssendmsg.exe if ENABLE_DRIVEDB if OS_WIN32_NSIS EXEFILES_WIN32 += \ $(exedir_win32)/update-smart-drivedb.exe endif endif FILES_WIN32 = \ $(EXEFILES_WIN32) \ $(docdir_win32)/AUTHORS.txt \ $(docdir_win32)/ChangeLog.txt \ $(docdir_win32)/ChangeLog-5.0-6.0.txt \ $(docdir_win32)/COPYING.txt \ $(docdir_win32)/INSTALL.txt \ $(docdir_win32)/NEWS.txt \ $(docdir_win32)/README.txt \ $(docdir_win32)/TODO.txt \ $(docdir_win32)/WARNINGS.txt \ $(docdir_win32)/checksums$(win_bits).txt \ $(docdir_win32)/smartd.conf \ $(docdir_win32)/smartctl.8.html \ $(docdir_win32)/smartctl.8.txt \ $(docdir_win32)/smartd.8.html \ $(docdir_win32)/smartd.8.txt \ $(docdir_win32)/smartd.conf.5.html \ $(docdir_win32)/smartd.conf.5.txt \ $(exedir_win32)/runcmda.exe.manifest \ $(exedir_win32)/runcmdu.exe.manifest if ENABLE_DRIVEDB FILES_WIN32 += \ $(exedir_win32)/drivedb.h endif CLEANFILES += \ $(FILES_WIN32) \ runcmdu.exe \ smartctl-nc.exe smartctl-nc.exe.tmp \ smartctl_res.rc smartctl_res.o \ smartd_res.rc smartd_res.o \ syslogevt.h syslogevt.o \ syslogevt.rc syslogevt_*.bin \ wtssendmsg.exe \ update-smart-drivedb.exe \ distdir.mkdir # Textfile converter from package cygutils or tofrodos # Note: Only use without options to be compatible with both packages UNIX2DOS = unix2dos DOS2UNIX = dos2unix # Build Windows distribution dist-win32: $(distzip_win32) install-win32: $(distinst_win32) ./$(distinst_win32) installer-win32: $(distinst_win32) distdir-win32: distdir.mkdir $(FILES_WIN32) $(distzip_win32): distdir.mkdir $(FILES_WIN32) @rm -fv $(distzip_win32) cd $(distdir_win32) && zip -9 ../$(distzip_win32) bin/* doc/* md5sum $@ > $@.md5 sha1sum $@ > $@.sha1 sha256sum $@ > $@.sha256 if OS_WIN32_NSIS # Build NSIS installer # Note: Only option character '-' is also compatible with Linux version of makensis $(distinst_win32): os_win32/installer.nsi distdir.mkdir $(FILES_WIN32) test -z '$(builddir_win64)' || ( cd $(builddir_win64) && make distdir-win32 ) @date=`sed -n 's,^.*DATE[^"]*"\([^"]*\)".*$$,\1,p' svnversion.h`; \ rev=`sed -n 's,^.*REV[^"]*"\([^"]*\)".*$$,r\1,p' svnversion.h`; \ verstr="$(PACKAGE_VERSION) $$date $$rev "$(BUILD_INFO); \ d64=; test -z '$(builddir_win64)' || d64='-DINPDIR64=$(builddir_win64)/$(PACKAGE)-$(VERSION).win64'; \ echo "'$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR='$$verstr' $<"; \ '$(MAKENSIS)' -V2 -NOCD -DINPDIR=$(distdir_win32) $$d64 -DOUTFILE=$@ -DVERSTR="$$verstr" $< md5sum $@ > $@.md5 sha1sum $@ > $@.sha1 sha256sum $@ > $@.sha256 # Build drivedb.h update tool update-smart-drivedb.exe: os_win32/update-smart-drivedb.nsi "$(MAKENSIS)" -V2 -NOCD -DBRANCH=$(DRIVEDB_BRANCH) $< else $(distinst_win32): @echo "makensis: command not found. Please install NSIS from http://nsis.sourceforge.net/" 1>&2 @exit 1 endif cleandist-win32: rm -rf $(distdir_win32) distdir.mkdir distdir.mkdir: @test -d $(exedir_win32) || mkdir -pv $(exedir_win32) @test -d $(docdir_win32) || mkdir -pv $(docdir_win32) touch $@ $(exedir_win32)/%.exe: %.exe cp -p $< $@ if test -n '$(STRIP)'; then $(STRIP) -s $@; else strip -s $@; fi touch -r $< $@ # strip would break NSIS integrity check $(exedir_win32)/update-smart-drivedb.exe: update-smart-drivedb.exe cp -p $< $@ # runcmd?.exe only differ by .exe.manifest files $(exedir_win32)/runcmda.exe: $(exedir_win32)/runcmdu.exe cp -p $< $@ $(exedir_win32)/%.h: $(srcdir)/%.h $(UNIX2DOS) < $< > $@ touch -r $< $@ $(exedir_win32)/%.exe.manifest: $(srcdir)/os_win32/%.exe.manifest $(UNIX2DOS) < $< > $@ touch -r $< $@ $(exedir_win32)/%.cmd: $(srcdir)/os_win32/%.cmd $(UNIX2DOS) < $< > $@ touch -r $< $@ $(docdir_win32)/%.html: %.html $(UNIX2DOS) < $< > $@ touch -r $< $@ $(docdir_win32)/%.txt: %.txt $(UNIX2DOS) < $< > $@ touch -r $< $@ $(docdir_win32)/%.txt: $(srcdir)/% $(UNIX2DOS) < $< > $@ touch -r $< $@ $(docdir_win32)/%.conf: $(srcdir)/%.conf $(UNIX2DOS) < $< > $@ touch -r $< $@ $(docdir_win32)/checksums$(win_bits).txt: $(EXEFILES_WIN32) (cd $(exedir_win32) && md5sum *.exe && sha1sum *.exe && sha256sum *.exe) \ | $(UNIX2DOS) > $@ # Build non-console version of smartctl for GSmartControl. # The script below changes the word at offset 220 (Subsystem) from 3 # (Console) to 2 (GUI) in a copy of smartctl.exe. # This will be changed when a tool (like 'editbin') is available in # the Cygwin distribution smartctl-nc.exe: smartctl.exe @rm -f $@ cp -p smartctl.exe $@.tmp @if test `od -A n -j 220 -N 2 -d $@.tmp` -eq 3; then :; \ else echo "invalid EXE header"; exit 1; fi @echo "editbin /subsystem:windows $@.tmp" @echo -ne '\002' | dd bs=1 seek=220 count=1 conv=notrunc of=$@.tmp 2>/dev/null @if test `od -A n -j 220 -N 2 -d $@.tmp` -eq 2; then :; \ else echo "EXE patch failed"; exit 1; fi mv -f $@.tmp $@ # Build runcmd?.exe and wtssendmsg.exe runcmdu.exe: os_win32/runcmd.c $(CC) -Os -o $@ $< wtssendmsg.exe: os_win32/wtssendmsg.c $(CC) -Os -o $@ $< -lwtsapi32 # Build os_win32/vc10/{config.h,smart*.rc,svnversion.h} for MSVC10 from MinGW files config-vc10: $(srcdir)/os_win32/vc10/config.h \ $(srcdir)/os_win32/vc10/smartctl_res.rc \ $(srcdir)/os_win32/vc10/smartd_res.rc \ $(srcdir)/os_win32/vc10/svnversion.h $(srcdir)/os_win32/vc10/config.h: config.h Makefile sed -e '1i/* os_win32/vc10/config.h. Generated from config.h by Makefile. */' \ -e 's,^#define HAVE_\(ATTR_PACKED\|GETTIMEOFDAY\|INTTYPES_H\|[DK_]*NTDDDISK_H\|STRINGS_H\|STRTOULL\|UNISTD_H\|WORKING_SNPRINTF\) 1$$,/* #undef HAVE_\1 */,' \ -e 's,^\(#define SMARTMONTOOLS_BUILD_HOST "[^-]*\)[^"]*,\1-pc-w32vc10,' $< > $@ $(srcdir)/os_win32/vc10/svnversion.h: svnversion.h cp $< $@ $(srcdir)/os_win32/vc10/smartctl_res.rc: smartctl_res.rc cp $< $@ $(srcdir)/os_win32/vc10/smartd_res.rc: smartd_res.rc cp $< $@ endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_netbsd.h����������������������������������������������������������0000644�0000000�0000000�00000003071�12062413436�017214� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_netbsd.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 Sergey Svishchev <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef OS_NETBSD_H_ #define OS_NETBSD_H_ #define OS_NETBSD_H_CVSID "$Id: os_netbsd.h 3728 2012-12-13 17:57:50Z chrfranke $\n" #include <sys/device.h> #include <sys/param.h> #include <sys/sysctl.h> #include <sys/scsiio.h> #include <sys/ataio.h> #define ata_smart_selftestlog __netbsd_ata_smart_selftestlog #include <dev/ata/atareg.h> #if HAVE_DEV_ATA_ATAVAR_H #include <dev/ata/atavar.h> #endif #include <dev/ic/wdcreg.h> #undef ata_smart_selftestlog #include <err.h> #include <fcntl.h> #include <util.h> #ifndef WDSM_RD_THRESHOLDS /* pre-1.6.2 system */ #define WDSM_RD_THRESHOLDS 0xd1 #endif #ifndef WDSMART_CYL #define WDSMART_CYL 0xc24f #endif #endif /* OS_NETBSD_H_ */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/atacmdnames.cpp������������������������������������������������������0000644�0000000�0000000�00000035423�12044317622�020052� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * atacmdnames.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 Philip Williams * Copyright (C) 2012 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ #include "atacmdnames.h" #include <stdlib.h> #include <stdio.h> const char * atacmdnames_cpp_cvsid = "$Id: atacmdnames.cpp 3670 2012-10-31 22:00:50Z chrfranke $" ATACMDNAMES_H_CVSID; const char cmd_reserved[] = "[RESERVED]"; const char cmd_vendor_specific[] = "[VENDOR SPECIFIC]"; const char cmd_reserved_sa[] = "[RESERVED FOR SERIAL ATA]"; const char cmd_reserved_cf[] = "[RESERVED FOR COMPACTFLASH ASSOCIATION]"; const char cmd_reserved_mcpt[] = "[RESERVED FOR MEDIA CARD PASS THROUGH]"; // ACS-3: Reserved const char cmd_recalibrate_ret4[]= "RECALIBRATE [RET-4]"; const char cmd_seek_ret4[] = "SEEK [RET-4]"; // Tables B.3 and B.4 of T13/2161-D (ACS-3) Revision 4, September 4, 2012 const char * const command_table[] = { /*-------------------------------------------------- 00h-0Fh -----*/ "NOP", cmd_reserved, cmd_reserved, "CFA REQUEST EXTENDED ERROR", cmd_reserved, cmd_reserved, "DATA SET MANAGEMENT", // ACS-2 cmd_reserved, "DEVICE RESET", cmd_reserved, cmd_reserved, "REQUEST SENSE DATA EXT", // ACS-2 cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, /*-------------------------------------------------- 10h-1Fh -----*/ "RECALIBRATE [OBS-4]", cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, cmd_recalibrate_ret4, /*-------------------------------------------------- 20h-2Fh -----*/ "READ SECTOR(S)", "READ SECTOR(S) [OBS-5]", "READ LONG [OBS-4]", "READ LONG (w/o retry) [OBS-4]", "READ SECTOR(S) EXT", "READ DMA EXT", "READ DMA QUEUED EXT [OBS-ACS-2]", "READ NATIVE MAX ADDRESS EXT [OBS-ACS-3]", cmd_reserved, "READ MULTIPLE EXT", "READ STREAM DMA", "READ STREAM", cmd_reserved, cmd_reserved, cmd_reserved, "READ LOG EXT", /*-------------------------------------------------- 30h-3Fh -----*/ "WRITE SECTOR(S)", "WRITE SECTOR(S) (w/o retry) [OBS-5]", "WRITE LONG [OBS-4]", "WRITE LONG (w/o retry) [OBS-4]", "WRITE SECTORS(S) EXT", "WRITE DMA EXT", "WRITE DMA QUEUED EXT [OBS-ACS-2]", "SET NATIVE MAX ADDRESS EXT [OBS-ACS-3]", "CFA WRITE SECTORS WITHOUT ERASE", "WRITE MULTIPLE EXT", "WRITE STREAM DMA", "WRITE STREAM", "WRITE VERIFY [OBS-4]", "WRITE DMA FUA EXT", "WRITE DMA QUEUED FUA EXT [OBS-ACS-2]", "WRITE LOG EXT", /*-------------------------------------------------- 40h-4Fh -----*/ "READ VERIFY SECTOR(S)", "READ VERIFY SECTOR(S) (w/o retry) [OBS-5]", "READ VERIFY SECTOR(S) EXT", cmd_reserved, cmd_reserved, "WRITE UNCORRECTABLE EXT", // ATA-8 cmd_reserved, "READ LOG DMA EXT", // ATA-8 cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, /*-------------------------------------------------- 50h-5Fh -----*/ "FORMAT TRACK [OBS-4]", "CONFIGURE STREAM", cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, "WRITE LOG DMA EXT", // ATA-8 cmd_reserved, cmd_reserved, cmd_reserved, "TRUSTED NON-DATA", // ATA-8 "TRUSTED RECEIVE", // ATA-8 "TRUSTED RECEIVE DMA", // ATA-8 "TRUSTED SEND", // ATA-8 "TRUSTED SEND DMA", // ATA-8 /*-------------------------------------------------- 60h-6Fh -----*/ "READ FPDMA QUEUED", // ATA-8 "WRITE FPDMA QUEUED", // ATA-8 cmd_reserved_sa, "NCQ QUEUE MANAGEMENT", // ACS-3 "SEND FPDMA QUEUED", // ACS-3 "RECEIVE FPDMA QUEUED", // ACS-3 cmd_reserved_sa, cmd_reserved_sa, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, /*-------------------------------------------------- 70h-7Fh -----*/ "SEEK [OBS-7]", cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, "SET DATE & TIME EXT", // ACS-3 "ACCESSIBLE MAX ADDRESS CONFIGURATION", // ACS-3 cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, cmd_seek_ret4, /*-------------------------------------------------- 80h-8Fh -----*/ cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, "CFA TRANSLATE SECTOR [VS IF NO CFA]", cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, /*-------------------------------------------------- 90h-9Fh -----*/ "EXECUTE DEVICE DIAGNOSTIC", "INITIALIZE DEVICE PARAMETERS [OBS-6]", "DOWNLOAD MICROCODE", "DOWNLOAD MICROCODE DMA", // ACS-2 "STANDBY IMMEDIATE [RET-4]", "IDLE IMMEDIATE [RET-4]", "STANDBY [RET-4]", "IDLE [RET-4]", "CHECK POWER MODE [RET-4]", "SLEEP [RET-4]", cmd_vendor_specific, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, /*-------------------------------------------------- A0h-AFh -----*/ "PACKET", "IDENTIFY PACKET DEVICE", "SERVICE [OBS-ACS-2]", cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, /*-------------------------------------------------- B0h-BFh -----*/ "SMART", "DEVICE CONFIGURATION [OBS-ACS-3]", cmd_reserved, cmd_reserved, "SANITIZE DEVICE", // ACS-2 cmd_reserved, "NV CACHE [OBS-ACS-3]", // ATA-8 cmd_reserved_cf, cmd_reserved_cf, cmd_reserved_cf, cmd_reserved_cf, cmd_reserved_cf, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, /*-------------------------------------------------- C0h-CFh -----*/ "CFA ERASE SECTORS [VS IF NO CFA]", cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, "READ MULTIPLE", "WRITE MULTIPLE", "SET MULTIPLE MODE", "READ DMA QUEUED [OBS-ACS-2]", "READ DMA", "READ DMA (w/o retry) [OBS-5]", "WRITE DMA", "WRITE DMA (w/o retry) [OBS-5]", "WRITE DMA QUEUED [OBS-ACS-2]", "CFA WRITE MULTIPLE WITHOUT ERASE", "WRITE MULTIPLE FUA EXT", cmd_reserved, /*-------------------------------------------------- D0h-DFh -----*/ cmd_reserved, "CHECK MEDIA CARD TYPE [OBS-ACS-2]", cmd_reserved_mcpt, cmd_reserved_mcpt, cmd_reserved_mcpt, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, cmd_reserved, "GET MEDIA STATUS [OBS-8]", "ACKNOWLEDGE MEDIA CHANGE [RET-4]", "BOOT POST-BOOT [RET-4]", "BOOT PRE-BOOT [RET-4]", "MEDIA LOCK [OBS-8]", "MEDIA UNLOCK [OBS-8]", /*-------------------------------------------------- E0h-EFh -----*/ "STANDBY IMMEDIATE", "IDLE IMMEDIATE", "STANDBY", "IDLE", "READ BUFFER", "CHECK POWER MODE", "SLEEP", "FLUSH CACHE", "WRITE BUFFER", "READ BUFFER DMA", // ACS-2 (was: WRITE SAME [RET-4]) "FLUSH CACHE EXT", "WRITE BUFFER DMA", // ACS-2 "IDENTIFY DEVICE", "MEDIA EJECT [OBS-8]", "IDENTIFY DEVICE DMA [OBS-4]", "SET FEATURES", /*-------------------------------------------------- F0h-FFh -----*/ cmd_vendor_specific, "SECURITY SET PASSWORD", "SECURITY UNLOCK", "SECURITY ERASE PREPARE", "SECURITY ERASE UNIT", "SECURITY FREEZE LOCK", "SECURITY DISABLE PASSWORD", cmd_vendor_specific, "READ NATIVE MAX ADDRESS [OBS-ACS-3]", "SET MAX ADDRESS [OBS-ACS-3]", cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific, cmd_vendor_specific }; typedef char ASSERT_command_table_size[ sizeof(command_table)/sizeof(command_table[0]) == 256 ? 1 : -1]; /* Returns the name of the command (and possibly sub-command) with the given command code and feature register values. For most command codes this simply returns the corresponding entry in the command_table array, but for others the value of the feature register specifies a subcommand or distinguishes commands. */ const char *look_up_ata_command(unsigned char c_code, unsigned char f_reg) { switch (c_code) { case 0x00: /* NOP */ switch (f_reg) { case 0x00: return "NOP [Abort queued commands]"; case 0x01: return "NOP [Don't abort queued commands] [OBS-ACS-2]"; default: return "NOP [Reserved subcommand] [OBS-ACS-2]"; } case 0x92: /* DOWNLOAD MICROCODE */ switch (f_reg) { case 0x01: return "DOWNLOAD MICROCODE [Temporary] [OBS-8]"; case 0x03: return "DOWNLOAD MICROCODE [Save with offsets]"; // ATA-8 case 0x07: return "DOWNLOAD MICROCODE [Save]"; case 0x0e: return "DOWNLOAD MICROCODE [Save for future use]"; // ACS-3 case 0x0f: return "DOWNLOAD MICROCODE [Activate]"; // ACS-3 default: return "DOWNLOAD MICROCODE [Reserved subcommand]"; } case 0xB0: /* SMART */ switch (f_reg) { case 0xD0: return "SMART READ DATA"; case 0xD1: return "SMART READ ATTRIBUTE THRESHOLDS [OBS-4]"; case 0xD2: return "SMART ENABLE/DISABLE ATTRIBUTE AUTOSAVE"; case 0xD3: return "SMART SAVE ATTRIBUTE VALUES [OBS-6]"; case 0xD4: return "SMART EXECUTE OFF-LINE IMMEDIATE"; case 0xD5: return "SMART READ LOG"; case 0xD6: return "SMART WRITE LOG"; case 0xD7: return "SMART WRITE ATTRIBUTE THRESHOLDS [NS, OBS-4]"; case 0xD8: return "SMART ENABLE OPERATIONS"; case 0xD9: return "SMART DISABLE OPERATIONS"; case 0xDA: return "SMART RETURN STATUS"; case 0xDB: return "SMART EN/DISABLE AUTO OFFLINE [NS (SFF-8035i)]"; default: if (f_reg >= 0xE0) return "SMART [Vendor specific subcommand]"; else return "SMART [Reserved subcommand]"; } case 0xB1: /* DEVICE CONFIGURATION */ switch (f_reg) { case 0xC0: return "DEVICE CONFIGURATION RESTORE [OBS-ACS-3]"; case 0xC1: return "DEVICE CONFIGURATION FREEZE LOCK [OBS-ACS-3]"; case 0xC2: return "DEVICE CONFIGURATION IDENTIFY [OBS-ACS-3]"; case 0xC3: return "DEVICE CONFIGURATION SET [OBS-ACS-3]"; default: return "DEVICE CONFIGURATION [Reserved subcommand] [OBS-ACS-3]"; } case 0xEF: /* SET FEATURES */ switch (f_reg) { case 0x01: return "SET FEATURES [Enable 8-bit PIO] [OBS-3]"; // Now CFA case 0x02: return "SET FEATURES [Enable write cache]"; case 0x03: return "SET FEATURES [Set transfer mode]"; case 0x04: return "SET FEATURES [Enable auto DR] [OBS-4]"; case 0x05: return "SET FEATURES [Enable APM]"; case 0x06: return "SET FEATURES [Enable Pwr-Up In Standby]"; case 0x07: return "SET FEATURES [Set device spin-up]"; case 0x09: return "SET FEATURES [Reserved (address offset)] [OPS-ACS-3]"; case 0x0A: return "SET FEATURES [Enable CFA power mode 1]"; case 0x10: return "SET FEATURES [Enable SATA feature]"; // ACS-3 case 0x20: return "SET FEATURES [Set Time-ltd R/W WCT]"; case 0x21: return "SET FEATURES [Set Time-ltd R/W EH]"; case 0x31: return "SET FEATURES [Disable Media Status Notf] [OBS-8]"; case 0x33: return "SET FEATURES [Disable retry] [OBS-4]"; case 0x41: return "SET FEATURES [Enable Free-fall Control]"; // ATA-8 case 0x42: return "SET FEATURES [Enable AAM] [OBS-ACS-2]"; case 0x43: return "SET FEATURES [Set Max Host I/F S Times]"; case 0x44: return "SET FEATURES [Length of VS data] [OBS-4]"; case 0x4a: return "SET FEATURES [Ext. Power Conditions]"; // ACS-2 case 0x54: return "SET FEATURES [Set cache segs] [OBS-4]"; case 0x55: return "SET FEATURES [Disable read look-ahead]"; case 0x5D: return "SET FEATURES [Enable release interrupt] [OBS-ACS-2]"; case 0x5E: return "SET FEATURES [Enable SERVICE interrupt] [OBS-ACS-2]"; case 0x66: return "SET FEATURES [Disable revert defaults]"; case 0x69: return "SET FEATURES [LPS Error Reporting Control]"; // ACS-2 case 0x77: return "SET FEATURES [Disable ECC] [OBS-4]"; case 0x81: return "SET FEATURES [Disable 8-bit PIO] [OBS-3]"; // Now CFA case 0x82: return "SET FEATURES [Disable write cache]"; case 0x84: return "SET FEATURES [Disable auto DR] [OBS-4]"; case 0x85: return "SET FEATURES [Disable APM]"; case 0x86: return "SET FEATURES [Disable Pwr-Up In Standby]"; case 0x88: return "SET FEATURES [Disable ECC] [OBS-4]"; case 0x89: return "SET FEATURES [Reserved (address offset)]"; case 0x8A: return "SET FEATURES [Disable CFA power mode 1]"; case 0x90: return "SET FEATURES [Disable SATA feature]"; // ACS-3 case 0x95: return "SET FEATURES [Enable Media Status Notf] [OBS-8]"; case 0x99: return "SET FEATURES [Enable retries] [OBS-4]"; case 0x9A: return "SET FEATURES [Set max avg curr] [OBS-4]"; case 0xAA: return "SET FEATURES [Enable read look-ahead]"; case 0xAB: return "SET FEATURES [Set max prefetch] [OBS-4]"; case 0xBB: return "SET FEATURES [4 bytes VS data] [OBS-4]"; case 0xC1: return "SET FEATURES [Disable Free-fall Control]"; // ATA-8 case 0xC2: return "SET FEATURES [Disable AAM] [OBS-ACS-2]"; case 0xC3: return "SET FEATURES [Sense Data Reporting]"; // ACS-2 case 0xCC: return "SET FEATURES [Enable revert to defaults]"; case 0xDD: return "SET FEATURES [Disable release interrupt] [OBS-ACS-2]"; case 0xDE: return "SET FEATURES [Disable SERVICE interrupt] [OBS-ACS-2]"; case 0xE0: return "SET FEATURES [Vendor specific] [OBS-7]"; default: if (f_reg >= 0xF0) return "SET FEATURES [Reserved for CFA]"; else return "SET FEATURES [Reserved subcommand]"; } case 0xF9: /* SET MAX */ switch (f_reg) { case 0x00: return "SET MAX ADDRESS [OBS-6]"; case 0x01: return "SET MAX SET PASSWORD [OBS-ACS-3]"; case 0x02: return "SET MAX LOCK [OBS-ACS-3]"; case 0x03: return "SET MAX UNLOCK [OBS-ACS-3]"; case 0x04: return "SET MAX FREEZE LOCK [OBS-ACS-3]"; default: return "SET MAX [Reserved subcommand] [OBS-ACS-3]"; } default: return command_table[c_code]; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/autogen.sh�����������������������������������������������������������0000755�0000000�0000000�00000006530�12166553414�017075� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # $Id: autogen.sh 3829 2013-07-08 15:13:16Z samm2 $ # # Generate ./configure from config.in and Makefile.in from Makefile.am. # This also adds files like missing,depcomp,install-sh to the source # directory. To update these files at a later date use: # autoreconf -f -i -v # Cygwin? test -x /usr/bin/uname && /usr/bin/uname | grep -i CYGWIN >/dev/null && { # Check for Unix text file type echo > dostest.tmp test "`wc -c < dostest.tmp`" -eq 1 || echo "Warning: DOS text file type set, 'make dist' and related targets will not work." rm -f dostest.tmp } typep() { cmd=$1 ; TMP=$IFS ; IFS=: ; set $PATH for dir do if [ -x "$dir/$cmd" ]; then echo "$dir/$cmd" IFS=$TMP return 0 fi done IFS=$TMP return 1 } test -x "$AUTOMAKE" || AUTOMAKE=`typep automake-1.12` || AUTOMAKE=`typep automake-1.11` || AUTOMAKE=`typep automake-1.10` || AUTOMAKE=`typep automake-1.9` || AUTOMAKE=`typep automake-1.8` || AUTOMAKE=`typep automake-1.7` || AUTOMAKE=`typep automake17` || { echo echo "You must have at least GNU Automake 1.7 (up to 1.11) installed" echo "in order to bootstrap smartmontools from SVN. Download the" echo "appropriate package for your distribution, or the source tarball" echo "from ftp://ftp.gnu.org/gnu/automake/ ." echo echo "Also note that support for new Automake series (anything newer" echo "than 1.11) is only added after extensive tests. If you live in" echo "the bleeding edge, you should know what you're doing, mainly how" echo "to test it before the developers. Be patient." exit 1; } test -x "$ACLOCAL" || ACLOCAL="aclocal`echo "$AUTOMAKE" | sed 's/.*automake//'`" && ACLOCAL=`typep "$ACLOCAL"` || { echo echo "autogen.sh found automake-1.X, but not the respective aclocal-1.X." echo "Your installation of GNU Automake is broken or incomplete." exit 2; } # Detect Automake version case "$AUTOMAKE" in *automake-1.7|*automake17) ver=1.7 ;; *automake-1.8) ver=1.8 ;; *) ver="`$AUTOMAKE --version | sed -n '1s,^.*[^.0-9]\([12]\.[0-9][-.0-9pl]*\).*$,\1,p'`" ver="${ver:-?.?.?}" esac # Warn if Automake version was not tested or does not support filesystem case "$ver" in 1.[78]|1.[78].*) # Check for case sensitive filesystem # (to avoid e.g. "DIST_COMMON = ... ChangeLog ..." in Makefile.in on Cygwin) rm -f CASETEST.TMP echo > casetest.tmp test -f CASETEST.TMP && { echo "Warning: GNU Automake version ${ver} does not properly handle case" echo "insensitive filesystems. Some make targets may not work." } rm -f casetest.tmp ;; 1.9.[1-6]|1.10|1.10.[12]|1.11|1.11.[1-6]|1.12.[2-5]) # OK ;; *) echo "Note: GNU Automake version ${ver} was not tested by the developers." echo "Please report success/failure to the smartmontools-support mailing list." esac # Install pkg-config macros # (Don't use 'aclocal -I m4 --install' to keep support for automake < 1.10) test -d m4 || mkdir m4 || exit 1 test -f m4/pkg.m4 || acdir=`${ACLOCAL} --print-ac-dir` && test -n "$acdir" && test -f "$acdir/pkg.m4" && { echo "$0: installing \`m4/pkg.m4' from \`$acdir/pkg.m4'" cp "$acdir/pkg.m4" m4/pkg.m4 } test -f m4/pkg.m4 || echo "Warning: cannot install m4/pkg.m4, 'make dist' and systemd detection will not work." set -e # stops on error status ${ACLOCAL} -I m4 autoheader ${AUTOMAKE} --add-missing --copy autoconf ������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/NEWS�����������������������������������������������������������������0000644�0000000�0000000�00000056411�12174532061�015570� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools NEWS ------------------ $Id: NEWS 3841 2013-07-26 17:38:57Z chrfranke $ The most up-to-date version of this file is: http://sourceforge.net/p/smartmontools/code/HEAD/tree/trunk/smartmontools/NEWS Date 2013-07-26 Summary: smartmontools release 6.2 ----------------------------------------------------------- - smartctl: Added ATA write cache reordering control using '-g wcreorder' and '-s wcreorder,[on|off]' options. - update-smart-drivedb: Updated for new SVN repository. - HDD, SSD and USB additions to drive database. - Areca RAID support: Fixed possible segfault on empty port. - HPT RAID support: Maximum disk number increased to 128. - Linux: RHEL 9 compile fixes. - FreeBSD: Device scanning now skips port multipliers. - Cygwin: 64-bit compile fixes. - Windows: Fixed bogus temp file name in smartd_warning.cmd (already included in smartmontools-6.1-2.win32-setup.exe). - Windows: smartd service is no longer installed as interactive. Date 2013-03-16 Summary: smartmontools release 6.1 ----------------------------------------------------------- - smartctl '-l directory': improved output format. - smartctl: Fix parsing of '-l select,cont+SIZE' option. - smartctl prints ATA Additional Product Id (OEM Id). - smartctl '-s/-g wcache' for SCSI devices to control write cache. - smartctl '-s/-g rcache' for SCSI devices to control read cache. - smartctl prints more info for SCSI devices: media rotation rate, form factor, physical block size, lowest LBA alignement, logical block provisioning, disk protection type and selftest progress status. - smartctl '--identify' updated for latest ATA ACS-3 spec. - smartd runs /etc/smartd_warning.sh to generate warning emails (Windows: smartd_warning.cmd). - smartd '-w PATH' option to specify this executable. - smartd '-d ignore' directive. - smartd DEVICESCAN ignores devices already specified. - smartd: added support for state persistence ('-s') and attribute logging ('-A') for SCSI devices. - smartd '-W' directive uses ATA attribute 190 if 194 is missing. - Support of larger SCSI defect lists via READ DEFECT(12). - Device type '-d usbjmicron,p' for Prolific USB bridges. - Many HDD, SSD and USB additions to drive database. - Linux: Support for SAS disks behind Areca controllers. - Linux: Improved support for SATA disks on LSI/Megaraid controllers - Linux: disks on MegaRaid controllers are automatically scanned - FreeBSD: Support for SAS disks behind Areca controllers. - FreeBSD: Enhanced ATA command support for 3ware. - FreeBSD: Support for 3ware 9750 (/dev/twsX). - FreeBSD: Fixed support for 48-bit ATA commands on legacy controllers with ATACAM driver. - FreeBSD: Improved support for SAS/SCSI disks on LSI/Megaraid controllers. - Windows: smartd.conf '-M exec' supports path names with spaces. - Windows: Tool wtssendmsg.exe to handle smartd.conf '-m console'. - Windows: DEVICESCAN now supports up to 128 drives. - Windows: smartctl.exe and smartd.exe include VERSIONINFO resource. - Windows: smartd.exe includes MESSAGETABLE resource. - Windows: syslogevt.exe is no longer provided. Date 2012-10-10 Summary: smartmontools release 6.0 ----------------------------------------------------------- - option/directive '-F nologdir' and '-F xerrorlba'. - smartctl '--identify' option. - smartctl prints nominal media rotation rate (ATA). - smartctl prints SATA version and speed. - smartctl '-l sataphy' works for CD/DVD drives also. - smartctl '-x' includes ATA Device Statistics. - smartd warning emails include device identify info. - smartd '-d' output is flushed to support redirection. - HDD, SSD and USB additions to drive database. - Windows smartd: smartd.conf directives '-m console', '-m active', '-m connected'. - Windows: Support for SAS disks behind Areca controllers. - Windows: Win9x/ME and NT4 are no longer supported. Date 2012-06-30 Summary: smartmontools release 5.43 ----------------------------------------------------------- - smartctl options '-g, --get' and '-s, --set' to get/set various ATA settings: AAM, APM, Read look-ahead, Write cache, Security (freeze), Standby mode/timer. - smartd directive '-e' to set (most of) the above settings on startup. - smartctl options '-f hex' and '-f hex,[id|val]'. - smartctl does not start ATA self-test if another test is already running. Override with new option '-t force'. - smartctl supports extended self-test polling times greater than 255 minutes. - Controller-independent SAT detection: '-d sat,auto[+TYPE]'. - smartd.conf DEFAULT directive. - Many HDD, SSD and USB additions to drive database. - Linux and FreeBSD: Support for SATA disks behind Areca SAS RAID controllers and HP Smart Array controllers. - Windows: Support for SATA disks behind Areca controllers. - Windows smartd: directives '-l offlinests,ns' and '-l selfteststs,ns'. - Windows installer: Combined 32-/64-bit support. - FreeBSD: fixed crash on SCSI devices with FreeBSD9-RC1 Date 2011-10-20 Summary: smartmontools release 5.42 ----------------------------------------------------------- - smartctl option '-l devstat' (Device Statistics). - smartctl option '-l ssd' (SSD endurance indicator). - smartd logs identify information of each SCSI/SAS device. - smartd resends warning emails if problem reappears. - smartd directives '-l offlinests' and '-l selfteststs'. - Many HDD, SSD and USB additions to drive database. - Platform-specific man pages. - smartd.8 man page no longer includes smartd.conf.5. - FreeBSD: Compilation fixes. - FreeBSD: Support for Areca controllers. - FreeBSD: Fix '-l scterc' support. - FreeBSD: Support for 48-bit ATA commands. - Linux: Support for Areca controllers enhanced. - Windows installer: UAC support. - Windows: update-smart-drivedb /S(ilent) option. - Windows: improved USB ID detection. Date 2011-06-09 Summary: smartmontools release 5.41 ----------------------------------------------------------- - Failed self-tests outdated by a newer successful extended self-test are no longer reported as errors. - Support for ATA Long Logical/Physical Sectors (LLS/LPS). - 'smartctl --scan-open' can create a draft smartd.conf. - smartctl prints World Wide Name (WWN) of ATA device. - smartctl option '-f brief' to select new attribute output format which includes more flags and fits in 80 columns. - smartd logs identify information and WWN of each ATA device. - smartd logs warning from drive database if present. - smartd logs changes of offline data collection status. - smartd directive '-l scterc,READTIME,WRITETIME'. - smartd preserves last scheduled selective self-tests span. - 'smartd.service' file for systemd. - configure option '--with-systemdsystemunitdir' - configure option '--with-exampledir'. - configure searches for init.d or rc.d directory. - 'make install' does no longer overwrite an existing smartd.conf file. - 'update-smart-drivedb' does no longer require GNU sed. - Many HDD, SSD and USB additions to drive database. - Linux USB autodetection: Enable '-d sat,16' for newer kernels. - Linux megaraid: Fix segfault on non-data SCSI commands. - Linux megaraid: Fix pass-through of non-data ATA commands. - FreeBSD: Use 'fetch' in 'update-smart-drivedb'. - OpenBSD: Use 'ftp' in 'update-smart-drivedb'. - OpenBSD: Workaround for shell bug. - OpenBSD: Fix DEVICESCAN for OpenBSD >= 4.8. - Windows: Experimental support for Intel ICHxR RAID. - Windows: DEVICESCAN includes USB devices. - Windows: Faster USB ID detection. - Windows: update-smart-drivedb tool. - Windows installer: Option '/SO component,...'. - Windows: Fix smartd warning email truncation on Win7. - Windows installer: Fix shortcut removal on Vista/Win7. - Windows: Add missing quotes in smartctl-run.bat and smartd-run.bat Date 2010-10-16 Summary: smartmontools release 5.40 ----------------------------------------------------------- - Other config entries may precede smartd DEVICESCAN. - Option '-v' allows to specify byte order of attribute raw value - configure: New default value for '--with-docdir'. - configure: '--enable-drivedb' is now the default. - Improved support for Intel SSDs. - Improved support for SandForce based SSDs. - Drive database is in a separate source file 'drivedb.h' which can be downloaded from SVN. - USB ID info is now included in 'drivedb.h'. - Many additions to drive database. - New script 'update-smart-drivedb'. - smartd libcap-ng support, option '-C, --capabilities'. - smartd directive '-l xerror' to check Extended Comprehensive SMART Error Log. - smartctl option '-l scterc[,...]' to get/set the SCT Error Recovery Control time limit. - smartctl option '-t vendor,N'. - smartctl options '--scan, --scan-open'. - Linux: Add '/dev/sd[a-c][a-z]' to smartd DEVICESCAN. - Linux: Support SATA drives on LSI 3ware 9750 controllers. - Windows: Read 'drivedb.h' and 'smartd.conf' from exe directory. - Windows: Support for 64-bit executables. - Windows: Support for cross compilation on Linux. - Fix regression in smartctl option '-t select,M-N'. - Fix SCT temperature table commands on big endian CPUs. - Fix regression in smartd SMARTD_DEVICE and SMARTD_DEVICETYPE environment variables. Date 2010-01-28 Summary: smartmontools release 5.39.1 ----------------------------------------------------------- - Fix crash on kFreeBSD. - Fix regression in smartctl option '-q, --quietmode'. - Fix regression in smartd directive '-l selftest'. - Linux: Allow smartd 'DEVICESCAN -d sat'. - Linux: Fix spin-up of SATA drive if '-n standby' is used. - Windows: Fix parsing of 3ware 'tw_cli' output. Date 2009-12-09 Summary: smartmontools release 5.39 (UNSTABLE/EXPERIMENTAL) ----------------------------------------------------------- - Sourcecode repository moved from CVS to SVN - Support for USB devices with Cypress, JMicron and Sunplus USB bridges - USB device type autodetection for some devices on Linux, Windows and FreeBSD (http://sourceforge.net/apps/trac/smartmontools/wiki/Supported_USB-Devices) - Support for Areca controllers on Linux - Support for MegaRAID controllers on Linux - Support for HighPoint RocketRAID controllers on FreeBSD - Support RAID controllers using /dev/pass devices on FreeBSD - Support CHECK_POWER_MODE and WRITE_LOG on FreeBSD - Support for up to 128 devices on 3ware controllers - smartctl option '-l xerror' to print ATA SMART Extended Comprehensive Error Log - smartctl option '-l xselftest' to print ATA SMART Extended Self-test Log - smartctl option '-l sataphy' to print SATA Phy Event Counters - smartctl option '-l sasphy' to print SAS device phy information - smartctl options '-l gplog,...' and '-l smartlog,...' to print any log page - smartctl option '-x' to print all extended info if available - smartctl prints SCSI load/unload cycle counts - Improve display of huge raw values of some SMART attributes - Option '-d sat+TYPE' to use SAT with controllers which require '-d TYPE' - Option '-v ID,RAW_FORMAT,ATTR_NAME' to add new vendor specific attributes - Support for SSD drives using 64-bit raw attributes - Many additions to drive database - New simplified syntax for drive database - Option '-B FILE' to read drive database from a file - Configure option to add drive database file to distribution - smartd can now handle attributes 197 and 198 with increasing raw values - smartd logs changes of self-test execution status - smartd directive '-n powermode,N' to limit the number of skipped checks - smartd flag '!' for '-r' and '-R' directives to log changes as critical - smartd supports scheduled Selective Self-Tests - Self-tests scheduled during system downtime or disk standby are run after next startup - smartd option '-s PREFIX' to store smartd internal state until next startup - smartd option '-A PREFIX' to log attributes at each check cycle - Configure options to enable the above by default - Change to an object oriented interface to access ATA and SCSI devices - Linux, Win32 and FreeBSD modules migrated to new interface - Rework of smartd data structures - Checkin date and SVN revision and optional BUILD_INFO printed in version info - Better support for GSmartControl on Windows - SELinux fixes to 3ware device node creation - Fix CCISS file descriptor leak on FreeBSD - Compile fixes for Solaris and FreeBSD - Use getaddrinfo() instead of gethostbyname() to support IPv6 - C++ Support for QNX Target, already tested for QNX 6.3.2 on x86 and armle target - Additional support for Samsung MLC flash drives - New device type detection algorithm on FreeBSD, not based on filename - Support for the adaX (ATA on CAM bus) devices on FreeBSD 8.0 and higher Date 2008-03-10 Summary: smartmontools release 5.38 (STABLE) -------------------------------------------- This is a stable release of smartmontools. In addition to changes below, it includes: - Libata/Marvell driver devices no longer need explicit '-d' switch - DEVICESCAN automatically detects libata/marvell driver SATA devices - Fixed auto-offline/autosave support in FreeBSD - SAT device type + SCSI generic devices work properly with smartd under Linux - Many additions to drive database - More portable autogen/autoconf/automake script set - Additional Windows IOCTL route to access SMART data - Some ATA-8 updates - Smoother CCISS compilation support in Linux - Dragonfly support - Fixed some ATA identity byte swap problems on big endian CPUs - Added support for the QNX operating system - No-fork option added to smartd - Improved device scanning and drive type recognition in Windows - 3ware support for controllers with more disks (32 max) - Improved Windows installer - Improved SMART Attribute list and descriptions - Fix to smartctl return codes - Fix to scheduled tests on Highpoint RAID controllers - New samsung firmware bug workaround option - Auto-offline and Auto-save fixed in Linux + libata - Solaris: better SCSI support and support for Sun compilers AND gcc - Fixed and improvements to CCISS support - More options for SCSI temperature monitoring and history - Additional command line options for selective self-tests - Compilation fixes for various platforms. See CHANGELOG for more details, or smartmontools SVN for still further details. Date 2006-12-20 Summary: smartmontools release 5.37 (UNSTABLE/EXPERIMENTAL) ----------------------------------------------------------- This is an unstable/experimental release of smartmontools. It includes: - Many additions to the table of known drives - SAT (SCSI/ATA Translation) support - SCSI background scan results log - smartd -W directive for temperature tracking and warning - smartctl -n option to check power state - improved smartd power state logging - CCISS support under Linux - HighPoint RocketRAID support under Linux - 3ware RAID support under Windows - SPT interface for SCSI devices under Windows - ATA selective self test under Windows XP/2003 - NSIS installer support for Windows version - Started move from C to C++ - Various other improvements Date 2006-04-12 Summary: smartmontools release 5.36 (STABLE) ----------------------------------------------------------- This is a stable smartmontools release. The 5.34 version described just below was never officially released because Bruce Allen decided to wait until Linux support for accessing SATA devices through libata was in the official kernel.org sources. Changes include: - Win 2000/XP:ability to cancel drive self-tests - Additions to the table of known drives - FreeBSD support for 3ware char device interface and multiple 3ware cards - Various cygwin improvements for running as service - Works 'out of the box' with Linux SATA libata - smartd option added to list test schedules - smartctl option added to list part of drive database - various improvements for SCSI disks and logs Date 2005-04-19 Summary: smartmontools release 5.34 (STABLE) ----------------------------------------------------------- This is a stable smartmontools release. It includes: - OS/2 and eComStation support All Platforms: - Printing of drive family info - SCSI disks: output size of grown defect list - Added info about drive family to 'smartctl -i' output. - Added option ',q' for smartd '-n' directive to suppress 'skipping checks' message which may spin up laptop disk. - Added message if smartd '-n' check power mode spins up disk. Cygwin and Windows: - Added info about Windows version and service pack to banner line. - Added support for smartd '-n' directive for Win2000/XP. - Added support for READ_LOG for WinNT4 also. - Fixed bug that prevents display of empty logs on Win2000/XP - Fixed use of cached smart enabled state in 'smartctl -i' output. Windows: - Fixed bug that prevents running smartd as service on WinNT4. Date 2004-9-5 Summary: smartmontools release 5.33 (UNSTABLE/EXPERIMENTAL) ----------------------------------------------------------- This is an unstable/experimental release of smartmontools. It includes - support for Darwin/Mac OSX - support for OpenBSD - support for 3ware ATA RAID controllers under FreeBSD - support for 3ware 9500 series SATA RAID controllers under Linux. Use /dev/twa[0-15] devices to access these. - support for 3ware character device interfaces /dev/twe[0-15] under Linux. This allows (for example) Selective Self-tests. - support for Marvell chip-set based SATA controllers under Linux. - smartd mail now works also under Windows (using "Blat" mailer). - smartd can now be run as a Windows service. Please report sucess/failure with these items to the smartmontools-support mailing list. Date 2004-7-5 Summary: smartmontools release 5.32 (STABLE) ----------------------------------------------------------- This is an stable release of smartmontools. Note added 2004/7/7: users building a Solaris/Intel version of the code should modify the 'configure' file, changing "pc-*-solaris*" on line 106 to read "*-pc-solaris*". Reference: http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/configure.in?r1=1.83&r2=1.84 Date: 2004-5-4 Summary: smartmontools release 5.31 (UNSTABLE/EXPERIMENTAL) ----------------------------------------------------------- This is an unstable/experimental release of smartmontools. It includes several new features: - Windows smartd daemon - smartd now monitors current and pending sector counts - Support for ATA-7 selective self-test features (Linux/NetBSD only) Please report sucess/failure with this option to the smartmontools-support mailing list. Date: 2004-3-6 Summary: smartmontools release 5.30 (STABLE) -------------------------------------------- This is a stable release of smartmontools: the first stable release since 5.26. - KNOWN BUG (identified/fixed by CF): smartd will segv and crash if the configuration file /etc/smartd.conf contains NO valid entries. This bug was introduced in version 1.259 of smartd.c by BA and is present in smartmontools releases 5.27-5.30 inclusive. This can be fixed by editing line 3165 of smartd.c, and changing: "else if (cfgentries[0]) {" to read: "else if (cfgentries && cfgentries[0]) {" Date: 2004-2-24 Summary: smartmontools release 5.29 (Experimental, not STABLE) -------------------------------------------------------------- This is another experimental release, to replace the 5.27 release that had a damaged configure script. The next stable release will be 5.30 - This release has SCSI support for NetBSD Date: 2004-2-12 Summary: smartmontools release 5.27 (Experimental, not STABLE) -------------------------------------------------------------- - WARNING: this release has a broken --prefix=/a/path option to the configure script. The consequence is that smartd will not look for the configuration file (smartd.conf) at the desired location. - NetBSD support added - A new Directive (-s) for smartd.conf now enables flexible automatic scheduled self-testing for both ATA and SCSI devices. - Solaris now has ATA device support (SPARC only) - A new Directive (-n) for smartd.conf to avoid spinning up disks - Errors when smartd sends mail are now logged to SYSLOG - Solaris smartd mail now works correctly (uses mailx not mail) Date: 2003-11-29 Summary: smartmontools release 5.26 ----------------------------------- This is a stable smartmontools release. The only known problem is that under Solaris, the email features of smartd do not work 'out of the box'. Three workarounds are: [1] use '-M exec mailx' in /etc/smartd.conf [2] in the start script for smartd, put /usr/ucb into PATH before /bin [3] upgrade to release 5.27 or later, or the latest CVS snapshot Date: 2003-11-19 Summary: smartmontools release 5.25 ----------------------------------- This release should not hang when accessing USB devices. It provides smartd SCSI self-test log monitoring for self-test errors, and a larger table of known ATA drives. DEVICESCAN should work correctly even on file systems containing XFS or JFS partitions, and on machines that use devfs, even without traditional links. From this time on, even numbered releases will be 'stable' ones and odd numbered releases (like 5.25) will be unstable/testing/development releases. Date: 2003-10-30 Summary: smartmontools release 5.23 ----------------------------------- This release has one known problem: DEVICESCAN device scanning does not work correctly if the disk with the /dev directory also has XFS or JFS file systems on it. Date: 2003-10-28 Summary: smartmontools release 5.22 ----------------------------------- Replaces flawed 5.21 release: the -T verypermissive option had to be entered as -T verpermissive. First experimental solaris support (SCSI only). This release had a serious flaw: smartd left open file descriptors for devices that it couldn't monitor. Date: 2003-10-14 Summary: smartmontools release 5.21 ----------------------------------- Preliminary support for FreeBSD added to smartmontools. For FreeBSD, ATA support requires a 5.1-CURRENT kernel while SCSI support should work across multiple versions (any that support CAM). Date: 2003-10-04 Summary: smartmontools release 5.20 ----------------------------------- Replaces flawed 5.19 release (which had a zero-length man page smartd.conf.5). Date: 2003-10-03 Summary: smartmontools release 5.19 ----------------------------------- This is the first release of smartmontools based on autoconf/automake. For this reason, it is a very experimental release. Please let us know in particular about documenation errors/omissions, missing or unneccesary files, and similar oversights. The major changes are: [1] installation scripts based on autoconfig/automake [2] ./configure [options] lets you set arbitrary paths [3] supports FHS with ./configure --prefix=/usr/local [4] correct paths are inserted into all man pages, binaries, etc. [5] tarballs and RPMs are now GPG-signed Date: 2003-10-02 11:35 Summary: smartd SEGV -------------------- Some versions of smartd, including smartmontools release 5.1-18, will SEGV if the combination of Directives in /etc/smartd.conf contains -l error AND/OR -l selftest without any Attribute monitoring Directives. This is fixed in 5.19 and above. A good workaround is to add: -o on OR -o off to enable or disable automatic offline data collection. Date: 2002-11-17 07:41 Summary: testunitready bug in smartd ------------------------------------ A bug in smartd prevented functioning on scsi devices. The bug in question only affects smartd users with scsi devices. To see if your version of smartd has the testunitready() bug, do smartd -V If the version of the module smartd.c in a line like: Module: smartd.c revision: 1.66 date: 2002/11/17 has a revision greater than or equal to 1.30, and less than or equal to 1.64, then your version of the code has this problem. This problem affected releases starting with RELEASE_5_0_16 up to and including RELEASE_5_0_43. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartd.freebsd.initd.in����������������������������������������������0000644�0000000�0000000�00000002326�11725407075�021435� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # $FreeBSD: ports/sysutils/smartmontools/files/smartd.in,v 1.4 2012/02/15 08:46:57 dougb Exp $ # # PROVIDE: smartd # REQUIRE: LOGIN # KEYWORD: shutdown nojail # # Define these smartd_* variables in one of these files: # /etc/rc.conf # /etc/rc.conf.local # /etc/rc.conf.d/smartd # # DO NOT CHANGE THESE DEFAULT VALUES HERE . /etc/rc.subr name=smartd rcvar=smartd_enable load_rc_config smartd : ${smartd_enable:="NO"} required_files=${smartd_config:="/usr/local/etc/smartd.conf"} pidfile=${smartd_pidfile:="/var/run/smartd.pid"} command="/usr/local/sbin/smartd" command_args="-c ${required_files} -p ${pidfile}" extra_commands="reload report" reload_cmd="smartd_reload" report_cmd="smartd_report" start_precmd=smartd_prestart smartd_prestart() { case "${smartd_flags}" in -p*|*-p*) err 1 'smartd_flags includes the -p option, use smartd_pidfile instead' ;; esac } smartd_reload() { local status if ! status=`run_rc_command status 2>&1`; then echo $status return 1 fi echo 'Reloading smartd.' kill -HUP $rc_pid } smartd_report() { local status if ! status=`run_rc_command status 2>&1`; then echo $status return 1 fi echo 'Checking SMART devices now.' kill -USR1 $rc_pid } run_rc_command "$1" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartctl.8.in��������������������������������������������������������0000644�0000000�0000000�00000271300�12172521573�017420� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.ig Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net> $Id: smartctl.8.in 3832 2013-07-20 14:49:31Z chrfranke $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License (for example COPYING); If not, see <http://www.gnu.org/licenses/>. This code was originally developed as a Senior Thesis by Michael Cornwell 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 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .SH NAME \fBsmartctl\fP \- Control and Monitor Utility for SMART Disks .SH SYNOPSIS .B smartctl [options] device .\" %IF NOT OS Windows .SH FULL PATH .B /usr/local/sbin/smartctl .\" %ENDIF NOT OS Windows .SH PACKAGE VERSION CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV .SH DESCRIPTION .\" %IF NOT OS ALL .\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools. .\"! It does not contain info specific to other platforms.] .\"! .PP .\" %ENDIF NOT OS ALL \fBsmartctl\fP controls the Self-Monitoring, Analysis and Reporting Technology (SMART) system built into most ATA/SATA and SCSI/SAS hard drives and solid-state drives. The purpose of SMART is to monitor the reliability of the hard drive and predict drive failures, and to carry out different types of drive self-tests. \fBsmartctl\fP also supports some features not related to SMART. This version of \fBsmartctl\fP is compatible with ACS-2, ATA8-ACS, ATA/ATAPI-7 and earlier standards (see \fBREFERENCES\fP below). \fBsmartctl\fP also provides support for polling TapeAlert messages from SCSI tape drives and changers. The user must specify the device to be controlled or interrogated as the final argument to \fBsmartctl\fP. The command set used by the device is often derived from the device path but may need help with the \'\-d\' option (for more information see the section on "ATA, SCSI command sets and SAT" below). Device paths are as follows: .\" %IF OS Linux .IP \fBLINUX\fP: 9 Use the forms \fB"/dev/hd[a\-t]"\fP for IDE/ATA devices, and \fB"/dev/sd[a\-z]"\fP for SCSI devices. For SCSI Tape Drives and Changers with TapeAlert support use the devices \fB"/dev/nst*"\fP and \fB"/dev/sg*"\fP. For SATA disks accessed with libata, use \fB"/dev/sd[a\-z]"\fP and append \fB"\-d ata"\fP. For disks behind 3ware controllers you may need \fB"/dev/sd[a\-z]"\fP or \fB"/dev/twe[0\-9]"\fP, \fB"/dev/twa[0\-9]"\fP or \fB"/dev/twl[0\-9]"\fP: see details below. For disks behind HighPoint RocketRAID controllers you may need \fB"/dev/sd[a\-z]"\fP. For disks behind Areca SATA RAID controllers, you need \fB"/dev/sg[2\-9]"\fP (note that smartmontools interacts with the Areca controllers via a SCSI generic device which is different than the SCSI device used for reading and writing data)! For HP Smart Array RAID controllers, there are three currently supported drivers: cciss, hpsa, and hpahcisr. For disks accessed via the cciss driver the device nodes are of the form \fB"/dev/cciss/c[0\-9]d0"\fP. For disks accessed via the hpahcisr and hpsa drivers, the device nodes you need are \fB"/dev/sg[0\-9]*"\fP. ("lsscsi \-g" is helpful in determining which scsi generic device node corresponds to which device.) Use the nodes corresponding to the RAID controllers, not the nodes corresponding to logical drives. See the \fB\-d\fP option below, as well. .\" %ENDIF OS Linux .\" %IF OS Darwin .IP \fBDARWIN\fP: 9 Use the forms \fB/dev/disk[0\-9]\fP or equivalently \fBdisk[0\-9]\fP or equivalently \fB/dev/rdisk[0\-9]\fP. Long forms are also available: please use \'\-h\' to see some examples. Note that there is currently no Darwin SCSI support. Use the OS X SAT SMART Driver to access SMART data on SAT capable USB and Firewire devices (see INSTALL file). .\" %ENDIF OS Darwin .\" %IF OS FreeBSD .IP \fBFREEBSD\fP: 9 Use the forms \fB"/dev/ad[0\-9]+"\fP for IDE/ATA devices and \fB"/dev/da[0\-9]+"\fP or \fB"/dev/pass[0\-9]+"\fP for SCSI devices. For SATA devices on AHCI bus use \fB"/dev/ada[0\-9]+"\fP format. For HP Smart Array RAID controllers, use \fB"/dev/ciss[0\-9]"\fP (and see the \fB-d\fP option, below). .\" %ENDIF OS FreeBSD .\" %IF OS NetBSD OpenBSD .IP \fBNETBSD/OPENBSD\fP: 9 Use the form \fB"/dev/wd[0\-9]+c"\fP for IDE/ATA devices. For SCSI disk and tape devices, use the device names \fB"/dev/sd[0\-9]+c"\fP and \fB"/dev/st[0\-9]+c"\fP respectively. Be sure to specify the correct "whole disk" partition letter for your architecture. .\" %ENDIF OS NetBSD OpenBSD .\" %IF OS Solaris .IP \fBSOLARIS\fP: 9 Use the forms \fB"/dev/rdsk/c?t?d?s?"\fP for IDE/ATA and SCSI disk devices, and \fB"/dev/rmt/*"\fP for SCSI tape devices. .\" %ENDIF OS Solaris .\" %IF OS Windows Cygwin .IP \fBWINDOWS\fP: 9 Use the forms \fB"/dev/sd[a\-z]"\fP for IDE/(S)ATA and SCSI disks "\\\\.\\PhysicalDrive[0\-25]" (where "a" maps to "0"). Use \fB"/dev/sd[a\-z][a\-z]"\fP for "\\\\.\\PhysicalDrive[26\-...]". These disks can also be referred to as \fB"/dev/pd[0\-255]"\fP for "\\\\.\\PhysicalDrive[0\-255]". ATA disks can also be referred to as \fB"/dev/hd[a\-z]"\fP for "\\\\.\\PhysicalDrive[0\-25]". Use one the forms \fB"/dev/tape[0\-255]"\fP, \fB"/dev/st[0\-255]"\fP, or \fB"/dev/nst[0\-255]"\fP for SCSI tape drives "\\\\.\\Tape[0\-255]". Alternatively, drive letters \fB"X:"\fP or \fB"X:\\"\fP may be used to specify the (\'basic\') disk behind a mounted partition. This does not work with \'dynamic\' disks. For disks behind 3ware 9000 controllers use \fB"/dev/sd[a\-z],N"\fP where N specifies the disk number (3ware \'port\') behind the controller providing the logical drive (\'unit\') specified by \fB"/dev/sd[a\-z]"\fP. Alternatively, use \fB"/dev/tw_cli/cx/py"\fP for controller x, port y to run the \'tw_cli\' tool and parse the output. This provides limited monitoring (\'\-i\', \'\-c\', \'\-A\' below) if SMART support is missing in the driver. Use \fB"/dev/tw_cli/stdin"\fP or \fB"/dev/tw_cli/clip"\fP to parse CLI or 3DM output from standard input or clipboard. The option \'\-d 3ware,N\' is not necessary on Windows. For disks behind an Intel ICHxR controller with RST driver use \fB"/dev/csmi[0\-9],N"\fP where N specifies the port behind the logical scsi controller "\\\\.\\Scsi[0\-9]:". [NEW EXPERIMENTAL SMARTCTL FEATURE] For SATA or SAS disks behind an Areca controller use \fB"/dev/arcmsr[0\-9]"\fP, see \'\-d areca,N[/E]\' below. The prefix \fB"/dev/"\fP is optional. .\" %ENDIF OS Windows Cygwin .\" %IF OS OS2 .IP \fBOS/2,eComStation\fP: 9 Use the form \fB"/dev/hd[a\-z]"\fP for IDE/ATA devices. .\" %ENDIF OS OS2 .PP if \'\-\' is specified as the device path, \fBsmartctl\fP reads and interprets it's own debug output from standard input. See \'\-r ataioctl\' below for details. .PP Based on the device path, \fBsmartctl\fP will guess the device type (ATA or SCSI). If necessary, the \'\-d\' option can be used to override this guess Note that the printed output of \fBsmartctl\fP displays most numerical values in base 10 (decimal), but some values are displayed in base 16 (hexadecimal). To distinguish them, the base 16 values are always displayed with a leading \fB"0x"\fP, for example: "0xff". This man page follows the same convention. .PP .SH OPTIONS .PP The options are grouped below into several categories. \fBsmartctl\fP will execute the corresponding commands in the order: INFORMATION, ENABLE/DISABLE, DISPLAY DATA, RUN/ABORT TESTS. .TP .B SHOW INFORMATION OPTIONS: .TP .B \-h, \-\-help, \-\-usage Prints a usage message to STDOUT and exits. .TP .B \-V, \-\-version, \-\-copyright, \-\-license Prints version, copyright, license, home page and SVN revision information for your copy of \fBsmartctl\fP to STDOUT and then exits. Please include this information if you are reporting bugs or problems. .TP .B \-i, \-\-info Prints the device model number, serial number, firmware version, and ATA Standard version/revision information. Says if the device supports SMART, and if so, whether SMART support is currently enabled or disabled. If the device supports Logical Block Address mode (LBA mode) print current user drive capacity in bytes. (If drive is has a user protected area reserved, or is "clipped", this may be smaller than the potential maximum drive capacity.) Indicates if the drive is in the smartmontools database (see \'\-v\' options below). If so, the drive model family may also be printed. If \'\-n\' (see below) is specified, the power mode of the drive is printed. .TP .B \-\-identify[=[w][nvb]] [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] Prints an annotated table of the IDENTIFY DEVICE data. By default, only valid words (words not equal to 0x0000 or 0xffff) and nonzero bits and bit fields are printed. This can be changed by the optional argument which consists of one or two characters from the set \'wnvb\'. The character \'w\' enables printing of all 256 words. The character \'n\' suppresses printing of bits, \'v\' enables printing of all bits from valid words, \'b\' enables printing of all bits. For example \'\-\-identify=n\' (valid words, no bits) produces the shortest output and \'\-\-identify=wb\' (all words, all bits) produces the longest output. .TP .B \-a, \-\-all Prints all SMART information about the disk, or TapeAlert information about the tape drive or changer. For ATA devices this is equivalent to .nf \'\-H \-i \-c \-A \-l error \-l selftest \-l selective\' .fi and for SCSI, this is equivalent to .nf \'\-H \-i \-A \-l error \-l selftest\'. .fi Note that for ATA disks this does \fBnot\fP enable the non-SMART options and the SMART options which require support for 48-bit ATA commands. .TP .B \-x, \-\-xall Prints all SMART and non-SMART information about the device. For ATA devices this is equivalent to .nf \'\-H \-i \-g all \-c \-A \-f brief \-l xerror,error \-l xselftest,selftest \-l selective \-l directory \-l scttemp \-l scterc \-l devstat \-l sataphy\'. .fi and for SCSI, this is equivalent to .nf \'\-H \-i \-A \-l error \-l selftest \-l background \-l sasphy\'. .fi .TP .B \-\-scan Scans for devices and prints each device name, device type and protocol ([ATA] or [SCSI]) info. May be used in conjunction with \'\-d TYPE\' to restrict the scan to a specific TYPE. See also info about platform specific device scan and the \fBDEVICESCAN\fP directive on \fBsmartd\fP(8) man page. .TP .B \-\-scan\-open Same as \-\-scan, but also tries to open each device before printing device info. The device open may change the device type due to autodetection (see also \'\-d test\'). This option can be used to create a draft \fBsmartd.conf\fP file. All options after \'\-\-\' are appended to each output line. For example: .nf smartctl \-\-scan\-open \-\- \-a \-W 4,45,50 \-m admin@work > smartd.conf .fi .TP .B \-g NAME, \-\-get=NAME Get non-SMART device settings. See \'\-s, \-\-set\' below for further info. .TP .B RUN-TIME BEHAVIOR OPTIONS: .TP .B \-q TYPE, \-\-quietmode=TYPE Specifies that \fBsmartctl\fP should run in one of the two quiet modes described here. The valid arguments to this option are: .I errorsonly \- only print: For the \'\-l error\' option, if nonzero, the number of errors recorded in the SMART error log and the power-on time when they occurred; For the \'\-l selftest\' option, errors recorded in the device self-test log; For the \'\-H\' option, SMART "disk failing" status or device Attributes (pre-failure or usage) which failed either now or in the past; For the \'\-A\' option, device Attributes (pre-failure or usage) which failed either now or in the past. .I silent \- print no output. The only way to learn about what was found is to use the exit status of \fBsmartctl\fP (see RETURN VALUES below). .I noserial \- Do not print the serial number of the device. .TP .B \-d TYPE, \-\-device=TYPE Specifies the type of the device. The valid arguments to this option are: .I auto \- attempt to guess the device type from the device name or from controller type info provided by the operating system or from a matching USB ID entry in the drive database. This is the default. .I test \- prints the guessed type, then opens the device and prints the (possibly changed) TYPE name and then exists without performing any further commands. .I ata \- the device type is ATA. This prevents \fBsmartctl\fP from issuing SCSI commands to an ATA device. .\" %IF NOT OS Darwin .I scsi \- the device type is SCSI. This prevents \fBsmartctl\fP from issuing ATA commands to a SCSI device. .I sat[,auto][,N] \- the device type is SCSI to ATA Translation (SAT). This is for ATA disks that have a SCSI to ATA Translation (SAT) Layer (SATL) between the disk and the operating system. SAT defines two ATA PASS THROUGH SCSI commands, one 12 bytes long and the other 16 bytes long. The default is the 16 byte variant which can be overridden with either \'\-d sat,12\' or \'\-d sat,16\'. If \'\-d sat,auto\' is specified, device type SAT (for ATA/SATA disks) is only used if the SCSI INQUIRY data reports a SATL (VENDOR: "ATA "). Otherwise device type SCSI (for SCSI/SAS disks) is used. .I usbcypress \- this device type is for ATA disks that are behind a Cypress USB to PATA bridge. This will use the ATACB proprietary scsi pass through command. The default SCSI operation code is 0x24, but although it can be overridden with \'\-d usbcypress,0xN\', where N is the scsi operation code, you're running the risk of damage to the device or filesystems on it. .I usbjmicron[,p][,x][,PORT] \- this device type is for SATA disks that are behind a JMicron USB to PATA/SATA bridge. The 48-bit ATA commands (required e.g. for \'\-l xerror\', see below) do not work with all of these bridges and are therefore disabled by default. These commands can be enabled by \'\-d usbjmicron,x\'. If two disks are connected to a bridge with two ports, an error message is printed if no PORT is specified. The port can be specified by \'\-d usbjmicron[,x],PORT\' where PORT is 0 (master) or 1 (slave). This is not necessary if the device uses a port multiplier to connect multiple disks to one port. The disks appear under separate /dev/ice names then. CAUTION: Specifying \',x\' for a device which does not support it results in I/O errors and may disconnect the drive. The same applies if the specified PORT does not exist or is not connected to a disk. [NEW EXPERIMENTAL SMARTCTL FEATURE] The Prolific PL2507/3507 USB bridges with older firmware support a pass-through command similar to JMicron and work with \'\-d usbjmicron,0\'. Newer Prolific firmware requires a modified command which can be selected by \'\-d usbjmicron,p\'. Note that this does not yet support the SMART status command. .I usbsunplus \- this device type is for SATA disks that are behind a SunplusIT USB to SATA bridge. .\" %ENDIF NOT OS Darwin .\" %IF OS Linux .I marvell \- [Linux only] interact with SATA disks behind Marvell chip-set controllers (using the Marvell rather than libata driver). .I megaraid,N \- [Linux only] the device consists of one or more SCSI/SAS disks connected to a MegaRAID controller. The non-negative integer N (in the range of 0 to 127 inclusive) denotes which disk on the controller is monitored. Use syntax such as: .nf \fBsmartctl \-a \-d megaraid,2 /dev/sda\fP .fi .nf \fBsmartctl \-a \-d megaraid,0 /dev/sdb\fP .fi .nf \fBsmartctl \-a \-d megaraid,0 /dev/bus/0\fP .fi This interface will also work for Dell PERC controllers. It is possible to set RAID device name as /dev/bus/N, where N is a SCSI bus number. The following entry in /proc/devices must exist: .fi For PERC2/3/4 controllers: \fBmegadevN\fP .fi For PERC5/6 controllers: \fBmegaraid_sas_ioctlN\fP .\" %ENDIF OS Linux .\" %IF OS FreeBSD Linux .I 3ware,N \- [FreeBSD and Linux only] the device consists of one or more ATA disks connected to a 3ware RAID controller. The non-negative integer N (in the range from 0 to 127 inclusive) denotes which disk on the controller is monitored. Use syntax such as: .nf \fBsmartctl \-a \-d 3ware,2 /dev/sda\fP [Linux only] .fi .nf \fBsmartctl \-a \-d 3ware,0 /dev/twe0\fP .fi .nf \fBsmartctl \-a \-d 3ware,1 /dev/twa0\fP .fi .nf \fBsmartctl \-a \-d 3ware,1 /dev/twl0\fP [Linux only] .fi .nf \fBsmartctl \-a \-d 3ware,1 /dev/tws0\fP [FreeBSD only] .fi The first two forms, which refer to devices /dev/sda\-z and /dev/twe0\-15, may be used with 3ware series 6000, 7000, and 8000 series controllers that use the 3x-xxxx driver. \fBNote that the /dev/sda\-z form is deprecated\fP starting with the Linux 2.6 kernel series and may not be supported by the Linux kernel in the near future. The final form, which refers to devices /dev/twa0\-15, must be used with 3ware 9000 series controllers, which use the 3w\-9xxx driver. The devices /dev/twl0\-15 [Linux] or /dev/tws0\-15 [FreeBSD] must be used with the 3ware/LSI 9750 series controllers which use the 3w-sas driver. Note that if the special character device nodes /dev/tw[ls]?, /dev/twa? and /dev/twe? do not exist, or exist with the incorrect major or minor numbers, smartctl will recreate them on the fly. Typically /dev/twa0 refers to the first 9000-series controller, /dev/twa1 refers to the second 9000 series controller, and so on. The /dev/twl0 devices refers to the first 9750 series controller, /dev/twl1 resfers to the second 9750 series controller, and so on. Likewise /dev/twe0 refers to the first 6/7/8000-series controller, /dev/twe1 refers to the second 6/7/8000 series controller, and so on. Note that for the 6/7/8000 controllers, \fBany\fP of the physical disks can be queried or examined using \fBany\fP of the 3ware's SCSI logical device /dev/sd? entries. Thus, if logical device /dev/sda is made up of two physical disks (3ware ports zero and one) and logical device /dev/sdb is made up of two other physical disks (3ware ports two and three) then you can examine the SMART data on \fBany\fP of the four physical disks using \fBeither\fP SCSI device /dev/sda \fBor\fP /dev/sdb. If you need to know which logical SCSI device a particular physical disk (3ware port) is associated with, use the dmesg or SYSLOG output to show which SCSI ID corresponds to a particular 3ware unit, and then use the 3ware CLI or 3dm tool to determine which ports (physical disks) correspond to particular 3ware units. If the value of N corresponds to a port that does \fBnot\fP exist on the 3ware controller, or to a port that does not physically have a disk attached to it, the behavior of \fBsmartctl\fP depends upon the specific controller model, firmware, Linux kernel and platform. In some cases you will get a warning message that the device does not exist. In other cases you will be presented with \'void\' data for a non-existent device. Note that if the /dev/sd? addressing form is used, then older 3w-xxxx drivers do not pass the "Enable Autosave" (\'\fB\-S on\fP\') and "Enable Automatic Offline" (\'\fB\-o on\fP\') commands to the disk, and produce these types of harmless syslog error messages instead: "\fB3w-xxxx: tw_ioctl(): Passthru size (123392) too big\fP". This can be fixed by upgrading to version 1.02.00.037 or later of the 3w-xxxx driver, or by applying a patch to older versions. Alternatively, use the character device /dev/twe0\-15 interface. The selective self-test functions (\'\-t select,A\-B\') are only supported using the character device interface /dev/twl0\-15, /dev/tws0\-15, /dev/twa0\-15 and /dev/twe0\-15. The necessary WRITE LOG commands can not be passed through the SCSI interface. .\" %ENDIF OS FreeBSD Linux .\" %IF OS FreeBSD Linux Windows Cygwin .I areca,N \- [FreeBSD, Linux, Windows and Cygwin only] the device consists of one or more SATA disks connected to an Areca SATA RAID controller. The positive integer N (in the range from 1 to 24 inclusive) denotes which disk on the controller is monitored. .\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS Linux On Linux use syntax such as: .nf \fBsmartctl \-a \-d areca,2 /dev/sg2\fP .fi .nf \fBsmartctl \-a \-d areca,3 /dev/sg3\fP .fi .\" %ENDIF OS Linux .\" %IF OS FreeBSD On FreeBSD use syntax such as: .nf \fBsmartctl \-a \-d areca,2 /dev/arcmsr1\fP .fi .nf \fBsmartctl \-a \-d areca,3 /dev/arcmsr2\fP .fi .\" %ENDIF OS FreeBSD .\" %IF OS Windows Cygwin [NEW EXPERIMENTAL SMARTCTL FEATURE] On Windows and Cygwin use syntax such as: .nf \fBsmartctl \-a \-d areca,2 /dev/arcmsr0\fP .fi .nf \fBsmartctl \-a \-d areca,3 /dev/arcmsr1\fP .fi .\" %ENDIF OS Windows Cygwin .\" %IF OS FreeBSD Linux Windows Cygwin The first line above addresses the second disk on the first Areca RAID controller. The second line addresses the third disk on the second Areca RAID controller. .\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS Linux To help identify the correct device on Linux, use the command: .nf \fBcat /proc/scsi/sg/device_hdr /proc/scsi/sg/devices\fP .fi to show the SCSI generic devices (one per line, starting with /dev/sg0). The correct SCSI generic devices to address for smartmontools are the ones with the type field equal to 3. If the incorrect device is addressed, please read the warning/error messages carefully. They should provide hints about what devices to use. .\" %ENDIF OS Linux .\" %IF OS FreeBSD Linux Windows Cygwin Important: the Areca controller must have firmware version 1.46 or later. Lower-numbered firmware versions will give (harmless) SCSI error messages and no SMART information. .I areca,N/E \- [FreeBSD, Linux, Windows and Cygwin only] [NEW EXPERIMENTAL SMARTCTL FEATURE] the device consists of one or more SATA or SAS disks connected to an Areca SAS RAID controller. The integer N (range 1 to 128) denotes the channel (slot) and E (range 1 to 8) denotes the enclosure. Important: This requires Areca SAS controller firmware version 1.51 or later. .\" %ENDIF OS FreeBSD Linux Windows Cygwin .\" %IF OS FreeBSD Linux .I cciss,N \- [FreeBSD and Linux only] the device consists of one or more SCSI/SAS or SATA disks connected to a cciss RAID controller. The non-negative integer N (in the range from 0 to 15 inclusive) denotes which disk on the controller is monitored. To look at disks behind HP Smart Array controllers, use syntax such as: .\" %ENDIF OS FreeBSD Linux .\" %IF OS Linux .nf \fBsmartctl \-a \-d cciss,0 /dev/cciss/c0d0\fP (cciss driver under Linux) .fi .nf \fBsmartctl \-a \-d cciss,0 /dev/sg2\fP (hpsa or hpahcisr drivers under Linux) .fi .\" %ENDIF OS Linux .\" %IF OS FreeBSD .nf \fBsmartctl \-a \-d cciss,0 /dev/ciss0\fP (under FreeBSD) .fi .\" %ENDIF OS FreeBSD .\" %IF OS FreeBSD Linux .I hpt,L/M/N \- [FreeBSD and Linux only] the device consists of one or more ATA disks connected to a HighPoint RocketRAID controller. The integer L is the controller id, the integer M is the channel number, and the integer N is the PMPort number if it is available. The allowed values of L are from 1 to 4 inclusive, M are from 1 to 128 inclusive and N from 1 to 4 if PMPort available. And also these values are limited by the model of the HighPoint RocketRAID controller. Use syntax such as: .\" %ENDIF OS FreeBSD Linux .\" %IF OS Linux .nf \fBsmartctl \-a \-d hpt,1/3 /dev/sda\fP (under Linux) .fi .nf \fBsmartctl \-a \-d hpt,1/2/3 /dev/sda\fP (under Linux) .fi .\" %ENDIF OS Linux .\" %IF OS FreeBSD .nf \fBsmartctl \-a \-d hpt,1/3 /dev/hptrr\fP (under FreeBSD) .fi .nf \fBsmartctl \-a \-d hpt,1/2/3 /dev/hptrr\fP (under FreeBSD) .fi .\" %ENDIF OS FreeBSD .\" %IF OS FreeBSD Linux Note that the /dev/sda\-z form should be the device node which stands for the disks derived from the HighPoint RocketRAID controllers under Linux and under FreeBSD, it is the character device which the driver registered (eg, /dev/hptrr, /dev/hptmv6). .\" %ENDIF OS FreeBSD Linux .TP .B \-T TYPE, \-\-tolerance=TYPE [ATA only] Specifies how tolerant \fBsmartctl\fP should be of ATA and SMART command failures. The behavior of \fBsmartctl\fP depends upon whether the command is "\fBoptional\fP" or "\fBmandatory\fP". Here "\fBmandatory\fP" means "required by the ATA Specification if the device implements the SMART command set" and "\fBoptional\fP" means "not required by the ATA Specification even if the device implements the SMART command set." The "\fBmandatory\fP" ATA and SMART commands are: (1) ATA IDENTIFY DEVICE, (2) SMART ENABLE/DISABLE ATTRIBUTE AUTOSAVE, (3) SMART ENABLE/DISABLE, and (4) SMART RETURN STATUS. The valid arguments to this option are: .I normal \- exit on failure of any \fBmandatory\fP SMART command, and ignore all failures of \fBoptional\fP SMART commands. This is the default. Note that on some devices, issuing unimplemented optional SMART commands doesn\'t cause an error. This can result in misleading \fBsmartctl\fP messages such as "Feature X not implemented", followed shortly by "Feature X: enabled". In most such cases, contrary to the final message, Feature X is \fBnot\fP enabled. .I conservative \- exit on failure of any \fBoptional\fP SMART command. .I permissive \- ignore failure(s) of \fBmandatory\fP SMART commands. This option may be given more than once. Each additional use of this option will cause one more additional failure to be ignored. Note that the use of this option can lead to messages like "Feature X not supported", followed shortly by "Feature X enable failed". In a few such cases, contrary to the final message, Feature X \fBis\fP enabled. .I verypermissive \- equivalent to giving a large number of \'\-T permissive\' options: ignore failures of \fBany number\fP of \fBmandatory\fP SMART commands. Please see the note above. .TP .B \-b TYPE, \-\-badsum=TYPE [ATA only] Specifies the action \fBsmartctl\fP should take if a checksum error is detected in the: (1) Device Identity Structure, (2) SMART Self-Test Log Structure, (3) SMART Attribute Value Structure, (4) SMART Attribute Threshold Structure, or (5) ATA Error Log Structure. The valid arguments to this option are: .I warn \- report the incorrect checksum but carry on in spite of it. This is the default. .I exit \- exit \fBsmartctl\fP. .I ignore \- continue silently without issuing a warning. .TP .B \-r TYPE, \-\-report=TYPE Intended primarily to help \fBsmartmontools\fP developers understand the behavior of \fBsmartmontools\fP on non-conforming or poorly conforming hardware. This option reports details of \fBsmartctl\fP transactions with the device. The option can be used multiple times. When used just once, it shows a record of the ioctl() transactions with the device. When used more than once, the detail of these ioctl() transactions are reported in greater detail. The valid arguments to this option are: .I ioctl \- report all ioctl() transactions. .I ataioctl \- report only ioctl() transactions with ATA devices. .I scsiioctl \- report only ioctl() transactions with SCSI devices. Invoking this once shows the SCSI commands in hex and the corresponding status. Invoking it a second time adds a hex listing of the first 64 bytes of data send to, or received from the device. Any argument may include a positive integer to specify the level of detail that should be reported. The argument should be followed by a comma then the integer with no spaces. For example, .I ataioctl,2 The default level is 1, so \'\-r ataioctl,1\' and \'\-r ataioctl\' are equivalent. For testing purposes, the output of \'\-r ataioctl,2\' can later be parsed by \fBsmartctl\fP itself if \'\-\' is used as device path argument. The ATA command input parameters, sector data and return values are reconstructed from the debug report read from stdin. Then \fBsmartctl\fP internally simulates an ATA device with the same behaviour. This is does not work for SCSI devices yet. .TP .B \-n POWERMODE, \-\-nocheck=POWERMODE [ATA only] Specifies if \fBsmartctl\fP should exit before performing any checks when the device is in a low-power mode. It may be used to prevent a disk from being spun-up by \fBsmartctl\fP. The power mode is ignored by default. A nonzero exit status is returned if the device is in one of the specified low-power modes (see RETURN VALUES below). Note: If this option is used it may also be necessary to specify the device type with the \'\-d\' option. Otherwise the device may spin up due to commands issued during device type autodetection. The valid arguments to this option are: .I never \- check the device always, but print the power mode if \'\-i\' is specified. .I sleep \- check the device unless it is in SLEEP mode. .I standby \- check the device unless it is in SLEEP or STANDBY mode. In these modes most disks are not spinning, so if you want to prevent a disk from spinning up, this is probably what you want. .I idle \- check the device unless it is in SLEEP, STANDBY or IDLE mode. In the IDLE state, most disks are still spinning, so this is probably not what you want. .TP .B SMART FEATURE ENABLE/DISABLE COMMANDS: .IP .B Note: if multiple options are used to both enable and disable a feature, then .B both the enable and disable commands will be issued. The enable command will always be issued .B before the corresponding disable command. .TP .B \-s VALUE, \-\-smart=VALUE Enables or disables SMART on device. The valid arguments to this option are \fIon\fP and \fIoff\fP. Note that the command \'\-s on\' (perhaps used with with the \'\-o on\' and \'\-S on\' options) should be placed in a start-up script for your machine, for example in rc.local or rc.sysinit. In principle the SMART feature settings are preserved over power-cycling, but it doesn\'t hurt to be sure. It is not necessary (or useful) to enable SMART to see the TapeAlert messages. .TP .B \-o VALUE, \-\-offlineauto=VALUE [ATA only] Enables or disables SMART automatic offline test, which scans the drive every four hours for disk defects. This command can be given during normal system operation. The valid arguments to this option are \fIon\fP and \fIoff\fP. Note that the SMART automatic offline test command is listed as "Obsolete" in every version of the ATA and ATA/ATAPI Specifications. It was originally part of the SFF-8035i Revision 2.0 specification, but was never part of any ATA specification. However it is implemented and used by many vendors. [Good documentation can be found in IBM\'s Official Published Disk Specifications. For example the IBM Travelstar 40GNX Hard Disk Drive Specifications (Revision 1.1, 22 April 2002, Publication # 1541, Document S07N-7715-02) page 164. You can also read the SFF-8035i Specification -- see REFERENCES below.] You can tell if automatic offline testing is supported by seeing if this command enables and disables it, as indicated by the \'Auto Offline Data Collection\' part of the SMART capabilities report (displayed with \'\-c\'). SMART provides \fBthree\fP basic categories of testing. The \fBfirst\fP category, called "online" testing, has no effect on the performance of the device. It is turned on by the \'\-s on\' option. The \fBsecond\fP category of testing is called "offline" testing. This type of test can, in principle, degrade the device performance. The \'\-o on\' option causes this offline testing to be carried out, automatically, on a regular scheduled basis. Normally, the disk will suspend offline testing while disk accesses are taking place, and then automatically resume it when the disk would otherwise be idle, so in practice it has little effect. Note that a one-time offline test can also be carried out immediately upon receipt of a user command. See the \'\-t offline\' option below, which causes a one-time offline test to be carried out immediately. The choice (made by the SFF-8035i and ATA specification authors) of the word \fItesting\fP for these first two categories is unfortunate, and often leads to confusion. In fact these first two categories of online and offline testing could have been more accurately described as online and offline \fBdata collection\fP. The results of this automatic or immediate offline testing (data collection) are reflected in the values of the SMART Attributes. Thus, if problems or errors are detected, the values of these Attributes will go below their failure thresholds; some types of errors may also appear in the SMART error log. These are visible with the \'\-A\' and \'\-l error\' options respectively. Some SMART attribute values are updated only during off-line data collection activities; the rest are updated during normal operation of the device or during both normal operation and off-line testing. The Attribute value table produced by the \'\-A\' option indicates this in the UPDATED column. Attributes of the first type are labeled "Offline" and Attributes of the second type are labeled "Always". The \fBthird\fP category of testing (and the \fIonly\fP category for which the word \'testing\' is really an appropriate choice) is "self" testing. This third type of test is only performed (immediately) when a command to run it is issued. The \'\-t\' and \'\-X\' options can be used to carry out and abort such self-tests; please see below for further details. Any errors detected in the self testing will be shown in the SMART self-test log, which can be examined using the \'\-l selftest\' option. \fBNote:\fP in this manual page, the word \fB"Test"\fP is used in connection with the second category just described, e.g. for the "offline" testing. The words \fB"Self-test"\fP are used in connection with the third category. .TP .B \-S VALUE, \-\-saveauto=VALUE [ATA] Enables or disables SMART autosave of device vendor-specific Attributes. The valid arguments to this option are \fIon\fP and \fIoff\fP. Note that this feature is preserved across disk power cycles, so you should only need to issue it once. The ATA standard does not specify a method to check whether SMART autosave is enabled. Unlike SCSI (below), smartctl is unable to print a warning if autosave is disabled. [SCSI] For SCSI devices this toggles the value of the Global Logging Target Save Disabled (GLTSD) bit in the Control Mode Page. Some disk manufacturers set this bit by default. This prevents error counters, power-up hours and other useful data from being placed in non-volatile storage, so these values may be reset to zero the next time the device is power-cycled. If the GLTSD bit is set then \'smartctl \-a\' will issue a warning. Use \fIon\fP to clear the GLTSD bit and thus enable saving counters to non-volatile storage. For extreme streaming-video type applications you might consider using \fIoff\fP to set the GLTSD bit. .TP .B \-g NAME, \-\-get=NAME, \-s NAME[,VALUE], \-\-set=NAME[,VALUE] Gets/sets non-SMART device settings. Note that the \'\-\-set\' option shares its short option \'\-s\' with \'\-\-smart\'. Valid arguments are: .I all \- Gets all values. This is equivalent to .nf \'-g aam -g apm -g lookahead -g security -g wcache\' .fi .I aam[,N|off] \- [ATA only] Gets/sets the Automatic Acoustic Management (AAM) feature (if supported). A value of 128 sets the most quiet (slowest) mode and 254 the fastest (loudest) mode, \'off\' disables AAM. Devices may support intermediate levels. Values below 128 are defined as vendor specific (0) or retired (1 to 127). Note that the AAM feature was declared obsolete in ATA ACS-2 Revision 4a (Dec 2010). .I apm[,N|off] \- [ATA only] Gets/sets the Advanced Power Management (APM) feature on device (if supported). If a value between 1 and 254 is provided, it will attempt to enable APM and set the specified value, \'off\' disables APM. Note the actual behavior depends on the drive, for example some drives disable APM if their value is set above 128. Values below 128 are supposed to allow drive spindown, values 128 and above adjust only head-parking frequency, although the actual behavior defined is also vendor-specific. .I lookahead[,on|off] \- [ATA only] Gets/sets the read look-ahead feature (if supported). Read look-ahead is usually enabled by default. .I security \- [ATA only] Gets the status of ATA Security feature (if supported). If ATA Security is enabled an ATA user password is set. The drive will be locked on next reset then. .I security-freeze \- [ATA only] Sets ATA Security feature to frozen mode. This prevents that the drive accepts any security commands until next reset. Note that the frozen mode may already be set by BIOS or OS. .I standby,[N|off] \- [ATA only] Sets the standby (spindown) timer and places the drive in the IDLE mode. A value of 0 or \'off\' disables the standby timer. Values from 1 to 240 specify timeouts from 5 seconds to 20 minutes in 5 second increments. Values from 241 to 251 specify timeouts from 30 minutes to 330 minutes in 30 minute increments. Value 252 specifies 21 minutes. Value 253 specifies a vendor specific time between 8 and 12 hours. Value 255 specifies 21 minutes and 15 seconds. Some drives may use a vendor specific interpretation for the values. Note that there is no get option because ATA standards do not specify a method to read the standby timer. .I standby,now \- [ATA only] Places the drive in the STANDBY mode. This usually spins down the drive. The setting of the standby timer is not affected. .I wcache[,on|off] \- [ATA] Gets/sets the volatile write cache feature (if supported). The write cache is usually enabled by default. .I wcache[,on|off] \- [SCSI] [NEW EXPERIMENTAL SMARTCTL FEATURE] Gets/sets the \'Write Cache Enable\' (WCE) bit (if supported). The write cache is usually enabled by default. .I wcreorder[,on|off] \- [ATA only] [NEW EXPERIMENTAL SMARTCTL FEATURE] Gets/sets Write Cache Reordering. If it is disabled (off), disk write scheduling is executed on a first-in-first-out (FIFO) basis. If Write Cache Reordering is enabled (on), then disk write scheduling may be reordered by the drive. If write cache is disabled, the current Write Cache Reordering state is remembered but has no effect on non-cached writes, which are always written in the order received. The state of Write Cache Reordering has no effect on either NCQ or LCQ queued commands. .I rcache[,on|off] \- [SCSI only] [NEW EXPERIMENTAL SMARTCTL FEATURE] Gets/sets the \'Read Cache Disable\' (RCE) bit. \'Off\' value disables read cache (if supported). The read cache is usually enabled by default. .TP .B SMART READ AND DISPLAY DATA OPTIONS: .TP .B \-H, \-\-health Check: Ask the device to report its SMART health status or pending TapeAlert messages. SMART status is based on information that it has gathered from online and offline tests, which were used to determine/update its SMART vendor-specific Attribute values. TapeAlert status is obtained by reading the TapeAlert log page. If the device reports failing health status, this means .B either that the device has already failed, .B or that it is predicting its own failure within the next 24 hours. If this happens, use the \'\-a\' option to get more information, and .B get your data off the disk and to someplace safe as soon as you can. .TP .B \-c, \-\-capabilities [ATA only] Prints only the generic SMART capabilities. These show what SMART features are implemented and how the device will respond to some of the different SMART commands. For example it shows if the device logs errors, if it supports offline surface scanning, and so on. If the device can carry out self-tests, this option also shows the estimated time required to run those tests. Note that the time required to run the Self-tests (listed in minutes) are fixed. However the time required to run the Immediate Offline Test (listed in seconds) is variable. This means that if you issue a command to perform an Immediate Offline test with the \'\-t offline\' option, then the time may jump to a larger value and then count down as the Immediate Offline Test is carried out. Please see REFERENCES below for further information about the the flags and capabilities described by this option. .TP .B \-A, \-\-attributes [ATA] Prints only the vendor specific SMART Attributes. The Attributes are numbered from 1 to 253 and have specific names and ID numbers. For example Attribute 12 is "power cycle count": how many times has the disk been powered up. Each Attribute has a "Raw" value, printed under the heading "RAW_VALUE", and a "Normalized" value printed under the heading "VALUE". [Note: \fBsmartctl\fP prints these values in base-10.] In the example just given, the "Raw Value" for Attribute 12 would be the actual number of times that the disk has been power-cycled, for example 365 if the disk has been turned on once per day for exactly one year. Each vendor uses their own algorithm to convert this "Raw" value to a "Normalized" value in the range from 1 to 254. Please keep in mind that \fBsmartctl\fP only reports the different Attribute types, values, and thresholds as read from the device. It does \fBnot\fP carry out the conversion between "Raw" and "Normalized" values: this is done by the disk\'s firmware. The conversion from Raw value to a quantity with physical units is not specified by the SMART standard. In most cases, the values printed by \fBsmartctl\fP are sensible. For example the temperature Attribute generally has its raw value equal to the temperature in Celsius. However in some cases vendors use unusual conventions. For example the Hitachi disk on my laptop reports its power-on hours in minutes, not hours. Some IBM disks track three temperatures rather than one, in their raw values. And so on. Each Attribute also has a Threshold value (whose range is 0 to 255) which is printed under the heading "THRESH". If the Normalized value is \fBless than or equal to\fP the Threshold value, then the Attribute is said to have failed. If the Attribute is a pre-failure Attribute, then disk failure is imminent. Each Attribute also has a "Worst" value shown under the heading "WORST". This is the smallest (closest to failure) value that the disk has recorded at any time during its lifetime when SMART was enabled. [Note however that some vendors firmware may actually \fBincrease\fP the "Worst" value for some "rate-type" Attributes.] The Attribute table printed out by \fBsmartctl\fP also shows the "TYPE" of the Attribute. Attributes are one of two possible types: Pre-failure or Old age. Pre-failure Attributes are ones which, if less than or equal to their threshold values, indicate pending disk failure. Old age, or usage Attributes, are ones which indicate end-of-product life from old-age or normal aging and wearout, if the Attribute value is less than or equal to the threshold. \fBPlease note\fP: the fact that an Attribute is of type 'Pre-fail' does \fBnot\fP mean that your disk is about to fail! It only has this meaning if the Attribute\'s current Normalized value is less than or equal to the threshold value. If the Attribute\'s current Normalized value is less than or equal to the threshold value, then the "WHEN_FAILED" column will display "FAILING_NOW". If not, but the worst recorded value is less than or equal to the threshold value, then this column will display "In_the_past". If the "WHEN_FAILED" column has no entry (indicated by a dash: \'\-\') then this Attribute is OK now (not failing) and has also never failed in the past. The table column labeled "UPDATED" shows if the SMART Attribute values are updated during both normal operation and off-line testing, or only during offline testing. The former are labeled "Always" and the latter are labeled "Offline". So to summarize: the Raw Attribute values are the ones that might have a real physical interpretation, such as "Temperature Celsius", "Hours", or "Start-Stop Cycles". Each manufacturer converts these, using their detailed knowledge of the disk\'s operations and failure modes, to Normalized Attribute values in the range 1\-254. The current and worst (lowest measured) of these Normalized Attribute values are stored on the disk, along with a Threshold value that the manufacturer has determined will indicate that the disk is going to fail, or that it has exceeded its design age or aging limit. \fBsmartctl\fP does \fBnot\fP calculate any of the Attribute values, thresholds, or types, it merely reports them from the SMART data on the device. Note that starting with ATA/ATAPI-4, revision 4, the meaning of these Attribute fields has been made entirely vendor-specific. However most newer ATA/SATA disks seem to respect their meaning, so we have retained the option of printing the Attribute values. Solid-state drives use different meanings for some of the attributes. In this case the attribute name printed by smartctl is incorrect unless the drive is already in the smartmontools drive database. [SCSI] For SCSI devices the "attributes" are obtained from the temperature and start-stop cycle counter log pages. Certain vendor specific attributes are listed if recognised. The attributes are output in a relatively free format (compared with ATA disk attributes). .TP .B \-f FORMAT, \-\-format=FORMAT [ATA only] Selects the output format of the attributes: .I old \- Old smartctl format. This is the default unless the \'\-x\' option is specified. .I brief \- New format which fits into 80 colums (except in some rare cases). This format also decodes four additional attribute flags. This is the default if the '\-x\' option is specified. .I hex,id \- Print all attribute IDs as hexadecimal numbers. .I hex,val \- Print all normalized values as hexadecimal numbers. .I hex \- Same as \'\-f hex,id \-f hex,val\'. .TP .B \-l TYPE, \-\-log=TYPE Prints either the SMART Error Log, the SMART Self-Test Log, the SMART Selective Self-Test Log [ATA only], the Log Directory [ATA only], or the Background Scan Results Log [SCSI only]. The valid arguments to this option are: .I error \- [ATA] prints the Summary SMART error log. SMART disks maintain a log of the most recent five non-trivial errors. For each of these errors, the disk power-on lifetime at which the error occurred is recorded, as is the device status (idle, standby, etc) at the time of the error. For some common types of errors, the Error Register (ER) and Status Register (SR) values are decoded and printed as text. The meanings of these are: .nf \fBABRT\fP: Command \fBAB\fPo\fBRT\fPed \fBAMNF\fP: \fBA\fPddress \fBM\fPark \fBN\fPot \fBF\fPound \fBCCTO\fP: \fBC\fPommand \fBC\fPompletion \fBT\fPimed \fBO\fPut \fBEOM\fP: \fBE\fPnd \fBO\fPf \fBM\fPedia \fBICRC\fP: \fBI\fPnterface \fBC\fPyclic \fBR\fPedundancy \fBC\fPode (CRC) error \fBIDNF\fP: \fBID\fPentity \fBN\fPot \fBF\fPound \fBILI\fP: (packet command-set specific) \fBMC\fP: \fBM\fPedia \fBC\fPhanged \fBMCR\fP: \fBM\fPedia \fBC\fPhange \fBR\fPequest \fBNM\fP: \fBN\fPo \fBM\fPedia \fBobs\fP: \fBobs\fPolete \fBTK0NF\fP: \fBT\fPrac\fBK 0 N\fPot \fBF\fPound \fBUNC\fP: \fBUNC\fPorrectable Error in Data \fBWP\fP: Media is \fBW\fPrite \fBP\fProtected .fi In addition, up to the last five commands that preceded the error are listed, along with a timestamp measured from the start of the corresponding power cycle. This is displayed in the form Dd+HH:MM:SS.msec where D is the number of days, HH is hours, MM is minutes, SS is seconds and msec is milliseconds. [Note: this time stamp wraps after 2^32 milliseconds, or 49 days 17 hours 2 minutes and 47.296 seconds.] The key ATA disk registers are also recorded in the log. The final column of the error log is a text-string description of the ATA command defined by the Command Register (CR) and Feature Register (FR) values. Commands that are obsolete in the most current spec are listed like this: \fBREAD LONG (w/ retry) [OBS-4]\fP, indicating that the command became obsolete with or in the ATA-4 specification. Similarly, the notation \fB[RET\-\fP\fIN\fP\fB]\fP is used to indicate that a command was retired in the ATA-\fIN\fP specification. Some commands are not defined in any version of the ATA specification but are in common use nonetheless; these are marked \fB[NS]\fP, meaning non-standard. The ATA Specification (ATA-5 Revision 1c, Section 8.41.6.8.2) says: \fB"Error log structures shall include UNC errors, IDNF errors for which the address requested was valid, servo errors, write fault errors, etc. Error log data structures shall not include errors attributed to the receipt of faulty commands such as command codes not implemented by the device or requests with invalid parameters or invalid addresses."\fP The definitions of these terms are: .br \fBUNC\fP (\fBUNC\fPorrectable): data is uncorrectable. This refers to data which has been read from the disk, but for which the Error Checking and Correction (ECC) codes are inconsistent. In effect, this means that the data can not be read. .br \fBIDNF\fP (\fBID N\fPot \fBF\fPound): user-accessible address could not be found. For READ LOG type commands, \fBIDNF\fP can also indicate that a device data log structure checksum was incorrect. If the command that caused the error was a READ or WRITE command, then the Logical Block Address (LBA) at which the error occurred will be printed in base 10 and base 16. The LBA is a linear address, which counts 512-byte sectors on the disk, starting from zero. (Because of the limitations of the SMART error log, if the LBA is greater than 0xfffffff, then either no error log entry will be made, or the error log entry will have an incorrect LBA. This may happen for drives with a capacity greater than 128 GiB or 137 GB.) On Linux systems the smartmontools web page has instructions about how to convert the LBA address to the name of the disk file containing the erroneous disk sector. Please note that some manufacturers \fBignore\fP the ATA specifications, and make entries in the error log if the device receives a command which is not implemented or is not valid. .I error \- [SCSI] prints the error counter log pages for reads, write and verifies. The verify row is only output if it has an element other than zero. .I xerror[,NUM][,error] \- [ATA only] prints the Extended Comprehensive SMART error log (General Purpose Log address 0x03). Unlike the Summary SMART error log (see \'\-l error\' above), it provides sufficient space to log the contents of the 48-bit LBA register set introduced with ATA-6. It also supports logs with more than one sector. Each sector holds up to 4 log entries. The actual number of log sectors is vendor specific, typical values for HDD are 2 (Samsung), 5 (Seagate) or 6 (WD). Only the 8 most recent error log entries are printed by default. This number can be changed by the optional parameter NUM. If ',error' is appended and the Extended Comprehensive SMART error log is not supported, the Summary SMART self-test log is printed. Please note that recent drives may report errors only in the Extended Comprehensive SMART error log. The Summary SMART error log may be reported as supported but is always empty then. .I selftest \- [ATA] prints the SMART self-test log. The disk maintains a self-test log showing the results of the self tests, which can be run using the \'\-t\' option described below. For each of the most recent twenty-one self-tests, the log shows the type of test (short or extended, off-line or captive) and the final status of the test. If the test did not complete successfully, then the percentage of the test remaining is shown. The time at which the test took place, measured in hours of disk lifetime, is also printed. [Note: this time stamp wraps after 2^16 hours, or 2730 days and 16 hours, or about 7.5 years.] If any errors were detected, the Logical Block Address (LBA) of the first error is printed in decimal notation. On Linux systems the smartmontools web page has instructions about how to convert this LBA address to the name of the disk file containing the erroneous block. .I selftest \- [SCSI] the self-test log for a SCSI device has a slightly different format than for an ATA device. For each of the most recent twenty self-tests, it shows the type of test and the status (final or in progress) of the test. SCSI standards use the terms "foreground" and "background" (rather than ATA\'s corresponding "captive" and "off-line") and "short" and "long" (rather than ATA\'s corresponding "short" and "extended") to describe the type of the test. The printed segment number is only relevant when a test fails in the third or later test segment. It identifies the test that failed and consists of either the number of the segment that failed during the test, or the number of the test that failed and the number of the segment in which the test was run, using a vendor-specific method of putting both numbers into a single byte. The Logical Block Address (LBA) of the first error is printed in hexadecimal notation. On Linux systems the smartmontools web page has instructions about how to convert this LBA address to the name of the disk file containing the erroneous block. If provided, the SCSI Sense Key (SK), Additional Sense Code (ASC) and Additional Sense Code Qualifier (ASQ) are also printed. The self tests can be run using the \'\-t\' option described below (using the ATA test terminology). .I xselftest[,NUM][,selftest] \- [ATA only] prints the Extended SMART self-test log (General Purpose Log address 0x07). Unlike the SMART self-test log (see \'\-l selftest\' above), it supports 48-bit LBA and logs with more than one sector. Each sector holds up to 19 log entries. The actual number of log sectors is vendor specific, typical values are 1 (Seagate) or 2 (Samsung). Only the 25 most recent log entries are printed by default. This number can be changed by the optional parameter NUM. If ',selftest' is appended and the Extended SMART self-test log is not supported, the old SMART self-test log is printed. .I selective \- [ATA only] Please see the \'\-t select\' option below for a description of selective self-tests. The selective self-test log shows the start/end Logical Block Addresses (LBA) of each of the five test spans, and their current test status. If the span is being tested or the remainder of the disk is being read-scanned, the current 65536-sector block of LBAs being tested is also displayed. The selective self-test log also shows if a read-scan of the remainder of the disk will be carried out after the selective self-test has completed (see \'\-t afterselect\' option) and the time delay before restarting this read-scan if it is interrupted (see \'\-t pending\' option). .I directory[,gs] \- [ATA only] if the device supports the General Purpose Logging feature set (ATA-6 and above) then this prints the Log Directory (the log at address 0). The Log Directory shows what logs are available and their length in sectors (512 bytes). The contents of the logs at address 1 [Summary SMART error log] and at address 6 [SMART self-test log] may be printed using the previously-described .I error and .I selftest arguments to this option. If your version of smartctl supports 48-bit ATA commands, both the General Purpose Log (GPL) and SMART Log (SL) directories are printed in one combined table. The output can be restricted to the GPL directory or SL directory by \'\-l directory,q\' or \'\-l directory,s\' respectively. .I background \- [SCSI only] the background scan results log outputs information derived from Background Media Scans (BMS) done after power up and/or periodically (e.g. every 24 hours) on recent SCSI disks. If supported, the BMS status is output first, indicating whether a background scan is currently underway (and if so a progress percentage), the amount of time the disk has been powered up and the number of scans already completed. Then there is a header and a line for each background scan "event". These will typically be either recovered or unrecoverable errors. That latter group may need some attention. There is a description of the background scan mechanism in section 4.18 of SBC-3 revision 6 (see www.t10.org ). .I scttemp, scttempsts, scttemphist \- [ATA only] prints the disk temperature information provided by the SMART Command Transport (SCT) commands. The option \'scttempsts\' prints current temperature and temperature ranges returned by the SCT Status command, \'scttemphist\' prints temperature limits and the temperature history table returned by the SCT Data Table command, and \'scttemp\' prints both. The temperature values are preserved across power cycles. The logging interval can be configured with the \'\-l scttempint,N[,p]\' option, see below. The SCT commands were introduced in ATA8-ACS and were also supported by many ATA-7 disks. .I scttempint,N[,p] \- [ATA only] clears the SCT temperature history table and sets the time interval for temperature logging to N minutes. If \',p\' is specified, the setting is preserved across power cycles. Otherwise, the setting is volatile and will be reverted to the last non-volatile setting by the next hard reset. The default interval is vendor specific, typical values are 1, 2, or 5 minutes. .I scterc[,READTIME,WRITETIME] \- [ATA only] prints values and descriptions of the SCT Error Recovery Control settings. These are equivalent to TLER (as used by Western Digital), CCTL (as used by Samsung and Hitachi) and ERC (as used by Seagate). READTIME and WRITETIME arguments (deciseconds) set the specified values. Values of 0 disable the feature, other values less than 65 are probably not supported. For RAID configurations, this is typically set to 70,70 deciseconds. .I devstat[,PAGE] \- [ATA only] prints values and descriptions of the ATA Device Statistics log pages (General Purpose Log address 0x04). If no PAGE number is specified, entries from all supported pages are printed. If PAGE 0 is specified, the list of supported pages is printed. Device Statistics was introduced in ACS-2 and is only supported by some recent devices (e.g. Hitachi 7K3000, Intel 320, 330, 520 and 710 Series SSDs, Crucial/Micron m4 SSDs). .I sataphy[,reset] \- [SATA only] prints values and descriptions of the SATA Phy Event Counters (General Purpose Log address 0x11). If \'\-l sataphy,reset\' is specified, all counters are reset after reading the values. This also works for SATA devices with Packet interface like CD/DVD drives. .I sasphy[,reset] \- [SAS (SCSI) only] prints values and descriptions of the SAS (SSP) Protocol Specific log page (log page 0x18). If \'\-l sasphy,reset\' is specified, all counters are reset after reading the values. .I gplog,ADDR[,FIRST[\-LAST|+SIZE]] \- [ATA only] prints a hex dump of any log accessible via General Purpose Logging (GPL) feature. The log address ADDR is the hex address listed in the log directory (see \'\-l directory\' above). The range of log sectors (pages) can be specified by decimal values FIRST\-LAST or FIRST+SIZE. FIRST defaults to 0, SIZE defaults to 1. LAST can be set to \'max\' to specify the last page of the log. .I smartlog,ADDR[,FIRST[\-LAST|+SIZE]] \- [ATA only] prints a hex dump of any log accessible via SMART Read Log command. See \'\-l gplog,...\' above for parameter syntax. For example, all these commands: .nf smartctl \-l gplog,0x80,10-15 /dev/sda smartctl \-l gplog,0x80,10+6 /dev/sda smartctl \-l smartlog,0x80,10-15 /dev/sda .fi print pages 10-15 of log 0x80 (first host vendor specific log). The hex dump format is compatible with the \'xxd \-r\' command. This command: .nf smartctl \-l gplog,0x11 /dev/sda | grep ^0 | xxd -r >log.bin .fi writes a binary representation of the one sector log 0x11 (SATA Phy Event Counters) to file log.bin. .I ssd \- [ATA] prints the Solid State Device Statistics log page. This has the same effect as \'\-l devstat,7\', see above. .I ssd \- [SCSI] prints the Solid State Media percentage used endurance indicator. A value of 0 indicates as new condition while 100 indicates the device is at the end of its lifetime as projected by the manufacturer. The value may reach 255. .TP .B \-v ID,FORMAT[:BYTEORDER][,NAME], \-\-vendorattribute=ID,FORMAT[:BYTEORDER][,NAME] [ATA only] Sets a vendor-specific raw value print FORMAT, an optional BYTEORDER and an optional NAME for Attribute ID. This option may be used multiple times. The Attribute ID can be in the range 1 to 255. If \'N\' is specified as ID, the settings for all Attributes are changed. The optional BYTEORDER consists of 1 to 8 characters from the set \'012345rvwz\'. The characters \'0\' to \'5\' select the byte 0 to 5 from the 48-bit raw value, \'r\' selects the reserved byte of the attribute data block, \'v\' selects the normalized value, \'w\' selects the worst value and \'z\' inserts a zero byte. The default BYTEORDER is \'543210\' for all 48-bit formats, \'r543210\' for the 54-bit formats, and \'543210wv\' for the 64-bit formats. For example, \'\-v 5,raw48:012345\' prints the raw value of attribute 5 with big endian instead of little endian byte ordering. The NAME is a string of letters, digits and underscore. Its length should not exceed 23 characters. The \'\-P showall\' option reports an error if this is the case. .I \-v help \- Prints (to STDOUT) a list of all valid arguments to this option, then exits. Valid arguments for FORMAT are: .I raw8 \- Print the Raw value as six 8-bit unsigned base-10 integers. This may be useful for decoding the meaning of the Raw value. .I raw16 \- Print the Raw value as three 16-bit unsigned base-10 integers. This may be useful for decoding the meaning of the Raw value. .I raw48 \- Print the Raw value as a 48-bit unsigned base-10 integer. This is the default for most attributes. .I hex48 \- Print the Raw value as a 12 digit hexadecimal number. This may be useful for decoding the meaning of the Raw value. .I raw56 \- Print the Raw value as a 54-bit unsigned base-10 integer. This includes the reserved byte which follows the 48-bit raw value. .I hex56 \- Print the Raw value as a 14 digit hexadecimal number. This includes the reserved byte which follows the 48-bit raw value. .I raw64 \- Print the Raw value as a 64-bit unsigned base-10 integer. This includes two bytes from the normalized and worst attribute value. This raw format is used by some SSD devices with Indilinx controller. .I hex64 \- Print the Raw value as a 16 digit hexadecimal number. This includes two bytes from the normalized and worst attribute value. This raw format is used by some SSD devices with Indilinx controller. .I min2hour \- Raw Attribute is power-on time in minutes. Its raw value will be displayed in the form "Xh+Ym". Here X is hours, and Y is minutes in the range 0\-59 inclusive. Y is always printed with two digits, for example "06" or "31" or "00". .I sec2hour \- Raw Attribute is power-on time in seconds. Its raw value will be displayed in the form "Xh+Ym+Zs". Here X is hours, Y is minutes in the range 0\-59 inclusive, and Z is seconds in the range 0\-59 inclusive. Y and Z are always printed with two digits, for example "06" or "31" or "00". .I halfmin2hour \- Raw Attribute is power-on time, measured in units of 30 seconds. This format is used by some Samsung disks. Its raw value will be displayed in the form "Xh+Ym". Here X is hours, and Y is minutes in the range 0\-59 inclusive. Y is always printed with two digits, for example "06" or "31" or "00". .I msec24hour32 \- Raw Attribute is power-on time measured in 32-bit hours and 24-bit milliseconds since last hour update. It will be displayed in the form "Xh+Ym+Z.Ms". Here X is hours, Y is minutes, Z is seconds and M is milliseconds. .I tempminmax \- Raw Attribute is the disk temperature in Celsius. Info about Min/Max temperature is printed if available. This is the default for Attributes 190 and 194. The recording interval (lifetime, last power cycle, last soft reset) of the min/max values is device specific. .I temp10x \- Raw Attribute is ten times the disk temperature in Celsius. .I raw16(raw16) \- Print the raw attribute as a 16-bit value and two optional 16-bit values if these words are nonzero. This is the default for Attributes 5 and 196. .I raw16(avg16) \- Raw attribute is spin-up time. It is printed as a 16-bit value and an optional "Average" 16-bit value if the word is nonzero. This is the default for Attribute 3. .I raw24(raw8) \- Print the raw attribute as a 24-bit value and three optional 8-bit values if these bytes are nonzero. This is the default for Attribute 9. .I raw24/raw24 \- Raw Attribute contains two 24-bit values. The first is the number of load cycles. The second is the number of unload cycles. The difference between these two values is the number of times that the drive was unexpectedly powered off (also called an emergency unload). As a rule of thumb, the mechanical stress created by one emergency unload is equivalent to that created by one hundred normal unloads. .I raw24/raw32 \- Raw attribute is an error rate which consists of a 24-bit error count and a 32-bit total count. The following old arguments to \'\-v\' are also still valid: .I 9,minutes \- same as: .I 9,min2hour,Power_On_Minutes. .I 9,seconds \- same as: .I 9,sec2hour,Power_On_Seconds. .I 9,halfminutes \- same as: .I 9,halfmin2hour,Power_On_Half_Minutes. .I 9,temp \- same as: .I 9,tempminmax,Temperature_Celsius. .I 192,emergencyretractcyclect \- same as: .I 192,raw48,Emerg_Retract_Cycle_Ct .I 193,loadunload \- same as: .I 193,raw24/raw24. .I 194,10xCelsius \- same as: .I 194,temp10x,Temperature_Celsius_x10. .I 194,unknown \- same as: .I 194,raw48,Unknown_Attribute. .I 197,increasing \- same as: .I 197,raw48,Total_Pending_Sectors. Also means that Attribute number 197 (Current Pending Sector Count) is not reset if uncorrectable sectors are reallocated (see \fBsmartd.conf\fP(5) man page). .I 198,increasing \- same as: .I 198,raw48,Total_Offl_Uncorrectabl. Also means that Attribute number 198 (Offline Uncorrectable Sector Count) is not reset if uncorrectable sectors are reallocated (see \fBsmartd.conf\fP(5) man page). .I 198,offlinescanuncsectorct \- same as: .I 198,raw48,Offline_Scan_UNC_SectCt. .I 200,writeerrorcount \- same as: .I 200,raw48,Write_Error_Count. .I 201,detectedtacount \- same as: .I 201,raw48,Detected_TA_Count. .I 220,temp \- same as: .I 220,tempminmax,Temperature_Celsius. Note: a table of hard drive models, listing which Attribute corresponds to temperature, can be found at: \fBhttp://www.guzu.net/linux/hddtemp.db\fP .TP .B \-F TYPE, \-\-firmwarebug=TYPE [ATA only] Modifies the behavior of \fBsmartctl\fP to compensate for some known and understood device firmware or driver bug. This option may be used multiple times. The valid arguments are: .I none \- Assume that the device firmware obeys the ATA specifications. This is the default, unless the device has presets for \'\-F\' in the drive database. Using this option on the command line will over-ride any preset values. .I nologdir \- Suppresses read attempts of SMART or GP Log Directory. Support for all standard logs is assumed without an actual check. Some Intel SSDs may freeze if log address 0 is read. .I samsung \- In some Samsung disks (example: model SV4012H Firmware Version: RM100-08) some of the two- and four-byte quantities in the SMART data structures are byte-swapped (relative to the ATA specification). Enabling this option tells \fBsmartctl\fP to evaluate these quantities in byte-reversed order. Some signs that your disk needs this option are (1) no self-test log printed, even though you have run self-tests; (2) very large numbers of ATA errors reported in the ATA error log; (3) strange and impossible values for the ATA error log timestamps. .I samsung2 \- In some Samsung disks the number of ATA errors reported is byte swapped. Enabling this option tells \fBsmartctl\fP to evaluate this quantity in byte-reversed order. An indication that your Samsung disk needs this option is that the self-test log is printed correctly, but there are a very large number of errors in the SMART error log. This is because the error count is byte swapped. Thus a disk with five errors (0x0005) will appear to have 20480 errors (0x5000). .I samsung3 \- Some Samsung disks (at least SP2514N with Firmware VF100-37) report a self-test still in progress with 0% remaining when the test was already completed. Enabling this option modifies the output of the self-test execution status (see options \'\-c\' or \'\-a\' above) accordingly. .I xerrorlba \- Fixes LBA byte ordering in Extended Comprehensive SMART error log. Some disk use little endian byte ordering instead of ATA register ordering to specifiy the LBA addresses in the log entries. .I swapid \- Fixes byte swapped ATA identify strings (device name, serial number, firmware version) returned by some buggy device drivers. .TP .B \-P TYPE, \-\-presets=TYPE [ATA only] Specifies whether \fBsmartctl\fP should use any preset options that are available for this drive. By default, if the drive is recognized in the \fBsmartmontools\fP database, then the presets are used. \fBsmartctl\fP can automatically set appropriate options for known drives. For example, the Maxtor 4D080H4 uses Attribute 9 to stores power-on time in minutes whereas most drives use that Attribute to store the power-on time in hours. The command-line option \'\-v 9,minutes\' ensures that \fBsmartctl\fP correctly interprets Attribute 9 in this case, but that option is preset for the Maxtor 4D080H4 and so need not be specified by the user on the \fBsmartctl\fP command line. The argument .I show will show any preset options for your drive and the argument .I showall will show all known drives in the \fBsmartmontools\fP database, along with their preset options. If there are no presets for your drive and you think there should be (for example, a \-v or \-F option is needed to get \fBsmartctl\fP to display correct values) then please contact the \fBsmartmontools\fP developers so that this information can be added to the \fBsmartmontools\fP database. Contact information is at the end of this man page. The valid arguments to this option are: .I use \- if a drive is recognized, then use the stored presets for it. This is the default. Note that presets will NOT override additional Attribute interpretation (\'\-v N,something\') command-line options or explicit \'\-F\' command-line options.. .I ignore \- do not use presets. .I show \- show if the drive is recognized in the database, and if so, its presets, then exit. .I showall \- list all recognized drives, and the presets that are set for them, then exit. This also checks the drive database regular expressions and settings for syntax errors. The \'\-P showall\' option takes up to two optional arguments to match a specific drive type and firmware version. The command: .nf smartctl \-P showall .fi lists all entries, the command: .nf smartctl \-P showall \'MODEL\' .fi lists all entries matching MODEL, and the command: .nf smartctl \-P showall \'MODEL\' \'FIRMWARE\' .fi lists all entries for this MODEL and a specific FIRMWARE version. .TP .B \-B [+]FILE, \-\-drivedb=[+]FILE [ATA only] Read the drive database from FILE. The new database replaces the built in database by default. If \'+\' is specified, then the new entries prepend the built in entries. Optional entries are read from the file .\" %IF NOT OS Windows \fB/usr/local/etc/smart_drivedb.h\fP .\" %ENDIF NOT OS Windows .\" %IF OS ALL (Windows: \fBEXEDIR/drivedb-add.h\fP) .\" %ENDIF OS ALL .\" %IF OS Windows .\"! \fBEXEDIR/drivedb-add.h\fP. .\" %ENDIF OS Windows .\" %IF ENABLE_DRIVEDB if this option is not specified. If .\" %IF NOT OS Windows \fB/usr/local/share/smartmontools/drivedb.h\fP .\" %ENDIF NOT OS Windows .\" %IF OS ALL (Windows: \fBEXEDIR/drivedb.h\fP) .\" %ENDIF OS ALL .\" %IF OS Windows .\"! \fBEXEDIR/drivedb.h\fP .\" %ENDIF OS Windows is present, the contents of this file is used instead of the built in table. Run .\" %IF NOT OS Windows \fB/usr/local/sbin/update-smart-drivedb\fP .\" %ENDIF NOT OS Windows .\" %IF OS ALL (Windows: \fBEXEDIR/update-smart-drivedb.exe\fP) .\" %ENDIF OS ALL .\" %IF OS Windows .\"! \fBEXEDIR/update-smart-drivedb.exe\fP .\" %ENDIF OS Windows to update this file from the smartmontools SVN repository. .\" %ENDIF ENABLE_DRIVEDB The database files use the same C/C++ syntax that is used to initialize the built in database array. C/C++ style comments are allowed. Example: .nf /* Full entry: */ { "Model family", // Info about model family/series. "MODEL1.*REGEX", // Regular expression to match model of device. "VERSION.*REGEX", // Regular expression to match firmware version(s). "Some warning", // Warning message. "\-v 9,minutes" // String of preset \-v and \-F options. }, /* Minimal entry: */ { "", // No model family/series info. "MODEL2.*REGEX", // Regular expression to match model of device. "", // All firmware versions. "", // No warning. "" // No options preset. }, /* USB ID entry: */ { "USB: Device; Bridge", // Info about USB device and bridge name. "0x1234:0xabcd", // Regular expression to match vendor:product ID. "0x0101", // Regular expression to match bcdDevice. "", // Not used. "\-d sat" // String with device type option. }, /* ... */ .fi .TP .B SMART RUN/ABORT OFFLINE TEST AND self-test OPTIONS: .TP .B \-t TEST, \-\-test=TEST Executes TEST immediately. The \'\-C\' option can be used in conjunction with this option to run the short or long (and also for ATA devices, selective or conveyance) self-tests in captive mode (known as "foreground mode" for SCSI devices). Note that only one test type can be run at a time, so only one test type should be specified per command line. Note also that if a computer is shutdown or power cycled during a self-test, no harm should result. The self-test will either be aborted or will resume automatically. All \'\-t TEST\' commands can be given during normal system operation unless captive mode (\'\-C\' option) is used. A running self-test can, however, degrade performance of the drive. Frequent I/O requests from the operating system increase the duration of a test. These impacts may vary from device to device. If a test failure occurs then the device may discontinue the testing and report the result immediately. The valid arguments to this option are: .I offline \- [ATA] runs SMART Immediate Offline Test. This immediately starts the test described above. This command can be given during normal system operation. The effects of this test are visible only in that it updates the SMART Attribute values, and if errors are found they will appear in the SMART error log, visible with the \'\-l error\' option. If the \'\-c\' option to \fBsmartctl\fP shows that the device has the "Suspend Offline collection upon new command" capability then you can track the progress of the Immediate Offline test using the \'\-c\' option to \fBsmartctl\fP. If the \'\-c\' option show that the device has the "Abort Offline collection upon new command" capability then most commands will abort the Immediate Offline Test, so you should not try to track the progress of the test with \'\-c\', as it will abort the test. .I offline \- [SCSI] runs the default self test in foreground. No entry is placed in the self test log. .I short \- [ATA] runs SMART Short Self Test (usually under ten minutes). This command can be given during normal system operation (unless run in captive mode \- see the \'\-C\' option below). This is a test in a different category than the immediate or automatic offline tests. The "Self" tests check the electrical and mechanical performance as well as the read performance of the disk. Their results are reported in the Self Test Error Log, readable with the \'\-l selftest\' option. Note that on some disks the progress of the self-test can be monitored by watching this log during the self-test; with other disks use the \'\-c\' option to monitor progress. .I short \- [SCSI] runs the "Background short" self-test. .I long \- [ATA] runs SMART Extended Self Test (tens of minutes). This is a longer and more thorough version of the Short Self Test described above. Note that this command can be given during normal system operation (unless run in captive mode \- see the \'\-C\' option below). .I long \- [SCSI] runs the "Background long" self-test. .I conveyance \- [ATA only] runs a SMART Conveyance Self Test (minutes). This self-test routine is intended to identify damage incurred during transporting of the device. This self-test routine should take on the order of minutes to complete. Note that this command can be given during normal system operation (unless run in captive mode \- see the \'\-C\' option below). .I select,N\-M, select,N+SIZE \- [ATA only] runs a SMART Selective Self Test, to test a \fBrange\fP of disk Logical Block Addresses (LBAs), rather than the entire disk. Each range of LBAs that is checked is called a "span" and is specified by a starting LBA (N) and an ending LBA (M) with N less than or equal to M. The range can also be specified as N+SIZE. A span at the end of a disk can be specified by N\-\fBmax\fP. For example the commands: .nf smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10+11 /dev/hda .fi both runs a self test on one span consisting of LBAs ten to twenty (inclusive). The command: .nf smartctl \-t select,100000000\-max /dev/hda .fi run a self test from LBA 100000000 up to the end of the disk. The \'\-t\' option can be given up to five times, to test up to five spans. For example the command: .nf smartctl \-t select,0\-100 \-t select,1000\-2000 /dev/hda .fi runs a self test on two spans. The first span consists of 101 LBAs and the second span consists of 1001 LBAs. Note that the spans can overlap partially or completely, for example: .nf smartctl \-t select,0\-10 \-t select,5\-15 \-t select,10\-20 /dev/hda .fi The results of the selective self-test can be obtained (both during and after the test) by printing the SMART self-test log, using the \'\-l selftest\' option to smartctl. Selective self tests are particularly useful as disk capacities increase: an extended self test (smartctl \-t long) can take several hours. Selective self-tests are helpful if (based on SYSLOG error messages, previous failed self-tests, or SMART error log entries) you suspect that a disk is having problems at a particular range of Logical Block Addresses (LBAs). Selective self-tests can be run during normal system operation (unless done in captive mode \- see the \'\-C\' option below). The following variants of the selective self-test command use spans based on the ranges from past tests already stored on the disk: .I select,redo[+SIZE] \- [ATA only] redo the last SMART Selective Self Test using the same LBA range. The starting LBA is identical to the LBA used by last test, same for ending LBA unless a new span size is specified by optional +SIZE argument. For example the commands: .nf smartctl \-t select,10\-20 /dev/hda smartctl \-t select,redo /dev/hda smartctl \-t select,redo+20 /dev/hda .fi have the same effect as: .nf smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10\-20 /dev/hda smartctl \-t select,10\-29 /dev/hda .fi .I select,next[+SIZE] \- [ATA only] runs a SMART Selective Self Test on the LBA range which follows the range of the last test. The starting LBA is set to (ending LBA +1) of the last test. A new span size may be specified by the optional +SIZE argument. For example the commands: .nf smartctl \-t select,0\-999 /dev/hda smartctl \-t select,next /dev/hda smartctl \-t select,next+2000 /dev/hda .fi have the same effect as: .nf smartctl \-t select,0\-999 /dev/hda smartctl \-t select,1000\-1999 /dev/hda smartctl \-t select,2000\-3999 /dev/hda .fi If the last test ended at the last LBA of the disk, the new range starts at LBA 0. The span size of the last span of a disk is adjusted such that the total number of spans to check the full disk will not be changed by future uses of \'\-t select,next\'. .I select,cont[+SIZE] \- [ATA only] performs a \'redo\' (above) if the self test status reports that the last test was aborted by the host. Otherwise it run the \'next\' (above) test. .I afterselect,on \- [ATA only] perform an offline read scan after a Selective self-test has completed. This option must be used together with one or more of the \fIselect,N\-M\fP options above. If the LBAs that have been specified in the Selective self-test pass the test with no errors found, then read scan the \fBremainder\fP of the disk. If the device is powered-cycled while this read scan is in progress, the read scan will be automatically resumed after a time specified by the pending timer (see below). The value of this option is preserved between selective self-tests. .I afterselect,off \- [ATA only] do not read scan the remainder of the disk after a Selective self-test has completed. This option must be use together with one or more of the \fIselect,N\-M\fP options above. The value of this option is preserved between selective self-tests. .I pending,N \- [ATA only] set the pending offline read scan timer to N minutes. Here N is an integer in the range from 0 to 65535 inclusive. If the device is powered off during a read scan after a Selective self-test, then resume the test automatically N minutes after power-up. This option must be use together with one or more of the \fIselect,N\-M\fP options above. The value of this option is preserved between selective self-tests. .I vendor,N \- [ATA only] issues the ATA command SMART EXECUTE OFF-LINE IMMEDIATE with subcommand N in LBA LOW register. The subcommand is specified as a hex value in the range 0x00 to 0xff. Subcommands 0x40-0x7e and 0x90-0xff are reserved for vendor specific use, see table 61 of T13/1699-D Revision 6a (ATA8-ACS). Note that the subcommands 0x00-0x04,0x7f,0x81-0x84 are supported by other smartctl options (e.g. 0x01: \'\-t short\', 0x7f: \'\-X\', 0x82: \'\-C \-t long\'). \fBWARNING: Only run subcommands documented by the vendor of the device.\fP Example for Intel (X18/X25-M G2, 320, 520 and 710 Series) SSDs only: The subcommand 0x40 (\'\-t vendor,0x40\') clears the timed workload related SMART attributes (226, 227, 228). Note that the raw values of these attributes are held at 65535 (0xffff) until the workload timer reaches 60 minutes. .I force \- start new self-test even if another test is already running. By default a running self-test will not be interrupted to begin another test. .TP .B \-C, \-\-captive [ATA] Runs self-tests in captive mode. This has no effect with \'\-t offline\' or if the \'\-t\' option is not used. \fBWARNING: Tests run in captive mode may busy out the drive for the length of the test. Only run captive tests on drives without any mounted partitions!\fP [SCSI] Runs the self-test in "Foreground" mode. .TP .B \-X, \-\-abort Aborts non-captive SMART Self Tests. Note that this command will abort the Offline Immediate Test routine only if your disk has the "Abort Offline collection upon new command" capability. .PP .SH ATA, SCSI command sets and SAT In the past there has been a clear distinction between storage devices that used the ATA and SCSI command sets. This distinction was often reflected in their device naming and hardware. Now various SCSI transports (e.g. SAS, FC and iSCSI) can interconnect to both SCSI disks (e.g. FC and SAS) and ATA disks (especially SATA). USB and IEEE 1394 storage devices use the SCSI command set externally but almost always contain ATA or SATA disks (or flash). The storage subsystems in some operating systems have started to remove the distinction between ATA and SCSI in their device naming policies. .PP 99% of operations that an OS performs on a disk involve the SCSI INQUIRY, READ CAPACITY, READ and WRITE commands, or their ATA equivalents. Since the SCSI commands are slightly more general than their ATA equivalents, many OSes are generating SCSI commands (mainly READ and WRITE) and letting a lower level translate them to their ATA equivalents as the need arises. An important note here is that "lower level" may be in external equipment and hence outside the control of an OS. .PP SCSI to ATA Translation (SAT) is a standard (ANSI INCITS 431-2007) that specifies how this translation is done. For the other 1% of operations that an OS performs on a disk, SAT provides two options. First is an optional ATA PASS-THROUGH SCSI command (there are two variants). The second is a translation from the closest SCSI command. Most current interest is in the "pass-through" option. .PP The relevance to smartmontools (and hence smartctl) is that its interactions with disks fall solidly into the "1%" category. So even if the OS can happily treat (and name) a disk as "SCSI", smartmontools needs to detect the native command set and act accordingly. As more storage manufacturers (including external SATA drives) comply with SAT, smartmontools is able to automatically distinguish the native command set of the device. In some cases the '\-d sat' option is needed on the command line. .PP There are also virtual disks which typically have no useful information to convey to smartmontools, but could conceivably in the future. An example of a virtual disk is the OS's view of a RAID 1 box. There are most likely two SATA disks inside a RAID 1 box. Addressing those SATA disks from a distant OS is a challenge for smartmontools. Another approach is running a tool like smartmontools inside the RAID 1 box (e.g. a Network Attached Storage (NAS) box) and fetching the logs via a browser. .PP .SH EXAMPLES .nf .B smartctl \-a /dev/hda .fi Print a large amount of SMART information for drive /dev/hda which is typically an ATA (IDE) or SATA disk in Linux. .PP .nf .B smartctl \-a /dev/sdb .fi Print a large amount of SMART information for drive /dev/sdb . This may be a SCSI disk or an ATA (SATA) disk. .PP .nf .B smartctl \-s off /dev/hdd .fi Disable SMART monitoring and data log collection on drive /dev/hdd . .PP .nf .B smartctl \-\-smart=on \-\-offlineauto=on \-\-saveauto=on /dev/hda .fi Enable SMART on drive /dev/hda, enable automatic offline testing every four hours, and enable autosaving of SMART Attributes. This is a good start-up line for your system\'s init files. You can issue this command on a running system. .PP .nf .B smartctl \-t long /dev/hdc .fi Begin an extended self-test of drive /dev/hdc. You can issue this command on a running system. The results can be seen in the self-test log visible with the \'\-l selftest\' option after it has completed. .PP .nf .B smartctl \-s on \-t offline /dev/hda .fi Enable SMART on the disk, and begin an immediate offline test of drive /dev/hda. You can issue this command on a running system. The results are only used to update the SMART Attributes, visible with the \'\-A\' option. If any device errors occur, they are logged to the SMART error log, which can be seen with the \'\-l error\' option. .PP .nf .B smartctl \-A \-v 9,minutes /dev/hda .fi Shows the vendor Attributes, when the disk stores its power-on time internally in minutes rather than hours. .PP .nf .B smartctl \-q errorsonly \-H \-l selftest /dev/hda .fi Produces output only if the device returns failing SMART status, or if some of the logged self-tests ended with errors. .PP .nf .B smartctl \-q silent \-a /dev/hda .fi Examine all SMART data for device /dev/hda, but produce no printed output. You must use the exit status (the .B $? shell variable) to learn if any Attributes are out of bound, if the SMART status is failing, if there are errors recorded in the self-test log, or if there are errors recorded in the disk error log. .PP .nf .B smartctl \-a \-d 3ware,0 /dev/sda .fi Examine all SMART data for the first ATA disk connected to a 3ware RAID controller card. .PP .nf .B smartctl \-a \-d 3ware,0 /dev/twe0 .fi Examine all SMART data for the first ATA disk connected to a 3ware RAID 6000/7000/8000 controller card. .PP .nf .B smartctl \-a \-d 3ware,0 /dev/twa0 .fi Examine all SMART data for the first ATA disk connected to a 3ware RAID 9000 controller card. .PP .nf .B smartctl \-a \-d 3ware,0 /dev/twl0 .fi Examine all SMART data for the first SATA (not SAS) disk connected to a 3ware RAID 9750 controller card. .PP .nf .B smartctl \-t short \-d 3ware,3 /dev/sdb .fi Start a short self-test on the fourth ATA disk connected to the 3ware RAID controller card which is the second SCSI device /dev/sdb. .PP .nf .B smartctl \-t long \-d areca,4 /dev/sg2 .fi Start a long self-test on the fourth SATA disk connected to an Areca RAID controller addressed by /dev/sg2. .PP .nf .B smartctl \-a \-d hpt,1/3 /dev/sda (under Linux) .B smartctl \-a \-d hpt,1/3 /dev/hptrr (under FreeBSD) .fi Examine all SMART data for the (S)ATA disk directly connected to the third channel of the first HighPoint RocketRAID controller card. .nf .PP .nf .B smartctl \-t short \-d hpt,1/1/2 /dev/sda (under Linux) .B smartctl \-t short \-d hpt,1/1/2 /dev/hptrr (under FreeBSD) .fi Start a short self-test on the (S)ATA disk connected to second pmport on the first channel of the first HighPoint RocketRAID controller card. .PP .nf .B smartctl \-t select,10\-100 \-t select,30\-300 \-t afterselect,on \-t pending,45 /dev/hda .fi Run a selective self-test on LBAs 10 to 100 and 30 to 300. After the these LBAs have been tested, read-scan the remainder of the disk. If the disk is power-cycled during the read-scan, resume the scan 45 minutes after power to the device is restored. .PP .nf .B smartctl \-a \-d cciss,0 /dev/cciss/c0d0 .fi Examine all SMART data for the first SCSI disk connected to a cciss RAID controller card. .PP .SH RETURN VALUES The return values of \fBsmartctl\fP are defined by a bitmask. If all is well with the disk, the return value (exit status) of \fBsmartctl\fP is 0 (all bits turned off). If a problem occurs, or an error, potential error, or fault is detected, then a non-zero status is returned. In this case, the eight different bits in the return value have the following meanings for ATA disks; some of these values may also be returned for SCSI disks. .TP .B Bit 0: Command line did not parse. .TP .B Bit 1: Device open failed, device did not return an IDENTIFY DEVICE structure, or device is in a low-power mode (see \'\-n\' option above). .TP .B Bit 2: Some SMART or other ATA command to the disk failed, or there was a checksum error in a SMART data structure (see \'\-b\' option above). .TP .B Bit 3: SMART status check returned "DISK FAILING". .TP .B Bit 4: 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. .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. [ATA only] Failed self-tests outdated by a newer successful extended self-test are ignored. .PP To test within the shell for whether or not the different bits are turned on or off, you can use the following type of construction (this is bash syntax): .nf .B smartstat=$(($? & 8)) .fi This looks at only at bit 3 of the exit status .B $? (since 8=2^3). The shell variable $smartstat will be nonzero if SMART status check returned "disk failing" and zero otherwise. This bash script prints all status bits: .nf status=$? for ((i=0; i<8; i++)); do echo "Bit $i: $((status & 2**i && 1))" done .fi .PP .SH NOTES The TapeAlert log page flags are cleared for the initiator when the page is read. This means that each alert condition is reported only once by \fBsmartctl\fP for each initiator for each activation of the condition. .PP .SH AUTHORS \fBBruce Allen\fP .br University of Wisconsin \- Milwaukee Physics Department .br \fBChristian Franke\fP (Windows interface, C++ redesign, most enhancements since 2009) .br \fBsmartmontools\-support@lists.sourceforge.net\fP .PP .SH CONTRIBUTORS The following have made large contributions to smartmontools: .nf \fBCasper Dik\fP (Solaris SCSI interface) \fBDouglas Gilbert\fP (SCSI subsystem) \fBGuido Guenther\fP (Autoconf/Automake packaging) \fBGeoffrey Keating\fP (Darwin ATA interface) \fBEduard Martinescu\fP (FreeBSD interface) \fBFr\['e]d\['e]ric L. W. Meunier\fP (Web site and Mailing list) \fBGabriele Pohl\fP (Web site and Wiki, conversion from CVS to SVN) \fBKeiji Sawada\fP (Solaris ATA interface) \fBManfred Schwarb\fP (Drive database) \fBSergey Svishchev\fP (NetBSD interface) \fBDavid Snyder and Sergey Svishchev\fP (OpenBSD interface) \fBPhil Williams\fP (User interface and drive database) \fBYuri Dario\fP (OS/2, eComStation interface) \fBShengfeng Zhou\fP (Linux/FreeBSD HighPoint RocketRAID interface) .fi Many other individuals have made smaller contributions and corrections. .PP .SH CREDITS .fi This code was derived from the smartsuite package, written by Michael Cornwell, and from the previous UCSC smartsuite package. It extends these to cover ATA-5 disks. This code was originally developed as a Senior Thesis by Michael Cornwell at the Concurrent Systems Laboratory (now part of the Storage Systems Research Center), Jack Baskin School of Engineering, University of California, Santa Cruz. \fBhttp://ssrc.soe.ucsc.edu/\fP . .SH HOME PAGE FOR SMARTMONTOOLS: .fi Please see the following web site for updates, further documentation, bug reports and patches: \fBhttp://smartmontools.sourceforge.net/\fP .SH SEE ALSO: \fBsmartd\fP(8), \fBbadblocks\fP(8), \fBide\-smart\fP(8). .SH REFERENCES FOR SMART .fi An introductory article about smartmontools is \fIMonitoring Hard Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004, pages 74-77. This is \fBhttp://www.linuxjournal.com/article/6983\fP online. If you would like to understand better how SMART works, and what it does, a good place to start is with Sections 4.8 and 6.54 of the first volume of the \'AT Attachment with Packet Interface-7\' (ATA/ATAPI-7) specification Revision 4b. This documents the SMART functionality which the \fBsmartmontools\fP utilities provide access to. .fi The functioning of SMART was originally defined by the SFF-8035i revision 2 and the SFF-8055i revision 1.4 specifications. These are publications of the Small Form Factors (SFF) Committee. Links to these and other documents may be found on the Links page of the \fBsmartmontools\fP Wiki at \fBhttp://sourceforge.net/apps/trac/smartmontools/wiki/Links\fP . .SH SVN ID OF THIS PAGE: $Id: smartctl.8.in 3832 2013-07-20 14:49:31Z chrfranke $ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_generic.cpp�������������������������������������������������������0000644�0000000�0000000�00000021551�12002315124�017674� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_generic.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008 Christian Franke <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * */ /* NOTE: The code in this file is only called when smartmontools has been compiled on an unrecognized/unsupported platform. This file can then serve as a "template" to make os_myOS.cpp if you wish to build support for that platform. PORTING NOTES AND COMMENTS -------------------------- To port smartmontools to the OS of your choice, please: [0] Contact smartmontools-support@lists.sourceforge.net to check that it's not already been done. [1] Make copies of os_generic.h and os_generic.cpp called os_myOS.h and os_myOS.cpp . [2] Modify configure.in so that case "${host}" includes myOS. [3] Verify that ./autogen.sh && ./configure && make compiles the code. If not, fix any compilation problems. If your OS lacks some function that is used elsewhere in the code, then add a AC_CHECK_FUNCS([missingfunction]) line to configure.in, and surround uses of the function with: #ifdef HAVE_MISSINGFUNCTION ... #endif where the macro HAVE_MISSINGFUNCTION is (or is not) defined in config.h. [4] Now that you have a working build environment, you have to replace the 'stub' function calls provided in this file. Provide the functions defined in this file by fleshing out the skeletons below. You can entirely eliminate the function 'unsupported()'. [5] Contact smartmontools-support@lists.sourceforge.net to see about checking your code into the smartmontools CVS archive. */ /* Developer's note: for testing this file, use an unsupported system, for example: ./configure --build=rs6000-ibm-aix && make */ // This is needed for the various HAVE_* macros and PROJECT_* macros. #include "config.h" // These are needed to define prototypes and structures for the // functions defined below #include "int64.h" #include "atacmds.h" #include "utility.h" // This is to include whatever structures and prototypes you define in // os_generic.h #include "os_generic.h" // Needed by '-V' option (CVS versioning) of smartd/smartctl. You // should have one *_H_CVSID macro appearing below for each file // appearing with #include "*.h" above. Please list these (below) in // alphabetic/dictionary order. const char * os_XXXX_cpp_cvsid="$Id: os_generic.cpp 3579 2012-07-20 17:50:12Z chrfranke $" ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_GENERIC_H_CVSID UTILITY_H_CVSID; // This is here to prevent compiler warnings for unused arguments of // functions. #define ARGUSED(x) ((void)(x)) // Please eliminate the following block: both the #include and // the 'unsupported()' function. They are only here to warn // unsuspecting users that their Operating System is not supported! If // you wish, you can use a similar warning mechanism for any of the // functions in this file that you can not (or choose not to) // implement. #ifdef HAVE_UNAME #include <sys/utsname.h> #endif static void unsupported(){ static int warninggiven; if (!warninggiven) { char *osname; #ifdef HAVE_UNAME struct utsname ostype; uname(&ostype); osname=ostype.sysname; #else osname="host's"; #endif pout("\n" "############################################################################\n" "WARNING: smartmontools has not been ported to the %s Operating System.\n" "Please see the files os_generic.cpp and os_generic.h for porting instructions.\n" "############################################################################\n\n", osname); warninggiven=1; } return; } // End of the 'unsupported()' block that you should eliminate. // print examples for smartctl. You should modify this function so // that the device paths are sensible for your OS, and to eliminate // unsupported commands (eg, 3ware controllers). static void print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); #ifdef HAVE_GETOPT_LONG printf( " smartctl -a /dev/hda (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hda\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a --device=3ware,2 /dev/sda\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" ); #else printf( " smartctl -a /dev/hda (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/hda (Enables SMART on first disk)\n" " smartctl -t long /dev/hda (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/hda\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a -d 3ware,2 /dev/sda\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" ); #endif return; } ///////////////////////////////////////////////////////////////////////////// namespace generic { // No need to publish anything, name provided for Doxygen class generic_smart_interface : public /*implements*/ smart_interface { public: #ifdef HAVE_GET_OS_VERSION_STR virtual const char * get_os_version_str(); #endif virtual std::string get_app_examples(const char * appname); virtual bool scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern = 0); protected: virtual ata_device * get_ata_device(const char * name, const char * type); virtual scsi_device * get_scsi_device(const char * name, const char * type); virtual smart_device * autodetect_smart_device(const char * name); virtual smart_device * get_custom_smart_device(const char * name, const char * type); virtual std::string get_valid_custom_dev_types_str(); }; ////////////////////////////////////////////////////////////////////// #ifdef HAVE_GET_OS_VERSION_STR /// Return build host and OS version as static string const char * generic_smart_interface::get_os_version_str() { return ::get_os_version_str(); } #endif std::string generic_smart_interface::get_app_examples(const char * appname) { if (!strcmp(appname, "smartctl")) ::print_smartctl_examples(); // this prints to stdout ... return ""; // ... so don't print again. } // Return ATA device object for the given device name or NULL // the type is always set to "ata" ata_device * generic_smart_interface::get_ata_device(const char * name, const char * type) { ARGUSED(name); ARGUSED(type); unsupported(); return NULL; } // Return SCSI device object for the given device name or NULL // the type is always set to "scsi" scsi_device * generic_smart_interface::get_scsi_device(const char * name, const char * type) { ARGUSED(name); ARGUSED(type); unsupported(); return NULL; } // Return device object for the given device name (autodetect the device type) smart_device * generic_smart_interface::autodetect_smart_device(const char * name) { ARGUSED(name); // for the given name return the apropriate device type unsupported(); return NULL; } // Fill devlist with all OS's disk devices of given type that match the pattern bool generic_smart_interface::scan_smart_devices(smart_device_list & devlist, const char * type, const char * pattern /*= 0*/) { ARGUSED(devlist); ARGUSED(type); ARGUSED(pattern); unsupported(); return false; } // Return device object of the given type with specified name or NULL smart_device * generic_smart_interface::get_custom_smart_device(const char * name, const char * type) { ARGUSED(name); ARGUSED(type); unsupported(); return NULL; } std::string generic_smart_interface::get_valid_custom_dev_types_str() { return ""; } } // namespace ///////////////////////////////////////////////////////////////////////////// /// Initialize platform interface and register with smi() void smart_interface::init() { static generic::generic_smart_interface the_interface; smart_interface::set(&the_interface); } �������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_generic.h���������������������������������������������������������0000644�0000000�0000000�00000002667�12062413436�017363� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_generic.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) YEAR YOUR_NAME <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ // In the three following lines, change 'GENERIC' to your OS name #ifndef OS_GENERIC_H_ #define OS_GENERIC_H_ #define OS_GENERIC_H_CVSID "$Id: os_generic.h 3728 2012-12-13 17:57:50Z chrfranke $\n" // Additional material should start here. Note: to keep the '-V' CVS // reporting option working as intended, you should only #include // system include files <something.h>. Local #include files // <"something.h"> should be #included in os_generic.c #endif /* OS_GENERIC_H_ */ �������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_os2.h�������������������������������������������������������������0000644�0000000�0000000�00000005424�12062413436�016444� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_os2.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2004-8 Yuri Dario <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef OS_OS2_H_ #define OS_OS2_H_ #define OS_XXXX_H_CVSID "$Id: os_os2.h 3728 2012-12-13 17:57:50Z chrfranke $\n" // Additional material should start here. Note: to keep the '-V' CVS // reporting option working as intended, you should only #include // system include files <something.h>. Local #include files // <"something.h"> should be #included in os_generic.c #define INCL_DOS #include <os2.h> #include "os_os2\hdreg.h" #include "os_linux.h" #pragma pack(1) #define DSKSP_CAT_SMART 0x80 /* SMART IOCTL category */ #define DSKSP_SMART_ONOFF 0x20 /* turn SMART on or off */ #define DSKSP_SMART_AUTOSAVE_ONOFF 0x21 /* turn SMART autosave on or off */ #define DSKSP_SMART_SAVE 0x22 /* force save of SMART data */ #define DSKSP_SMART_GETSTATUS 0x23 /* get SMART status (pass/fail) */ #define DSKSP_SMART_GET_ATTRIBUTES 0x24 /* get SMART attributes table */ #define DSKSP_SMART_GET_THRESHOLDS 0x25 /* get SMART thresholds table */ #define DSKSP_SMART_READ_LOG 0x26 #define DSKSP_SMART_WRITE_LOG 0x27 #define DSKSP_SMART_READ_LOG_EXT 0x28 #define DSKSP_SMART_WRITE_LOG_EXT 0x29 #define DSKSP_SMART_EOLI 0x30 /* EXECUTE OFF-LINE IMMEDIATE */ #define SMART_CMD_ON 1 /* on value for related SMART functions */ #define SMART_CMD_OFF 0 /* off value for related SMART functions */ #define DSKSP_CAT_GENERIC 0x90 /* generic IOCTL category */ #define DSKSP_GET_INQUIRY_DATA 0x42 /* get ATA/ATAPI inquiry data */ typedef struct _DSKSP_CommandParameters { BYTE byPhysicalUnit; /* physical unit number 0-n */ /* 0 = 1st disk, 1 = 2nd disk, ...*/ /* 0x80 = Pri/Mas, 0x81=Pri/Sla, 0x82=Sec/Mas,*/ } DSKSP_CommandParameters, *PDSKSP_CommandParameters; struct SMART_ParamExt { UCHAR byPhysicalUnit; // 0=Pri/Mas, 1=Pri/Sla, 2=Sec/Mas, etc. ULONG LogAddress; // valid values 0-255. See ATA/ATPI standard // for details ULONG SectorCount; // valid values 0-255 See ATA/ATPI standard // for details ULONG reserved; // reserved. must be set to 0 }; #endif /* OS_GENERIC_H_ */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_solaris.cpp�������������������������������������������������������0000644�0000000�0000000�00000032125�12125373277�017756� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * os_solaris.c * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2003-8 Casper Dik <smartmontools-support@lists.sourceforge.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include <stdlib.h> #include <ctype.h> #include <string.h> #include <dirent.h> #include <stdio.h> #include <unistd.h> #include <sys/param.h> // These are needed to define prototypes for the functions defined below #include "config.h" #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "utility.h" // This is to include whatever prototypes you define in os_solaris.h #include "os_solaris.h" #define ARGUSED(x) ((void)(x)) extern long long bytes; static const char *filenameandversion="$Id: os_solaris.cpp 3806 2013-03-29 20:17:03Z chrfranke $"; const char *os_XXXX_c_cvsid="$Id: os_solaris.cpp 3806 2013-03-29 20:17:03Z chrfranke $" \ ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_SOLARIS_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; // The printwarning() function warns about unimplemented functions int printedout[2]; char *unimplemented[2]={ "ATA command routine ata_command_interface()", "3ware Escalade Controller command routine escalade_command_interface()", }; int printwarning(int which){ if (!unimplemented[which]) return 0; if (printedout[which]) return 1; printedout[which]=1; pout("\n" "#######################################################################\n" "%s NOT IMPLEMENTED under Solaris.\n" "Please contact " PACKAGE_BUGREPORT " if\n" "you want to help in porting smartmontools to Solaris.\n" "#######################################################################\n" "\n", unimplemented[which]); return 1; } // print examples for smartctl void print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); #ifdef HAVE_GETOPT_LONG printf( " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/rdsk/c0t0d0s0\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/rdsk/c0t0d0s0\n" " (Prints Self-Test & Attribute errors)\n" ); #else printf( " smartctl -a /dev/rdsk/c0t0d0s0 (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/rdsk/c0t0d0s0 (Enables SMART on first disk)\n" " smartctl -t long /dev/rdsk/c0t0d0s0 (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/rdsk/c0t0d0s0\n" " (Prints Self-Test & Attribute errors)\n" ); #endif return; } static const char *uscsidrvrs[] = { "sd", "ssd", "st" }; static const char *atadrvrs[] = { "cmdk", "dad", }; static int isdevtype(const char *dev_name, const char *table[], int tsize) { char devpath[MAXPATHLEN]; int i; char *basename; if (realpath(dev_name, devpath) == NULL) return 0; if ((basename = strrchr(devpath, '/')) == NULL) return 0; basename++; for (i = 0; i < tsize; i++) { int l = strlen(table[i]); if (strncmp(basename, table[i], l) == 0 && basename[l] == '@') return 1; } return 0; } static int isscsidev(const char *path) { return isdevtype(path, uscsidrvrs, sizeof (uscsidrvrs) / sizeof (char *)); } static int isatadev(const char *path) { return isdevtype(path, atadrvrs, sizeof (atadrvrs) / sizeof (char *)); } // tries to guess device type given the name (a path) int guess_device_type (const char* dev_name) { if (isscsidev(dev_name)) return CONTROLLER_SCSI; else if (isatadev(dev_name)) return CONTROLLER_ATA; else return CONTROLLER_UNKNOWN; } struct pathlist { char **names; int nnames; int maxnames; }; static int addpath(const char *path, struct pathlist *res) { if (++res->nnames > res->maxnames) { res->maxnames += 16; res->names = static_cast<char**>(realloc(res->names, res->maxnames * sizeof (char *))); if (res->names == NULL) return -1; bytes += 16*sizeof(char *); } if (!(res->names[res->nnames-1] = CustomStrDup((char *)path, 1, __LINE__, filenameandversion))) return -1; return 0; } static int grokdir(const char *dir, struct pathlist *res, int testfun(const char *)) { char pathbuf[MAXPATHLEN]; size_t len; DIR *dp; struct dirent *de; int isdisk = strstr(dir, "dsk") != NULL; char *p; len = snprintf(pathbuf, sizeof (pathbuf), "%s/", dir); if (len >= sizeof (pathbuf)) return -1; dp = opendir(dir); if (dp == NULL) return 0; while ((de = readdir(dp)) != NULL) { if (de->d_name[0] == '.') continue; if (strlen(de->d_name) + len >= sizeof (pathbuf)) continue; if (isdisk) { /* Disk represented by slice 0 */ p = strstr(de->d_name, "s0"); /* String doesn't end in "s0\0" */ if (p == NULL || p[2] != '\0') continue; } else { /* Tape drive represented by the all-digit device */ for (p = de->d_name; *p; p++) if (!isdigit((int)(*p))) break; if (*p != '\0') continue; } strcpy(&pathbuf[len], de->d_name); if (testfun(pathbuf)) { if (addpath(pathbuf, res) == -1) { closedir(dp); return -1; } } } closedir(dp); return 0; } // makes a list of ATA or SCSI devices for the DEVICESCAN directive of // smartd. Returns number of devices, or -1 if out of memory. int make_device_names (char*** devlist, const char* name) { struct pathlist res; res.nnames = res.maxnames = 0; res.names = NULL; if (strcmp(name, "SCSI") == 0) { if (grokdir("/dev/rdsk", &res, isscsidev) == -1) return -1; if (grokdir("/dev/rmt", &res, isscsidev) == -1) return -1; } else if (strcmp(name, "ATA") == 0) { if (grokdir("/dev/rdsk", &res, isatadev) == -1) return -1; } else { // non-SCSI and non-ATA case not implemented *devlist=NULL; return 0; } // shrink array to min possible size res.names = static_cast<char**>(realloc(res.names, res.nnames * sizeof (char *))); bytes -= sizeof(char *)*(res.maxnames-res.nnames); // pass list back *devlist = res.names; return res.nnames; } // Like open(). Return integer handle, used by functions below only. // type="ATA" or "SCSI". int deviceopen(const char *pathname, char *type){ if (!strcmp(type,"SCSI")) return open(pathname, O_RDWR | O_NONBLOCK); else if (!strcmp(type,"ATA")) return open(pathname, O_RDONLY | O_NONBLOCK); else return -1; } // Like close(). Acts on handles returned by above function. int deviceclose(int fd){ return close(fd); } #if defined(__sparc) // swap each 2-byte pairs in a sector static void swap_sector(void *p) { int i; char t, *cp = static_cast<char*>(p); for(i = 0; i < 256; i++) { t = cp[0]; cp[0] = cp[1]; cp[1] = t; cp += 2; } } #endif // Interface to ATA devices. See os_linux.c int ata_command_interface(int fd, smart_command_set command, int select, char *data){ #if defined(__sparc) int err; switch (command){ case CHECK_POWER_MODE: /* currently not recognized */ return -1; case READ_VALUES: return smart_read_data(fd, data); case READ_THRESHOLDS: return smart_read_thresholds(fd, data); case READ_LOG: return smart_read_log(fd, select, 1, data); case IDENTIFY: err = ata_identify(fd, data); if(err) return err; swap_sector(static_cast<void*>(data)); return 0; case PIDENTIFY: err = ata_pidentify(fd, data); if(err) return err; swap_sector(static_cast<void*>(data)); return 0; case ENABLE: return smart_enable(fd); case DISABLE: return smart_disable(fd); case STATUS: return smart_status(fd); case AUTO_OFFLINE: return smart_auto_offline(fd, select); case AUTOSAVE: return smart_auto_save(fd, select); case IMMEDIATE_OFFLINE: return smart_immediate_offline(fd, select); case STATUS_CHECK: return smart_status_check(fd); default: pout("Unrecognized command %d in ata_command_interface() of os_solaris.c\n", command); EXIT(1); break; } #else /* __sparc */ ARGUSED(fd); ARGUSED(command); ARGUSED(select); ARGUSED(data); /* Above smart_* routines uses undocumented ioctls of "dada" * driver, which is specific to SPARC Solaris. See * os_solaris_ata.s for further details. x86 Solaris seems not to * provide similar or alternative interface... */ if (printwarning(0)) return -1; #endif return -1; } #include <errno.h> #include <sys/scsi/generic/commands.h> #include <sys/scsi/generic/status.h> #include <sys/scsi/impl/types.h> #include <sys/scsi/impl/uscsi.h> // Interface to SCSI devices. See os_linux.c int do_scsi_cmnd_io(int fd, struct scsi_cmnd_io * iop, int report) { struct uscsi_cmd uscsi; if (report > 0) { int k; const unsigned char * ucp = iop->cmnd; const char * np; np = scsi_get_opcode_name(ucp[0]); pout(" [%s: ", np ? np : "<unknown opcode>"); for (k = 0; k < (int)iop->cmnd_len; ++k) pout("%02x ", ucp[k]); pout("]\n"); if ((report > 1) && (DXFER_TO_DEVICE == iop->dxfer_dir) && (iop->dxferp)) { int trunc = (iop->dxfer_len > 256) ? 1 : 0; pout(" Outgoing data, len=%d%s:\n", (int)iop->dxfer_len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((char *)iop->dxferp, (trunc ? 256 : iop->dxfer_len) , 1); } } memset(&uscsi, 0, sizeof (uscsi)); uscsi.uscsi_cdb = reinterpret_cast<char*>(iop->cmnd); uscsi.uscsi_cdblen = iop->cmnd_len; if (iop->timeout == 0) uscsi.uscsi_timeout = 60; /* 60 seconds */ else uscsi.uscsi_timeout = iop->timeout; uscsi.uscsi_bufaddr = reinterpret_cast<char*>(iop->dxferp); uscsi.uscsi_buflen = iop->dxfer_len; uscsi.uscsi_rqbuf = reinterpret_cast<char*>(iop->sensep); uscsi.uscsi_rqlen = iop->max_sense_len; switch (iop->dxfer_dir) { case DXFER_NONE: case DXFER_FROM_DEVICE: uscsi.uscsi_flags = USCSI_READ; break; case DXFER_TO_DEVICE: uscsi.uscsi_flags = USCSI_WRITE; break; default: return -EINVAL; } uscsi.uscsi_flags |= (USCSI_ISOLATE | USCSI_RQENABLE); if (ioctl(fd, USCSICMD, &uscsi)) { int err = errno; if (! ((EIO == err) && uscsi.uscsi_status)) return -err; /* errno is set to EIO when a non-zero SCSI completion status given */ } iop->scsi_status = uscsi.uscsi_status; iop->resid = uscsi.uscsi_resid; iop->resp_sense_len = iop->max_sense_len - uscsi.uscsi_rqresid; if (report > 0) { int trunc; int len = iop->resp_sense_len; if ((SCSI_STATUS_CHECK_CONDITION == iop->scsi_status) && iop->sensep && (len > 3)) { if ((iop->sensep[0] & 0x7f) > 0x71) pout(" status=%x: [desc] sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[1] & 0xf, iop->sensep[2], iop->sensep[3]); else pout(" status=%x: sense_key=%x asc=%x ascq=%x\n", iop->scsi_status, iop->sensep[2] & 0xf, iop->sensep[12], iop->sensep[13]); if (report > 1) { pout(" >>> Sense buffer, len=%d:\n", len); dStrHex((const char *)iop->sensep, ((len > 252) ? 252 : len) , 1); } } else if (iop->scsi_status) pout(" status=%x\n", iop->scsi_status); if (iop->resid) pout(" dxfer_len=%d, resid=%d\n", iop->dxfer_len, iop->resid); if (report > 1) { len = iop->dxfer_len - iop->resid; if (len > 0) { trunc = (len > 256) ? 1 : 0; pout(" Incoming data, len=%d%s:\n", len, (trunc ? " [only first 256 bytes shown]" : "")); dStrHex((char *)iop->dxferp, (trunc ? 256 : len) , 1); } } } return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_solaris_ata.s�����������������������������������������������������0000644�0000000�0000000�00000031026�12062413436�020252� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������! ! os_solaris_ata.s ! ! Home page of code is: http://smartmontools.sourceforge.net ! ! Copyright (C) 2003-8 SAWADA Keiji <smartmontools-support@lists.sourceforge.net> ! ! This program is free software; you can redistribute it and/or modify ! it under the terms of the GNU General Public License as published by ! the Free Software Foundation; either version 2 of the License, or ! (at your option) any later version. ! ! This program is distributed in the hope that it will be useful, but ! WITHOUT ANY WARRANTY; without even the implied warranty of ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! General Public License for more details. ! ! You should have received a copy of the GNU General Public License ! along with this program; if not, write to the Free Software Foundation, ! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ! ! ! -------------------------------------------------------- ! direct access routines to ATA device under Solaris/SPARC ! -------------------------------------------------------- ! ! Information ! ----------- ! ! In Solaris, programmer can pass SCSI command to target device directly ! by using USCSI ioctl or using "scg" generic SCSI driver. But, such ! method does not exist for ATA devices. ! ! However, I can access Solaris kernel source because I am subscriber of ! Source Foundation Program of Solaris. So, I can find method of ! accessing ATA device directly. The method is to pack command in ! undocumented structure and issue ioctl that appears only in kernel ! source. Yes, that is the same way in using USCSI interface. ! ! But, I met difficulty in disclosing this technique. I have signed NDA ! with Sun that inhibits me not to violate their intellectual property. ! ! Fortunately, Sun allows licensees to publish "Interfaces" if: ! ! (1) he/she treats Solaris code as confidential ! ! (2) and he/she doesn't incorporate Sun's code into his/her code ! ! (3) and disclose enough information to use "Interface" to everyone. ! ! So, I publish that technique in assembly code or object code because: ! ! (1) I believe Sun's intellectural property is not invaded because I ! didn't reveal any struct member and ioctl to non-licensee. ! ! (2) no piece of kernel source is included in this code. ! ! (3) And finally, I publish enough information below in order to use ! this code. ! ! For last reason, please don't remove "Calling Interface" section from ! distribution. ! ! ! Calling Interface ! ----------------- ! ! Name of function/macro presents corresponding S.M.A.R.T. command. ! ! Parameters are described below. ! ! int fd ! ! File descriptor of ATA device. Device would be ! /dev/rdsk/cXtXdXsX. ! ! Device should be raw device serviced by "dada" driver. ATAPI ! CD-ROM/R/RW, DVD-ROM, and so on are not allowed because they are ! serviced by "sd" driver. On x86 Solaris, "cmdk" driver services ! them, this routines doesn't work. ! ! int s ! Select sector for service. For example, this indicates log sector ! number for smart_read_log() function. Probably you need to read ! ATA specification for this parameter. ! ! void *data ! Data going to be read/written. It don't have to be word aligned, ! But data shall points valid user memory space. ! ! This is very tiny routines, but if you feel this insufficient, please ! let me know. ! ! ksw / SAWADA Keiji ! <card_captor@users.sourceforge.net> .file "solaris-ata-in.c" .section ".rodata" .align 8 .LLC0: .asciz "$Id: os_solaris_ata.s 3728 2012-12-13 17:57:50Z chrfranke $" .global os_solaris_ata_s_cvsid .section ".data" .align 4 .type os_solaris_ata_s_cvsid, #object .size os_solaris_ata_s_cvsid, 4 os_solaris_ata_s_cvsid: .long .LLC0 .section ".text" .align 4 .type ata_cmd, #function .proc 04 ata_cmd: !#PROLOGUE# 0 save %sp, -184, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] st %i2, [%fp+76] st %i3, [%fp+80] st %i4, [%fp+84] st %i5, [%fp+88] ld [%fp+92], %g1 st %g1, [%fp-76] ld [%fp-76], %g1 and %g1, 3, %g1 cmp %g1, 0 be .LL2 nop mov -2, %g1 st %g1, [%fp-80] b .LL1 nop .LL2: add %fp, -56, %g1 mov %g1, %o0 mov 0, %o1 mov 36, %o2 call memset, 0 nop add %fp, -72, %g1 mov %g1, %o0 mov 0, %o1 mov 16, %o2 call memset, 0 nop ld [%fp+72], %g1 stb %g1, [%fp-72] mov 1, %g1 stb %g1, [%fp-71] mov 1, %g1 stb %g1, [%fp-70] ld [%fp+76], %g1 stb %g1, [%fp-69] ld [%fp+84], %g1 sll %g1, 9, %g1 st %g1, [%fp-68] ld [%fp+80], %g1 st %g1, [%fp-60] mov 10, %g1 sth %g1, [%fp-52] ld [%fp+88], %g1 cmp %g1, 0 be .LL3 nop mov 14, %g1 st %g1, [%fp-84] b .LL4 nop .LL3: mov 6, %g1 st %g1, [%fp-84] .LL4: ld [%fp-84], %g1 st %g1, [%fp-48] ld [%fp+88], %g1 sll %g1, 9, %g1 st %g1, [%fp-44] ld [%fp+88], %g1 sll %g1, 9, %g1 st %g1, [%fp-40] ld [%fp+88], %g1 cmp %g1, 0 be .LL5 nop ld [%fp+92], %g1 st %g1, [%fp-88] b .LL6 nop .LL5: st %g0, [%fp-88] .LL6: ld [%fp-88], %g1 st %g1, [%fp-36] add %fp, -72, %g1 st %g1, [%fp-32] add %fp, -56, %g1 ld [%fp+68], %o0 mov 1481, %o1 mov %g1, %o2 call ioctl, 0 nop mov %o0, %g1 st %g1, [%fp-80] .LL1: ld [%fp-80], %i0 ret restore .size ata_cmd, .-ata_cmd .align 4 .global ata_identify .type ata_identify, #function .proc 04 ata_identify: !#PROLOGUE# 0 save %sp, -648, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] add %fp, -536, %g1 st %g1, [%sp+92] ld [%fp+68], %o0 mov 236, %o1 mov 0, %o2 mov 0, %o3 mov 1, %o4 mov 1, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] add %fp, -536, %g1 ld [%fp+72], %o0 mov %g1, %o1 mov 512, %o2 call memcpy, 0 nop ld [%fp-20], %g1 cmp %g1, 0 be .LL8 nop mov -1, %g1 st %g1, [%fp-540] b .LL9 nop .LL8: st %g0, [%fp-540] .LL9: ld [%fp-540], %g1 mov %g1, %i0 ret restore .size ata_identify, .-ata_identify .align 4 .global ata_pidentify .type ata_pidentify, #function .proc 04 ata_pidentify: !#PROLOGUE# 0 save %sp, -648, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] add %fp, -536, %g1 st %g1, [%sp+92] ld [%fp+68], %o0 mov 161, %o1 mov 0, %o2 mov 0, %o3 mov 1, %o4 mov 1, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] add %fp, -536, %g1 ld [%fp+72], %o0 mov %g1, %o1 mov 512, %o2 call memcpy, 0 nop ld [%fp-20], %g1 cmp %g1, 0 be .LL11 nop mov -1, %g1 st %g1, [%fp-540] b .LL12 nop .LL11: st %g0, [%fp-540] .LL12: ld [%fp-540], %g1 mov %g1, %i0 ret restore .size ata_pidentify, .-ata_pidentify .align 4 .global smart_read_data .type smart_read_data, #function .proc 04 smart_read_data: !#PROLOGUE# 0 save %sp, -648, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] add %fp, -536, %g1 st %g1, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 208, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 mov 0, %o4 mov 1, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] add %fp, -536, %g1 ld [%fp+72], %o0 mov %g1, %o1 mov 512, %o2 call memcpy, 0 nop ld [%fp-20], %g1 cmp %g1, 0 be .LL14 nop mov -1, %g1 st %g1, [%fp-540] b .LL15 nop .LL14: st %g0, [%fp-540] .LL15: ld [%fp-540], %g1 mov %g1, %i0 ret restore .size smart_read_data, .-smart_read_data .align 4 .global smart_read_thresholds .type smart_read_thresholds, #function .proc 04 smart_read_thresholds: !#PROLOGUE# 0 save %sp, -648, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] add %fp, -536, %g1 st %g1, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 209, %o2 sethi %hi(12733440), %g1 or %g1, 769, %o3 mov 1, %o4 mov 1, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] add %fp, -536, %g1 ld [%fp+72], %o0 mov %g1, %o1 mov 512, %o2 call memcpy, 0 nop ld [%fp-20], %g1 cmp %g1, 0 be .LL17 nop mov -1, %g1 st %g1, [%fp-540] b .LL18 nop .LL17: st %g0, [%fp-540] .LL18: ld [%fp-540], %g1 mov %g1, %i0 ret restore .size smart_read_thresholds, .-smart_read_thresholds .align 4 .global smart_auto_save .type smart_auto_save, #function .proc 04 smart_auto_save: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 210, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 ld [%fp+72], %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL20 nop mov -1, %g1 st %g1, [%fp-24] b .LL21 nop .LL20: st %g0, [%fp-24] .LL21: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_auto_save, .-smart_auto_save .align 4 .global smart_immediate_offline .type smart_immediate_offline, #function .proc 04 smart_immediate_offline: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] ld [%fp+72], %g1 and %g1, 255, %o5 sethi %hi(12733440), %g1 or %g1, 768, %g1 or %o5, %g1, %g1 st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 212, %o2 mov %g1, %o3 mov 0, %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL23 nop mov -1, %g1 st %g1, [%fp-24] b .LL24 nop .LL23: st %g0, [%fp-24] .LL24: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_immediate_offline, .-smart_immediate_offline .align 4 .global smart_read_log .type smart_read_log, #function .proc 04 smart_read_log: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] st %i2, [%fp+76] st %i3, [%fp+80] ld [%fp+72], %g1 and %g1, 255, %o5 sethi %hi(12733440), %g1 or %g1, 768, %g1 or %o5, %g1, %o5 ld [%fp+80], %g1 st %g1, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 213, %o2 mov %o5, %o3 ld [%fp+76], %o4 ld [%fp+76], %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL26 nop mov -1, %g1 st %g1, [%fp-24] b .LL27 nop .LL26: st %g0, [%fp-24] .LL27: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_read_log, .-smart_read_log .align 4 .global smart_enable .type smart_enable, #function .proc 04 smart_enable: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 216, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 mov 0, %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL29 nop mov -1, %g1 st %g1, [%fp-24] b .LL30 nop .LL29: st %g0, [%fp-24] .LL30: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_enable, .-smart_enable .align 4 .global smart_disable .type smart_disable, #function .proc 04 smart_disable: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 217, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 mov 0, %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL32 nop mov -1, %g1 st %g1, [%fp-24] b .LL33 nop .LL32: st %g0, [%fp-24] .LL33: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_disable, .-smart_disable .align 4 .global smart_status .type smart_status, #function .proc 04 smart_status: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 218, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 mov 0, %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL35 nop mov -1, %g1 st %g1, [%fp-24] b .LL36 nop .LL35: st %g0, [%fp-24] .LL36: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_status, .-smart_status .align 4 .global smart_status_check .type smart_status_check, #function .proc 04 smart_status_check: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 218, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 mov 0, %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL38 nop mov -1, %g1 st %g1, [%fp-24] b .LL37 nop .LL38: st %g0, [%fp-24] .LL37: ld [%fp-24], %i0 ret restore .size smart_status_check, .-smart_status_check .align 4 .global smart_auto_offline .type smart_auto_offline, #function .proc 04 smart_auto_offline: !#PROLOGUE# 0 save %sp, -128, %sp !#PROLOGUE# 1 st %i0, [%fp+68] st %i1, [%fp+72] st %g0, [%sp+92] ld [%fp+68], %o0 mov 176, %o1 mov 219, %o2 sethi %hi(12733440), %g1 or %g1, 768, %o3 ld [%fp+72], %o4 mov 0, %o5 call ata_cmd, 0 nop mov %o0, %g1 st %g1, [%fp-20] ld [%fp-20], %g1 cmp %g1, 0 be .LL40 nop mov -1, %g1 st %g1, [%fp-24] b .LL41 nop .LL40: st %g0, [%fp-24] .LL41: ld [%fp-24], %g1 mov %g1, %i0 ret restore .size smart_auto_offline, .-smart_auto_offline .ident "GCC: (GNU) 3.4.2" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/os_qnxnto.cpp��������������������������������������������������������0000644�0000000�0000000�00000055375�12125373277�017645� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� // This is needed for the various HAVE_* macros and PROJECT_* macros. #include "config.h" // These are needed to define prototypes and structures for the // functions defined below #include "int64.h" #include "atacmds.h" #include "scsicmds.h" #include "utility.h" // This is to include whatever structures and prototypes you define in // os_generic.h #include "os_qnxnto.h" #include <errno.h> // Needed by '-V' option (CVS versioning) of smartd/smartctl. You // should have one *_H_CVSID macro appearing below for each file // appearing with #include "*.h" above. Please list these (below) in // alphabetic/dictionary order. const char *os_XXXX_c_cvsid="$Id: os_qnxnto.cpp 3806 2013-03-29 20:17:03Z chrfranke $" \ ATACMDS_H_CVSID CONFIG_H_CVSID INT64_H_CVSID OS_QNXNTO_H_CVSID SCSICMDS_H_CVSID UTILITY_H_CVSID; // This is here to prevent compiler warnings for unused arguments of // functions. #define ARGUSED(x) ((void)(x)) // Please eliminate the following block: both the #include and // the 'unsupported()' function. They are only here to warn // unsuspecting users that their Operating System is not supported! If // you wish, you can use a similar warning mechanism for any of the // functions in this file that you can not (or choose not to) // implement. #ifdef HAVE_UNAME #include <sys/utsname.h> #endif //---------------------------------------------------------------------------------------------- // private Functions static int ata_sense_data(void *sdata,int *error,int *key,int *asc,int *ascq); static int ata_interpret_sense(struct cam_pass_thru *cpt,void *sense,int *status,int rcount); static int ata_pass_thru(int fd,struct cam_pass_thru *pcpt); //---------------------------------------------------------------------------------------------- static void unsupported(){ static int warninggiven; if (!warninggiven) { char *osname; #ifdef HAVE_UNAME struct utsname ostype; uname(&ostype); osname=ostype.sysname; #else osname="host's"; #endif pout("\n" "############################################################################\n" "WARNING: smartmontools has not been ported to the %s Operating System.\n" "Please see the files os_generic.cpp and os_generic.h for porting instructions.\n" "############################################################################\n\n", osname); warninggiven=1; } return; } // End of the 'unsupported()' block that you should eliminate. // print examples for smartctl. You should modify this function so // that the device paths are sensible for your OS, and to eliminate // unsupported commands (eg, 3ware controllers). void print_smartctl_examples(){ printf("=================================================== SMARTCTL EXAMPLES =====\n\n"); #ifdef HAVE_GETOPT_LONG printf( " smartctl -a /dev/hd0 (Prints all SMART information)\n\n" " smartctl --smart=on --offlineauto=on --saveauto=on /dev/hd0\n" " (Enables SMART on first disk)\n\n" " smartctl -t long /dev/hd0 (Executes extended disk self-test)\n\n" " smartctl --attributes --log=selftest --quietmode=errorsonly /dev/hd0\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a --device=3ware,2 /dev/sda\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" ); #else printf( " smartctl -a /dev/hd0 (Prints all SMART information)\n" " smartctl -s on -o on -S on /dev/hd0 (Enables SMART on first disk)\n" " smartctl -t long /dev/hd0 (Executes extended disk self-test)\n" " smartctl -A -l selftest -q errorsonly /dev/hd0\n" " (Prints Self-Test & Attribute errors)\n" " smartctl -a -d 3ware,2 /dev/sda\n" " (Prints all SMART info for 3rd ATA disk on 3ware RAID controller)\n" ); #endif return; } // tries to guess device type given the name (a path). See utility.h // for return values. static const char *net_dev_prefix = "/dev/"; static const char *net_dev_ata_disk = "hd"; int guess_device_type (const char* dev_name) { int len,dev_prefix_len; dev_prefix_len=strlen(net_dev_prefix); if(!dev_name||!(len=strlen(dev_name))) return(CONTROLLER_UNKNOWN); if (!strncmp(net_dev_prefix,dev_name,dev_prefix_len)) { if(len<=dev_prefix_len) return(CONTROLLER_UNKNOWN); else dev_name += dev_prefix_len; } if(!strncmp(net_dev_ata_disk,dev_name,strlen(net_dev_ata_disk))) return(CONTROLLER_ATA); return(CONTROLLER_UNKNOWN); } // makes a list of ATA or SCSI devices for the DEVICESCAN directive of // smartd. Returns number N of devices, or -1 if out of // memory. Allocates N+1 arrays: one of N pointers (devlist); the // other N arrays each contain null-terminated character strings. In // the case N==0, no arrays are allocated because the array of 0 // pointers has zero length, equivalent to calling malloc(0). int make_device_names (char*** devlist, const char* name) { ARGUSED(devlist); ARGUSED(name); unsupported(); return 0; } // Like open(). Return non-negative integer handle, only used by the // functions below. type=="ATA" or "SCSI". If you need to store // extra information about your devices, create a private internal // array within this file (see os_freebsd.cpp for an example). If you // can not open the device (permission denied, does not exist, etc) // set errno as open() does and return <0. int deviceopen(const char *pathname, char *type) { if(!strcmp(type, "ATA")) return(open(pathname,O_RDWR|O_NONBLOCK)); else return(-1); } // Like close(). Acts only on integer handles returned by // deviceopen() above. int deviceclose(int fd) { return(close(fd)); } //---------------------------------------------------------------------------------------------- // Interface to ATA devices. See os_linux.cpp for the cannonical example. // DETAILED DESCRIPTION OF ARGUMENTS // device: is the integer handle provided by deviceopen() // command: defines the different operations, see atacmds.h // select: additional input data IF NEEDED (which log, which type of // self-test). // data: location to write output data, IF NEEDED (1 or 512 bytes). // Note: not all commands use all arguments. // RETURN VALUES (for all commands BUT command==STATUS_CHECK) // -1 if the command failed // 0 if the command succeeded, // RETURN VALUES if command==STATUS_CHECK // -1 if the command failed OR the disk SMART status can't be determined // 0 if the command succeeded and disk SMART status is "OK" // 1 if the command succeeded and disk SMART status is "FAILING" int ata_command_interface(int fd,smart_command_set command,int select,char *data) { struct cam_pass_thru cpt; ATA_SENSE sense; CDB *cdb; int status,rc; memset(&cpt,0x00,sizeof(struct cam_pass_thru)); cdb=(CDB *)cpt.cam_cdb; rc=-1; switch(command) { case READ_VALUES: cpt.cam_flags = CAM_DIR_IN; cpt.cam_cdb_len = 16; cpt.cam_dxfer_len = 512; cpt.cam_data_ptr = (uint32_t)data; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_READ_VALUES; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case READ_THRESHOLDS: cpt.cam_flags = CAM_DIR_IN; cpt.cam_cdb_len = 16; cpt.cam_dxfer_len = 512; cpt.cam_data_ptr = (uint32_t)data; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_READ_THRESHOLDS; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case READ_LOG: cpt.cam_flags = CAM_DIR_IN; cpt.cam_cdb_len = 16; cpt.cam_dxfer_len = 512; cpt.cam_data_ptr = (uint32_t)data; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_READ_LOG_SECTOR; cdb->ata_pass_thru.sector_count= 1; cdb->ata_pass_thru.lba_low = select; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case WRITE_LOG: return(-1); break; case IDENTIFY: cpt.cam_flags = CAM_DIR_IN; cpt.cam_cdb_len = 16; cpt.cam_dxfer_len = 512; cpt.cam_data_ptr = (uint32_t)data; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; cdb->ata_pass_thru.command = ATA_IDENTIFY_DEVICE; break; case PIDENTIFY: cpt.cam_flags = CAM_DIR_IN; cpt.cam_cdb_len = 16; cpt.cam_dxfer_len = 512; cpt.cam_data_ptr = (uint32_t)data; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_PIO_DATA_IN; cdb->ata_pass_thru.flags = ATA_FLG_T_DIR|ATA_FLG_TLEN_STPSIU; cdb->ata_pass_thru.command = ATA_IDENTIFY_PACKET_DEVICE; break; case ENABLE: cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_ENABLE; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case DISABLE: cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_DISABLE; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case AUTO_OFFLINE: // NOTE: According to ATAPI 4 and UP, this command is obsolete cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_AUTO_OFFLINE; cdb->ata_pass_thru.lba_low = select; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case AUTOSAVE: cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_AUTOSAVE; cdb->ata_pass_thru.sector_count= select; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case IMMEDIATE_OFFLINE: // NOTE: According to ATAPI 4 and UP, this command is obsolete cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_IMMEDIATE_OFFLINE; cdb->ata_pass_thru.lba_low = select; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case STATUS_CHECK: // same command, no HDIO in NetBSD case STATUS: cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.flags = ATA_FLG_CK_COND; cdb->ata_pass_thru.command = ATA_SMART_CMD; cdb->ata_pass_thru.features = ATA_SMART_STATUS; cdb->ata_pass_thru.lba_mid = ATA_SMART_LBA_MID_SIG; cdb->ata_pass_thru.lba_high = ATA_SMART_LBA_HI_SIG; break; case CHECK_POWER_MODE: cpt.cam_flags = CAM_DIR_NONE; cpt.cam_cdb_len = 16; cpt.cam_sense_len = sizeof(sense); cpt.cam_sense_ptr = (uint32_t)&sense; cdb->ata_pass_thru.opcode = SC_ATA_PT16; cdb->ata_pass_thru.protocol = ATA_PROTO_DATA_NONE; cdb->ata_pass_thru.flags = ATA_FLG_CK_COND; cdb->ata_pass_thru.command = ATA_CHECK_POWER_MODE; break; default: pout("Unrecognized command %d in ata_command_interface()\n", command); errno=ENOSYS; return(-1); } // execute now if((status=ata_pass_thru(fd,&cpt))==EOK) { rc=status==EOK?0:-1; if(cpt.cam_status!=CAM_REQ_CMP) { ata_interpret_sense(&cpt,&sense,&status,0); if(command==STATUS||command==STATUS_CHECK) rc=((sense.desc.lba_high<<8)|sense.desc.lba_mid)==ATA_SMART_SIG?0:1; } } if(command==CHECK_POWER_MODE) data[0]=cdb->ata_pass_thru.sector_count; // finish return(rc); } //---------------------------------------------------------------------------------------------- // Interface to SCSI devices. See os_linux.c int do_scsi_cmnd_io(int fd,struct scsi_cmnd_io * iop,int report) { ARGUSED(fd); ARGUSED(iop); ARGUSED(report); unsupported(); return -ENOSYS; } //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- static int ata_sense_data(void *sdata,int *error,int *key,int *asc,int *ascq) { SCSI_SENSE *sf; SCSI_SENSE_DESCRIPTOR *sd; sf=(SCSI_SENSE *)sdata; sd=(SCSI_SENSE_DESCRIPTOR *)sdata; *error=sf->error; if(*error & SENSE_DATA_FMT_DESCRIPTOR) { *key=sd->sense & SK_MSK; *asc=sd->asc; *ascq=sd->ascq; } else { *key=sf->sense & SK_MSK; *asc=sf->asc; *ascq=sf->ascq; } return(CAM_SUCCESS); } //---------------------------------------------------------------------------------------------- static int ata_interpret_sense(struct cam_pass_thru *cpt,void *sense,int *status,int rcount) { int retry; int key; int asc; int ascq; int error; *status=EIO; retry=CAM_TRUE; if(cpt->cam_status&CAM_AUTOSNS_VALID) { ata_sense_data(sense,&error,&key,&asc,&ascq); switch(key) { case SK_NO_SENSE: // No sense data (no error) retry=CAM_FALSE; *status=EOK; break; case SK_RECOVERED: // Recovered error switch(asc) { case ASC_ATA_PASS_THRU: switch(ascq) { case ASCQ_ATA_PASS_THRU_INFO_AVAIL: break; default: break; } break; default: break; } retry=CAM_FALSE; *status=EOK; break; case SK_NOT_RDY: // Device not ready *status=EAGAIN; switch(asc) { case ASC_NOT_READY: switch(ascq) { case ASCQ_BECOMING_READY: case ASCQ_CAUSE_NOT_REPORTABLE: default: retry=CAM_FALSE; break; } break; case ASC_MEDIA_NOT_PRESENT: *status=ENXIO; retry=CAM_FALSE; break; } break; case SK_MEDIUM: // Medium error case SK_HARDWARE: // Hardware error retry=CAM_FALSE; *status=EIO; break; case SK_ILLEGAL: // Illegal Request (bad command) retry=CAM_FALSE; *status=EINVAL; break; case SK_UNIT_ATN: // Unit Attention switch(asc) { case ASC_MEDIUM_CHANGED: *status=ESTALE; retry=CAM_FALSE; break; case ASC_BUS_RESET: break; } break; case SK_DATA_PROT: // Data Protect retry=CAM_FALSE; *status=EROFS; break; case SK_VENDOR: // Vendor Specific case SK_CPY_ABORT: // Copy Aborted retry=CAM_FALSE; *status=EIO; break; case SK_CMD_ABORT: // Aborted Command retry=CAM_FALSE; *status=ECANCELED; break; case SK_EQUAL: // Equal case SK_VOL_OFL: // Volume Overflow case SK_MISCMP: // Miscompare case SK_RESERVED: // Reserved break; } if(*status==EOK) { switch(cpt->cam_status&CAM_STATUS_MASK) { case CAM_REQ_CMP_ERR: // CCB request completed with an err retry=CAM_FALSE; *status=EIO; break; case CAM_BUSY: // CAM subsystem is busy *status=EAGAIN; break; case CAM_REQ_INVALID: // CCB request is invalid case CAM_PATH_INVALID: // Path ID supplied is invalid case CAM_DEV_NOT_THERE: // SCSI device not installed/there case CAM_SEL_TIMEOUT: // Target selection timeout case CAM_LUN_INVALID: // LUN supplied is invalid case CAM_TID_INVALID: // Target ID supplied is invalid retry=CAM_FALSE; *status=ENXIO; break; case CAM_CMD_TIMEOUT: // Command timeout *status=rcount?EAGAIN:EIO; break; case CAM_MSG_REJECT_REC: // Message reject received case CAM_SCSI_BUS_RESET: // SCSI bus reset sent/received case CAM_UNCOR_PARITY: // Uncorrectable parity err occurred case CAM_AUTOSENSE_FAIL: // Autosense: Request sense cmd fail case CAM_NO_HBA: // No HBA detected Error case CAM_DATA_RUN_ERR: // Data overrun/underrun error retry=CAM_FALSE; *status=EIO; break; case CAM_UNEXP_BUSFREE: // Unexpected BUS free case CAM_SEQUENCE_FAIL: // Target bus phase sequence failure *status=EIO; break; case CAM_PROVIDE_FAIL: // Unable to provide requ. capability retry=CAM_FALSE; *status=ENOTTY; break; case CAM_CCB_LEN_ERR: // CCB length supplied is inadequate case CAM_BDR_SENT: // A SCSI BDR msg was sent to target case CAM_REQ_TERMIO: // CCB request terminated by the host case CAM_FUNC_NOTAVAIL: // The requ. func is not available case CAM_NO_NEXUS: // Nexus is not established case CAM_IID_INVALID: // The initiator ID is invalid case CAM_CDB_RECVD: // The SCSI CDB has been received retry=CAM_FALSE; *status=EIO; break; case CAM_SCSI_BUSY: // SCSI bus busy *status=EAGAIN; break; } } } return(retry); } //---------------------------------------------------------------------------------------------- static int ata_pass_thru(int fd,struct cam_pass_thru *pcpt) { int icnt; int status; iov_t iov[3]; struct cam_pass_thru cpt; cpt=*pcpt; icnt=1; SETIOV(&iov[0],&cpt,sizeof(cpt)); cpt.cam_timeout=cpt.cam_timeout?cpt.cam_timeout:CAM_TIME_DEFAULT; if(cpt.cam_sense_len) { SETIOV(&iov[1],(void *)cpt.cam_sense_ptr,cpt.cam_sense_len); cpt.cam_sense_ptr=sizeof(cpt); icnt++; } if(cpt.cam_dxfer_len) { SETIOV(&iov[2],(void *)cpt.cam_data_ptr,cpt.cam_dxfer_len); cpt.cam_data_ptr=(paddr_t)sizeof(cpt)+cpt.cam_sense_len; icnt++; } if((status=devctlv(fd,DCMD_CAM_PASS_THRU,icnt,icnt,iov,iov,NULL))) pout("ata_pass_thru devctl: %s\n",strerror(status)); pcpt->cam_status=cpt.cam_status; pcpt->cam_scsi_status=cpt.cam_scsi_status; return(status); } //---------------------------------------------------------------------------------------------- �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/ataprint.h�����������������������������������������������������������0000644�0000000�0000000�00000012675�12166107121�017064� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * ataprint.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); If not, see <http://www.gnu.org/licenses/>. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef ATAPRINT_H_ #define ATAPRINT_H_ #define ATAPRINT_H_CVSID "$Id: ataprint.h 3825 2013-07-06 21:38:25Z samm2 $\n" #include <vector> // Request to dump a GP or SMART log struct ata_log_request { bool gpl; // false: SMART, true: GP unsigned char logaddr; // Log address unsigned page; // First page (sector) unsigned nsectors; // # Sectors ata_log_request() : gpl(false), logaddr(0), page(0), nsectors(0) { } }; // Options for ataPrintMain struct ata_print_options { bool drive_info; int identify_word_level, identify_bit_level; bool smart_check_status; bool smart_general_values; bool smart_vendor_attrib; bool smart_error_log; bool smart_selftest_log; bool smart_selective_selftest_log; bool gp_logdir, smart_logdir; unsigned smart_ext_error_log; unsigned smart_ext_selftest_log; bool retry_error_log, retry_selftest_log; std::vector<ata_log_request> log_requests; bool devstat_all_pages, devstat_ssd_page; std::vector<int> devstat_pages; bool sct_temp_sts, sct_temp_hist; bool sct_erc_get; bool sct_erc_set; unsigned sct_erc_readtime, sct_erc_writetime; bool sataphy, sataphy_reset; bool smart_disable, smart_enable; bool smart_auto_offl_disable, smart_auto_offl_enable; bool smart_auto_save_disable, smart_auto_save_enable; int smart_selftest_type; // OFFLINE_FULL_SCAN, ..., see atacmds.h. -1 for no test bool smart_selftest_force; // Ignore already running test ata_selective_selftest_args smart_selective_args; // Extra args for selective self-test unsigned sct_temp_int; bool sct_temp_int_pers; enum { FMT_BRIEF = 0x01, FMT_HEX_ID = 0x02, FMT_HEX_VAL = 0x04 }; unsigned char output_format; // FMT_* flags firmwarebug_defs firmwarebugs; // -F options bool fix_swapped_id; // Fix swapped ID strings returned by some buggy drivers ata_vendor_attr_defs attribute_defs; // -v options bool ignore_presets; // Ignore presets from drive database bool show_presets; // Show presets and exit unsigned char powermode; // Skip check, if disk in idle or standby mode bool get_set_used; // true if any get/set command is used bool get_aam; // print Automatic Acoustic Management status int set_aam; // disable(-1), enable(1..255->0..254) Automatic Acoustic Management bool get_apm; // print Advanced Power Management status int set_apm; // disable(-1), enable(2..255->1..254) Advanced Power Management bool get_lookahead; // print read look-ahead status int set_lookahead; // disable(-1), enable(1) read look-ahead int set_standby; // set(1..255->0..254) standby timer bool set_standby_now; // set drive to standby bool get_security; // print ATA security status bool set_security_freeze; // Freeze ATA security bool get_wcache; // print write cache status int set_wcache; // disable(-1), enable(1) write cache bool sct_wcache_reorder_get; // print write cache reordering status int sct_wcache_reorder_set; // disable(-1), enable(1) write cache reordering ata_print_options() : drive_info(false), identify_word_level(-1), identify_bit_level(-1), smart_check_status(false), smart_general_values(false), smart_vendor_attrib(false), smart_error_log(false), smart_selftest_log(false), smart_selective_selftest_log(false), gp_logdir(false), smart_logdir(false), smart_ext_error_log(0), smart_ext_selftest_log(0), retry_error_log(false), retry_selftest_log(false), devstat_all_pages(false), devstat_ssd_page(false), sct_temp_sts(false), sct_temp_hist(false), sct_erc_get(false), sct_erc_set(false), sct_erc_readtime(0), sct_erc_writetime(0), sataphy(false), sataphy_reset(false), smart_disable(false), smart_enable(false), smart_auto_offl_disable(false), smart_auto_offl_enable(false), smart_auto_save_disable(false), smart_auto_save_enable(false), smart_selftest_type(-1), smart_selftest_force(false), sct_temp_int(0), sct_temp_int_pers(false), output_format(0), fix_swapped_id(false), ignore_presets(false), show_presets(false), powermode(0), get_set_used(false), get_aam(false), set_aam(0), get_apm(false), set_apm(0), get_lookahead(false), set_lookahead(0), set_standby(0), set_standby_now(false), get_security(false), set_security_freeze(false), get_wcache(false), set_wcache(0), sct_wcache_reorder_get(false), sct_wcache_reorder_set(0) { } }; int ataPrintMain(ata_device * device, const ata_print_options & options); #endif �������������������������������������������������������������������smartmontools-6.2+svn3841.orig/examplescripts/������������������������������������������������������0000755�0000000�0000000�00000000000�12212065522�020121� 5����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/examplescripts/README������������������������������������������������0000644�0000000�0000000�00000003745�12062413436�021016� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Home page: http://smartmontools.sourceforge.net # # $Id: README 3728 2012-12-13 17:57:50Z chrfranke $ # # Copyright (C) 2003-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2, or (at your option) any later # version. # # You should have received a copy of the GNU General Public License (for # example COPYING); if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, 02110-1301 USA. # # This code was originally developed as a Senior Thesis by Michael Cornwell # 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/ This directory contains executable bash scripts, that are intended for use with the -m address -M exec /path/to/an/executable Directive in /etc/smartd.conf. Details about how to use this Directive may be found in the man pages for smartd and smartd.conf. man 8 smartd man 5 smartd.conf should display those pages on your system. If you wish to contribute additional scripts to this collection, please email them to <smartmontools-support@lists.sourceforge.net>, and include a brief description to use below. The files contained in this directory are: Example1: appends values of $SMARTD_* environment variables and the output of smartctl -a to the normal email message, and sends that to the email address listed as the argument to the -m Directive. Example2: Appends output of smartctl -a to the normal email message and sends that to the email address listed as the argument to the -m Directive. Example3: Uses wall(1) to send a warning message to all users, then powers down the machine. Example4: Uses powersave-notify to issue a desktop neutral warning. ���������������������������smartmontools-6.2+svn3841.orig/examplescripts/Example4����������������������������������������������0000755�0000000�0000000�00000000176�11227432427�021541� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh /usr/lib/powersave/powersave-notify "<b>Your hard disk drive is failing!</b> S.M.A.R.T. message: $SMARTD_MESSAGE" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/examplescripts/Example1����������������������������������������������0000755�0000000�0000000�00000003013�11227432427�021527� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # # This is a script from the smartmontools examplescripts/ directory. # It can be used as an argument to the -M exec Directive in # /etc/smartd.conf, in a line like # -m root@localhost -M exec /path/to/this/file # # Please see man 8 smartd or man 5 smartd.conf for further # information. # # $Id: Example1,v 1.7 2004/08/29 02:33:17 ballen4705 Exp $ # Save standard input into a temp file cat > /root/tempfile # Echo command line arguments into temp file echo "Command line argument 1:" >> /root/tempfile echo $1 >> /root/tempfile echo "Command line argument 2:" >> /root/tempfile echo $2 >> /root/tempfile echo "Command line argument 3:" >> /root/tempfile echo $3 >> /root/tempfile # Echo environment variables into a temp file echo "Variables are": >> /root/tempfile echo "$SMARTD_DEVICE" >> /root/tempfile echo "$SMARTD_DEVICESTRING" >> /root/tempfile echo "$SMARTD_DEVICETYPE" >> /root/tempfile echo "$SMARTD_MESSAGE" >> /root/tempfile echo "$SMARTD_FULLMESSAGE" >> /root/tempfile echo "$SMARTD_ADDRESS" >> /root/tempfile echo "$SMARTD_SUBJECT" >> /root/tempfile echo "$SMARTD_TFIRST" >> /root/tempfile echo "$SMARTD_TFIRSTEPOCH" >> /root/tempfile # Run smartctl -a and save output in temp file /usr/sbin/smartctl -a -d $SMARTD_DEVICETYPE $SMARTD_DEVICE >> /root/tempfile # Email the contents of the temp file. Solaris and other OSes # may need to use /bin/mailx not /bin/mail. /bin/mail -s "SMART errors detected on host: `hostname`" $SMARTD_ADDRESS < /root/tempfile # And exit exit 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/examplescripts/Example3����������������������������������������������0000755�0000000�0000000�00000001265�11456324732�021543� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/bash # # This is a script from the smartmontools examplescripts/ directory. # It can be used as an argument to the -M exec Directive in # /etc/smartd.conf, in a line like # -m <nomailer> -M exec /path/to/this/file # # Please see man 8 smartd or man 5 smartd.conf for further # information. # # $Id: Example3 3187 2010-10-16 13:34:18Z chrfranke $ # Warn all users of a problem wall <<EOF Problem detected with disk: $SMARTD_DEVICESTRING Warning message from smartd is: $SMARTD_MESSAGE Shutting down machine in 30 seconds... EOF # Wait half a minute sleep 30 # Power down the machine (uncomment the shutdown command if you really # want to do this!) # /sbin/shutdown -hf now �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/examplescripts/Example2����������������������������������������������0000755�0000000�0000000�00000001322�11227432427�021531� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/bash # # This is a script from the smartmontools examplescripts/ directory. # It can be used as an argument to the -M exec Directive in # /etc/smartd.conf, in a line like # -m root@localhost -M exec /path/to/this/file # # Please see man 8 smartd or man 5 smartd.conf for further # information. # # $Id: Example2,v 1.4 2004/01/07 16:49:56 ballen4705 Exp $ # Save the email message (STDIN) to a file: cat > /root/msg # Append the output of smartctl -a to the message: /usr/sbin/smartctl -a -d $SMARTD_DEVICETYPE $SMARTD_DEVICE >> /root/msg # Now email the message to the user at address ADD. Solaris and # other OSes may need to use /bin/mailx below. /bin/mail -s "$SMARTD_SUBJECT" $SMARTD_ADDRESS < /root/msg ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartctl.h�����������������������������������������������������������0000644�0000000�0000000�00000005701�12062407372�017071� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * smartctl.h * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2008-10 Christian Franke <smartmontools-support@lists.sourceforge.net> * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org> * * 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 Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * 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/ * */ #ifndef SMARTCTL_H_ #define SMARTCTL_H_ #define SMARTCTL_H_CVSID "$Id: smartctl.h 3727 2012-12-13 17:23:06Z samm2 $\n" // Return codes (bitmask) // command line did not parse, or internal error occured in smartctl #define FAILCMD (0x01<<0) // device open failed #define FAILDEV (0x01<<1) // device is in low power mode and -n option requests to exit #define FAILPOWER (0x01<<1) // read device identity (ATA only) failed #define FAILID (0x01<<1) // smart command failed, or ATA identify device structure missing information #define FAILSMART (0x01<<2) // SMART STATUS returned FAILURE #define FAILSTATUS (0x01<<3) // Attributes found <= threshold with prefail=1 #define FAILATTR (0x01<<4) // SMART STATUS returned GOOD but age attributes failed or prefail // attributes have failed in the past #define FAILAGE (0x01<<5) // Device had Errors in the error log #define FAILERR (0x01<<6) // Device had Errors in the self-test log #define FAILLOG (0x01<<7) // Classes of SMART commands. Here 'mandatory' means "Required by the // ATA/ATAPI-5 Specification if the device implements the S.M.A.R.T. // command set." The 'mandatory' S.M.A.R.T. commands are: (1) // Enable/Disable Attribute Autosave, (2) Enable/Disable S.M.A.R.T., // and (3) S.M.A.R.T. Return Status. All others are optional. enum failure_type { OPTIONAL_CMD, MANDATORY_CMD, }; // Globals to set failuretest() policy extern bool failuretest_conservative; extern unsigned char failuretest_permissive; // Compares failure type to policy in effect, and either exits or // simply returns to the calling routine. void failuretest(failure_type type, int returnvalue); // Globals to control printing extern bool printing_is_switchable; extern bool printing_is_off; // Printing control functions inline void print_on() { if (printing_is_switchable) printing_is_off = false; } inline void print_off() { if (printing_is_switchable) printing_is_off = true; } #endif ���������������������������������������������������������������smartmontools-6.2+svn3841.orig/smartd.8.in����������������������������������������������������������0000644�0000000�0000000�00000073753�12120657255�017075� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.ig Copyright (C) 2002-10 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2004-13 Christian Franke <smartmontools-support@lists.sourceforge.net> $Id: smartd.8.in 3799 2013-03-15 17:47:25Z chrfranke $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. You should have received a copy of the GNU General Public License (for example COPYING); If not, see <http://www.gnu.org/licenses/>. This code was originally developed as a Senior Thesis by Michael Cornwell 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 SMARTD 8 CURRENT_SVN_DATE CURRENT_SVN_VERSION CURRENT_SVN_DATE .SH NAME \fBsmartd\fP \- SMART Disk Monitoring Daemon .SH SYNOPSIS .B smartd [options] .\" %IF NOT OS Windows .SH FULL PATH .B /usr/local/sbin/smartd .\" %ENDIF NOT OS Windows .SH PACKAGE VERSION CURRENT_SVN_VERSION CURRENT_SVN_DATE CURRENT_SVN_REV .SH DESCRIPTION .\" %IF NOT OS ALL .\"! [This man page is generated for the OS_MAN_FILTER version of smartmontools. .\"! It does not contain info specific to other platforms.] .\"! .PP .\" %ENDIF NOT OS ALL \fBsmartd\fP is a daemon that monitors the Self-Monitoring, Analysis and Reporting Technology (SMART) system built into most ATA/SATA and SCSI/SAS hard drives and solid-state drives. The purpose of SMART is to monitor the reliability of the hard drive and predict drive failures, and to carry out different types of drive self-tests. This version of \fBsmartd\fP is compatible with ACS-2, ATA8-ACS, ATA/ATAPI-7 and earlier standards (see \fBREFERENCES\fP below). \fBsmartd\fP will attempt to enable SMART monitoring on ATA devices (equivalent to \fBsmartctl -s on\fP) and polls these and SCSI devices every 30 minutes (configurable), logging SMART errors and changes of SMART Attributes via the SYSLOG interface. The default location for these SYSLOG notifications and warnings is system-dependent (typically \fB/var/log/messages\fP or \fB/var/log/syslog\fP). To change this default location, please see the \fB\'-l\'\fP command-line option described below. In addition to logging to a file, \fBsmartd\fP can also be configured to send email warnings if problems are detected. Depending upon the type of problem, you may want to run self-tests on the disk, back up the disk, replace the disk, or use a manufacturer\'s utility to force reallocation of bad or unreadable disk sectors. If disk problems are detected, please see the \fBsmartctl\fP manual page and the \fBsmartmontools\fP web page/FAQ for further guidance. If you send a \fBUSR1\fP signal to \fBsmartd\fP it will immediately check the status of the disks, and then return to polling the disks every 30 minutes. See the \fB\'\-i\'\fP option below for additional details. \fBsmartd\fP can be configured at start-up using the configuration file \fB/usr/local/etc/smartd.conf\fP (Windows: \fBEXEDIR/smartd.conf\fP). If the configuration file is subsequently modified, \fBsmartd\fP can be told to re-read the configuration file by sending it a \fBHUP\fP signal, for example with the command: .fi \fBkillall -HUP smartd\fP. .fi .\" %IF OS Windows (Windows: See NOTES below.) .\" %ENDIF OS Windows On startup, if \fBsmartd\fP finds a syntax error in the configuration file, it will print an error message and then exit. However if \fBsmartd\fP is already running, then is told with a \fBHUP\fP signal to re-read the configuration file, and then find a syntax error in this file, it will print an error message and then continue, ignoring the contents of the (faulty) configuration file, as if the \fBHUP\fP signal had never been received. When \fBsmartd\fP is running in debug mode, the \fBINT\fP signal (normally generated from a shell with CONTROL-C) is treated in the same way as a \fBHUP\fP signal: it makes \fBsmartd\fP reload its configuration file. To exit \fBsmartd\fP use CONTROL-\e .\" %IF OS Windows (Windows: CONTROL-Break). .\" %ENDIF OS Windows On startup, in the absence of the configuration file \fB/usr/local/etc/smartd.conf\fP, the \fBsmartd\fP daemon first scans for all devices that support SMART. The scanning is done as follows: .\" %IF OS Linux .IP \fBLINUX:\fP 9 Examine all entries \fB"/dev/hd[a-t]"\fP for IDE/ATA devices, and \fB"/dev/sd[a-z]"\fP, \fB"/dev/sd[a-c][a-z]"\fP for SCSI or SATA devices. Disks behind RAID controllers are not included. .\" %ENDIF OS Linux .\" %IF OS FreeBSD .IP \fBFREEBSD:\fP 9 Authoritative list of disk devices is obtained from SCSI (CAM) and ATA subsystems. Disks behind RAID controllers are not included. .\" %ENDIF OS FreeBSD .\" %IF OS NetBSD OpenBSD .IP \fBNETBSD/OPENBSD:\fP 9 Authoritative list of disk devices is obtained from sysctl \'hw.disknames\'. .\" %ENDIF OS NetBSD OpenBSD .\" %IF OS Solaris .IP \fBSOLARIS:\fP 9 Examine all entries \fB"/dev/rdsk/*s0"\fP for IDE/ATA and SCSI disk devices, and entries \fB"/dev/rmt/*"\fP for SCSI tape devices. .\" %ENDIF OS Solaris .\" %IF OS Darwin .IP \fBDARWIN:\fP 9 The IOService plane is scanned for ATA block storage devices. .\" %ENDIF OS Darwin .\" %IF OS Windows Cygwin .IP \fBWINDOWS\fP: 9 Examine all entries \fB"/dev/sd[a\-z]"\fP, \fB"/dev/sd[a\-c][a\-z]"\fP and \fB"/dev/sdd[a\-x]"\fP ("\\\\.\\PhysicalDrive[0\-127]") for IDE/(S)ATA and SCSI disk devices. If a 3ware 9000 controller is installed, examine all entries \fB"/dev/sdX,N"\fP for the first logical drive (\'unit\' \fB"/dev/sdX"\fP) and all physical disks (\'ports\' \fB",N"\fP) detected behind this controller. Same for a second controller if present. If directive \'\-d csmi\' or no \'\-d\' directive is specified, examine all entries \fB"/dev/csmi[0\-9],N"\fP for drives behind an Intel ICHxR controller with RST driver. Disks behind Areca RAID controllers are not included. .\" %ENDIF OS Windows Cygwin .PP \fBsmartd\fP then monitors for \fIall\fP possible SMART errors (corresponding to the \fB\'\-a\'\fP Directive in the configuration file; see the \fBsmartd.conf\fP(5) man page). .SH OPTIONS .TP .B \-A PREFIX, \-\-attributelog=PREFIX Writes \fBsmartd\fP attribute information (normalized and raw attribute values) to files \'PREFIX\'\'MODEL\-SERIAL.ata.csv\' or \'PREFIX\'\'VENDOR\-MODEL\-SERIAL.scsi.csv\'. At each check cycle attributes are logged as a line of semicolon separated triplets of the form "attribute-ID;attribute-norm-value;attribute-raw-value;". For SCSI devices error counters and temperature recorded in the form "counter-name;counter-value;" Each line is led by a date string of the form "yyyy-mm-dd HH:MM:SS" (in UTC). .\" %IF ENABLE_ATTRIBUTELOG If this option is not specified, attribute information is written to files \'/usr/local/var/lib/smartmontools/attrlog.MODEL\-SERIAL.ata.csv\'. To disable attribute log files, specify this option with an empty string argument: \'-A ""\'. .\" %ENDIF ENABLE_ATTRIBUTELOG MODEL and SERIAL are build from drive identify information, invalid characters are replaced by underline. If the PREFIX has the form \'/path/dir/\' (e.g. \'/var/lib/smartd/\'), then files \'MODEL\-SERIAL.ata.csv\' are created in directory \'/path/dir\'. If the PREFIX has the form \'/path/name\' (e.g. \'/var/lib/misc/attrlog\-\'), then files 'nameMODEL\-SERIAL.ata.csv' are created in directory '/path/'. The path must be absolute, except if debug mode is enabled. .TP .B \-B [+]FILE, \-\-drivedb=[+]FILE [ATA only] Read the drive database from FILE. The new database replaces the built in database by default. If \'+\' is specified, then the new entries prepend the built in entries. Please see the \fBsmartctl\fP(8) man page for further details. .TP .B \-c FILE, \-\-configfile=FILE Read \fBsmartd\fP configuration Directives from FILE, instead of from the default location \fB/usr/local/etc/smartd.conf\fP (Windows: \fBEXEDIR/smartd.conf\fP). If FILE does \fBnot\fP exist, then \fBsmartd\fP will print an error message and exit with nonzero status. Thus, \'\-c /usr/local/etc/smartd.conf\' can be used to verify the existence of the default configuration file. By using \'\-\' for FILE, the configuration is read from standard input. This is useful for commands like: .nf .B echo /dev/hdb \-m user@home \-M test | smartd \-c \- \-q onecheck .fi to perform quick and simple checks without a configuration file. .\" %IF ENABLE_CAPABILITIES .TP .B \-C, \-\-capabilities Use \fBcapabilities(7)\fP. Warning: Mail notification does not work when used. .\" %ENDIF ENABLE_CAPABILITIES .TP .B \-d, \-\-debug Runs \fBsmartd\fP in "debug" mode. In this mode, it displays status information to STDOUT rather than logging it to SYSLOG and does not \fBfork(2)\fP into the background and detach from the controlling terminal. In this mode, \fBsmartd\fP also prints more verbose information about what it is doing than when operating in "daemon" mode. In this mode, the \fBINT\fP signal (normally generated from a terminal with CONTROL-C) makes \fBsmartd\fP reload its configuration file. Please use CONTROL-\e to exit .\" %IF OS Windows (Windows: CONTROL-Break). [Windows only] The "debug" mode can be toggled by the command \fBsmartd sigusr2\fP. A new console for debug output is opened when debug mode is enabled. .\" %ENDIF OS Windows .TP .B \-D, \-\-showdirectives Prints a list (to STDOUT) of all the possible Directives which may appear in the configuration file /usr/local/etc/smartd.conf, and then exits. These Directives are also described later in this man page. They may appear in the configuration file following the device name. .TP .B \-h, \-\-help, \-\-usage Prints usage message to STDOUT and exits. .TP .B \-i N, \-\-interval=N Sets the interval between disk checks to \fIN\fP seconds, where \fIN\fP is a decimal integer. The minimum allowed value is ten and the maximum is the largest positive integer that can be represented on your system (often 2^31-1). The default is 1800 seconds. Note that the superuser can make \fBsmartd\fP check the status of the disks at any time by sending it the \fBSIGUSR1\fP signal, for example with the command: .nf .B kill -SIGUSR1 <pid> .fi where \fB<pid>\fP is the process id number of \fBsmartd\fP. One may also use: .nf .B killall -USR1 smartd .fi for the same purpose. .fi .\" %IF OS Windows (Windows: See NOTES below.) .\" %ENDIF OS Windows .TP .B \-l FACILITY, \-\-logfacility=FACILITY Uses syslog facility FACILITY to log the messages from \fBsmartd\fP. Here FACILITY is one of \fIlocal0\fP, \fIlocal1\fP, ..., \fIlocal7\fP, or \fIdaemon\fP [default]. If this command-line option is not used, then by default messages from \fBsmartd\fP are logged to the facility \fIdaemon\fP. If you would like to have \fBsmartd\fP messages logged somewhere other than the default location, this can typically be accomplished with (for example) the following steps: .RS 7 .IP \fB[1]\fP 4 Modify the script that starts \fBsmartd\fP to include the \fBsmartd\fP command-line argument \'\-l local3\'. This tells \fBsmartd\fP to log its messages to facility \fBlocal3\fP. .IP \fB[2]\fP 4 Modify the \fBsyslogd\fP configuration file (typically \fB/etc/syslog.conf\fP) by adding a line of the form: .nf \fBlocal3.* /var/log/smartd.log\fP .fi This tells \fBsyslogd\fP to log all the messages from facility \fBlocal3\fP to the designated file: /var/log/smartd.log. .IP \fB[3]\fP 4 Tell \fBsyslogd\fP to re-read its configuration file, typically by sending the \fBsyslogd\fP process a \fBSIGHUP\fP hang-up signal. .IP \fB[4]\fP 4 Start (or restart) the \fBsmartd\fP daemon. .RE .\" The following two lines are a workaround for a man2html bug. Please leave them. .\" They define a non-existent option; useful because man2html can't correctly reset the margins. .TP .B \& For more detailed information, please refer to the man pages for \fBsyslog.conf\fP, \fBsyslogd\fP, and \fBsyslog\fP. You may also want to modify the log rotation configuration files; see the man pages for \fBlogrotate\fP and examine your system\'s /etc/logrotate.conf file. .\" %IF OS Cygwin Cygwin: If no \fBsyslogd\fP is running, the \'\-l\' option has no effect. In this case, all \fBsyslog\fP messages are written to Windows event log. .\" %ENDIF OS Cygwin .\" %IF OS Windows Windows: Some \fBsyslog\fP functionality is implemented internally in \fBsmartd\fP as follows: If no \'\-l\' option (or \'\-l daemon\') is specified, messages are written to Windows event log or to file \fB./smartd.log\fP if event log is not available (access denied). By specifying other values of FACILITY, log output is redirected as follows: \'\-l local0\' to file \fB./smartd.log\fP, \'\-l local1\' to standard output (redirect with \'>\' to any file), \'\-l local2\' to standard error, \'\-l local[3-7]\': to file \fB./smartd[1-5].log\fP. .\" %ENDIF OS Windows .TP .B \-n, \-\-no\-fork Do not fork into background; this is useful when executed from modern init methods like initng, minit or supervise. .\" %IF OS Cygwin On Cygwin, this allows running \fBsmartd\fP as service via cygrunsrv, see NOTES below. .\" %ENDIF OS Cygwin .\" %IF OS Windows On Windows, this option is not available, use \'\-\-service\' instead. .\" %ENDIF OS Windows .TP .B \-p NAME, \-\-pidfile=NAME Writes pidfile \fINAME\fP containing the \fBsmartd\fP Process ID number (PID). To avoid symlink attacks make sure the directory to which pidfile is written is only writable for root. Without this option, or if the \-\-debug option is given, no PID file is written on startup. If \fBsmartd\fP is killed with a maskable signal then the pidfile is removed. .TP .B \-q WHEN, \-\-quit=WHEN Specifies when, if ever, \fBsmartd\fP should exit. The valid arguments are to this option are: .I nodev \- Exit if there are no devices to monitor, or if any errors are found at startup in the configuration file. This is the default. .I errors \- Exit if there are no devices to monitor, or if any errors are found in the configuration file /usr/local/etc/smartd.conf at startup or whenever it is reloaded. .I nodevstartup \- Exit if there are no devices to monitor at startup. But continue to run if no devices are found whenever the configuration file is reloaded. .I never \- Only exit if a fatal error occurs (no remaining system memory, invalid command line arguments). In this mode, even if there are no devices to monitor, or if the configuration file \fB/usr/local/etc/smartd.conf\fP has errors, \fBsmartd\fP will continue to run, waiting to load a configuration file listing valid devices. .I onecheck \- Start \fBsmartd\fP in debug mode, then register devices, then check device\'s SMART status once, and then exit with zero exit status if all of these steps worked correctly. This last option is intended for \'distribution-writers\' who want to create automated scripts to determine whether or not to automatically start up \fBsmartd\fP after installing smartmontools. After starting \fBsmartd\fP with this command-line option, the distribution\'s install scripts should wait a reasonable length of time (say ten seconds). If \fBsmartd\fP has not exited with zero status by that time, the script should send \fBsmartd\fP a SIGTERM or SIGKILL and assume that \fBsmartd\fP will not operate correctly on the host. Conversely, if \fBsmartd\fP exits with zero status, then it is safe to run \fBsmartd\fP in normal daemon mode. If \fBsmartd\fP is unable to monitor any devices or encounters other problems then it will return with non-zero exit status. .I showtests \- Start \fBsmartd\fP in debug mode, then register devices, then write a list of future scheduled self tests to stdout, and then exit with zero exit status if all of these steps worked correctly. Device's SMART status is not checked. This option is intended to test whether the '\-s REGEX' directives in smartd.conf will have the desired effect. The output lists the next test schedules, limited to 5 tests per type and device. This is followed by a summary of all tests of each device within the next 90 days. .TP .B \-r TYPE, \-\-report=TYPE Intended primarily to help .B smartmontools developers understand the behavior of .B smartmontools on non-conforming or poorly-conforming hardware. This option reports details of \fBsmartd\fP transactions with the device. The option can be used multiple times. When used just once, it shows a record of the ioctl() transactions with the device. When used more than once, the detail of these ioctl() transactions are reported in greater detail. The valid arguments to this option are: .I ioctl \- report all ioctl() transactions. .I ataioctl \- report only ioctl() transactions with ATA devices. .I scsiioctl \- report only ioctl() transactions with SCSI devices. Any argument may include a positive integer to specify the level of detail that should be reported. The argument should be followed by a comma then the integer with no spaces. For example, \fIataioctl,2\fP The default level is 1, so \'\-r ataioctl,1\' and \'\-r ataioctl\' are equivalent. .TP .B \-s PREFIX, \-\-savestates=PREFIX Reads/writes \fBsmartd\fP state information from/to files \'PREFIX\'\'MODEL\-SERIAL.ata.state\' or \'PREFIX\'\'VENDOR\-MODEL\-SERIAL.scsi.state\'. This preserves SMART attributes, drive min and max temperatures (\-W directive), info about last sent warning email (\-m directive), and the time of next check of the self-test REGEXP (\-s directive) across boot cycles. .\" %IF ENABLE_SAVESTATES If this option is not specified, state information is maintained in files \'/usr/local/var/lib/smartmontools/smartd.MODEL\-SERIAL.ata.state\' for ATA devices and \'/usr/local/var/lib/smartmontools/smartd.VENDOR\-MODEL\-SERIAL.scsi.state\' for SCSI devices. To disable state files, specify this option with an empty string argument: \'\-s ""\'. .\" %ENDIF ENABLE_SAVESTATES MODEL and SERIAL are build from drive identify information, invalid characters are replaced by underline. If the PREFIX has the form \'/path/dir/\' (e.g. \'/var/lib/smartd/\'), then files \'MODEL\-SERIAL.ata.state\' are created in directory \'/path/dir\'. If the PREFIX has the form \'/path/name\' (e.g. \'/var/lib/misc/smartd\-\'), then files 'nameMODEL\-SERIAL.ata.state' are created in directory '/path/'. The path must be absolute, except if debug mode is enabled. The state information files are read on smartd startup. The files are always (re)written after reading the configuration file, before rereading the configuration file (SIGHUP), before smartd shutdown, and after a check forced by SIGUSR1. After a normal check cycle, a file is only rewritten if an important change (which usually results in a SYSLOG output) occurred. .TP .B \-w PATH, \-\-warnexec=PATH [NEW EXPERIMENTAL SMARTD FEATURE] Run the executable PATH instead of the default script when smartd needs to send warning messages. PATH must point to an executable binary file or script. The default script is .\" %IF NOT OS Windows \fB/usr/local/etc/smartd_warning.sh\fP. .\" %ENDIF NOT OS Windows .\" %IF OS ALL (Windows: EXEDIR/smartd_warning.cmd) .\" %ENDIF OS ALL .\" %IF OS Windows .\"! \fBEXEDIR/smartd_warning.cmd\fP. .\" %ENDIF OS Windows .\" %IF OS Windows .TP .B \-\-service [Windows only] Enables \fBsmartd\fP to run as a Windows service. The option must be specified in the service command line as the first argument. It should not be used from console. See NOTES below for details. .\" %ENDIF OS Windows .TP .B \-V, \-\-version, \-\-license, \-\-copyright Prints version, copyright, license, home page and SVN revision information for your copy of \fBsmartd\fP to STDOUT and then exits. Please include this information if you are reporting bugs or problems. .SH EXAMPLES .B smartd .fi Runs the daemon in forked mode. This is the normal way to run \fBsmartd\fP. Entries are logged to SYSLOG. .B smartd -d -i 30 .fi Run in foreground (debug) mode, checking the disk status every 30 seconds. .B smartd -q onecheck .fi Registers devices, and checks the status of the devices exactly once. The exit status (the bash .B $? variable) will be zero if all went well, and nonzero if no devices were detected or some other problem was encountered. .fi Note that \fBsmartmontools\fP provides a start-up script in \fB/usr/local/etc/rc.d/init.d/smartd\fP which is responsible for starting and stopping the daemon via the normal init interface. Using this script, you can start \fBsmartd\fP by giving the command: .nf .B /usr/local/etc/rc.d/init.d/smartd start .fi and stop it by using the command: .nf .B /usr/local/etc/rc.d/init.d/smartd stop .fi .SH CONFIGURATION The syntax of the smartd.conf(5) file is discussed separately. .SH NOTES \fBsmartd\fP will make log entries at loglevel .B LOG_INFO if the Normalized SMART Attribute values have changed, as reported using the .B \'\-t\', \'\-p\', or .B \'\-u\' Directives. For example: .nf .B \'Device: /dev/hda, SMART Attribute: 194 Temperature_Celsius changed from 94 to 93\' .fi Note that in this message, the value given is the \'Normalized\' not the \'Raw\' Attribute value (the disk temperature in this case is about 22 Celsius). The .B \'-R\' and .B \'-r\' Directives modify this behavior, so that the information is printed with the Raw values as well, for example: .nf .B \'Device: /dev/hda, SMART Attribute: 194 Temperature_Celsius changed from 94 [Raw 22] to 93 [Raw 23]\' .fi Here the Raw values are the actual disk temperatures in Celsius. The way in which the Raw values are printed, and the names under which the Attributes are reported, is governed by the various .B \'-v Num,Description\' Directives described previously. Please see the .B smartctl manual page for further explanation of the differences between Normalized and Raw Attribute values. \fBsmartd\fP will make log entries at loglevel .B LOG_CRIT if a SMART Attribute has failed, for example: .nf .B \'Device: /dev/hdc, Failed SMART Attribute: 5 Reallocated_Sector_Ct\' .fi This loglevel is used for reporting enabled by the .B \'\-H\', \-f\', \'\-l\ selftest\', and .B \'\-l\ error\' Directives. Entries reporting failure of SMART Prefailure Attributes should not be ignored: they mean that the disk is failing. Use the .B smartctl utility to investigate. .\" %IF OS Solaris Under Solaris with the default \fB/etc/syslog.conf\fP configuration, messages below loglevel \fBLOG_NOTICE\fP will \fBnot\fP be recorded. Hence all \fBsmartd\fP messages with loglevel \fBLOG_INFO\fP will be lost. If you want to use the existing daemon facility to log all messages from \fBsmartd\fP, you should change \fB/etc/syslog.conf\fP from: .nf ...;daemon.notice;... /var/adm/messages .fi to read: .nf ...;daemon.info;... /var/adm/messages .fi Alternatively, you can use a local facility to log messages: please see the \fBsmartd\fP '\-l' command-line option described above. .\" %ENDIF OS Solaris .\" %IF OS Cygwin The Cygwin Version of \fBsmartd\fP can be run as a service via the cygrunsrv tool. The start-up script provides Cygwin-specific commands to install and remove the service: .nf .B /usr/local/etc/rc.d/init.d/smartd install [options] .B /usr/local/etc/rc.d/init.d/smartd remove .fi The service can be started and stopped by the start-up script as usual (see \fBEXAMPLES\fP above). .\" %ENDIF OS Cygwin .\" %IF OS Windows On Windows, the log messages are written to the event log or to a file. See documentation of the '\-l FACILITY' option above for details. On Windows, the following built-in commands can be used to control \fBsmartd\fP, if running as a daemon: \'\fBsmartd status\fP\' \- check status \'\fBsmartd stop\fP\' \- stop smartd \'\fBsmartd reload\fP\' \- reread config file \'\fBsmartd restart\fP\' \- restart smartd \'\fBsmartd sigusr1\fP\' \- check disks now \'\fBsmartd sigusr2\fP\' \- toggle debug mode The Windows Version of \fBsmartd\fP has buildin support for services: \'\fBsmartd install [options]\fP\' installs a service named "smartd" (display name "SmartD Service") using the command line \'/INSTALLPATH/smartd.exe \-\-service [options]\'. This also installs smartd.exe as a event message file for the Windows event viewer. \'\fBsmartd remove\fP\' can later be used to remove the service and event message entries from the registry. Upon startup, the smartd service changes the working directory to its own installation path. If smartd.conf and blat.exe are stored in this directory, no \'-c\' option and \'-M exec\' directive is needed. The debug mode (\'\-d\', \'\-q onecheck\') does not work if smartd is running as service. The service can be controlled as usual with Windows commands \'net\' or \'sc\' (\'\fBnet start smartd\fP\', \'\fBnet stop smartd\fP\'). Pausing the service (\'\fBnet pause smartd\fP\') sets the interval between disk checks (\'\-i N\') to infinite. Continuing the paused service (\'\fBnet continue smartd\fP\') resets the interval and rereads the configuration file immediately (like \fBSIGHUP\fP): Continuing a still running service (\'\fBnet continue smartd\fP\' without preceding \'\fBnet pause smartd\fP\') does not reread configuration but checks disks immediately (like \fBSIGUSR1\fP). .\" %ENDIF OS Windows .SH LOG TIMESTAMP TIMEZONE When \fBsmartd\fP makes log entries, these are time-stamped. The time stamps are in the computer's local time zone, which is generally set using either the environment variable \'\fBTZ\fP\' or using a time-zone file such as \fB/etc/localtime\fP. You may wish to change the timezone while \fBsmartd\fP is running (for example, if you carry a laptop to a new time-zone and don't reboot it). Due to a bug in the \fBtzset(3)\fP function of many unix standard C libraries, the time-zone stamps of \fBsmartd\fP might not change. For some systems, \fBsmartd\fP will work around this problem \fIif\fP the time-zone is set using \fB/etc/localtime\fP. The work-around \fIfails\fP if the time-zone is set using the \'\fBTZ\fP\' variable (or a file that it points to). .SH RETURN VALUES The return value (exit status) of \fBsmartd\fP can have the following values: .TP .B 0: Daemon startup successful, or \fBsmartd\fP was killed by a SIGTERM (or in debug mode, a SIGQUIT). .TP .B 1: Commandline did not parse. .TP .B 2: There was a syntax error in the config file. .TP .B 3: Forking the daemon failed. .TP .B 4: Couldn\'t create PID file. .TP .B 5: Config file does not exist (only returned in conjunction with the \'\-c\' option). .TP .B 6: Config file exists, but cannot be read. .TP .B 8: \fBsmartd\fP ran out of memory during startup. .TP .B 9: A compile time constant of\fB smartd\fP was too small. This can be caused by an excessive number of disks, or by lines in \fB /usr/local/etc/smartd.conf\fP that are too long. Please report this problem to \fB smartmontools-support@lists.sourceforge.net\fP. .TP .B 10: An inconsistency was found in \fBsmartd\fP\'s internal data structures. This should never happen. It must be due to either a coding or compiler bug. \fIPlease\fP report such failures to smartmontools-support@lists.sourceforge.net. .TP .B 16: A device explicitly listed in .B /usr/local/etc/smartd.conf can\'t be monitored. .TP .B 17: \fBsmartd\fP didn\'t find any devices to monitor. .TP .B 254: When in daemon mode, \fBsmartd\fP received a SIGINT or SIGQUIT. (Note that in debug mode, SIGINT has the same effect as SIGHUP, and makes \fBsmartd\fP reload its configuration file. SIGQUIT has the same effect as SIGTERM and causes \fBsmartd\fP to exit with zero exit status. .TP .B 132 and above \fBsmartd\fP was killed by a signal that is not explicitly listed above. The exit status is then 128 plus the signal number. For example if \fBsmartd\fP is killed by SIGKILL (signal 9) then the exit status is 137. .PP .SH AUTHORS \fBBruce Allen\fP .br University of Wisconsin \- Milwaukee Physics Department .br \fBChristian Franke\fP (Windows interface, C++ redesign, most enhancements since 2009) .br \fBsmartmontools\-support@lists.sourceforge.net\fP .PP .SH CONTRIBUTORS The following have made large contributions to smartmontools: .nf \fBCasper Dik\fP (Solaris SCSI interface) \fBDouglas Gilbert\fP (SCSI subsystem) \fBGuido Guenther\fP (Autoconf/Automake packaging) \fBGeoffrey Keating\fP (Darwin ATA interface) \fBEduard Martinescu\fP (FreeBSD interface) \fBFr\['e]d\['e]ric L. W. Meunier\fP (Web site and Mailing list) \fBGabriele Pohl\fP (Web site and Wiki, conversion from CVS to SVN) \fBKeiji Sawada\fP (Solaris ATA interface) \fBManfred Schwarb\fP (Drive database) \fBSergey Svishchev\fP (NetBSD interface) \fBDavid Snyder and Sergey Svishchev\fP (OpenBSD interface) \fBPhil Williams\fP (User interface and drive database) \fBShengfeng Zhou\fP (Linux/FreeBSD HighPoint RocketRAID interface) .fi Many other individuals have made smaller contributions and corrections. .PP .SH CREDITS .fi This code was derived from the smartsuite package, written by Michael Cornwell, and from the previous UCSC smartsuite package. It extends these to cover ATA-5 disks. This code was originally developed as a Senior Thesis by Michael Cornwell at the Concurrent Systems Laboratory (now part of the Storage Systems Research Center), Jack Baskin School of Engineering, University of California, Santa Cruz. \fBhttp://ssrc.soe.ucsc.edu/\fP . .SH HOME PAGE FOR SMARTMONTOOLS: .fi Please see the following web site for updates, further documentation, bug reports and patches: \fBhttp://smartmontools.sourceforge.net/\fP .SH SEE ALSO: \fBsmartd.conf\fP(5), \fBsmartctl\fP(8), \fBsyslogd\fP(8), \fBsyslog.conf\fP(5), \fBbadblocks\fP(8), \fBide\-smart\fP(8), \fBregex\fP(7). .SH REFERENCES FOR SMART .fi An introductory article about smartmontools is \fIMonitoring Hard Disks with SMART\fP, by Bruce Allen, Linux Journal, January 2004, pages 74-77. This is \fBhttp://www.linuxjournal.com/article/6983\fP online. If you would like to understand better how SMART works, and what it does, a good place to start is with Sections 4.8 and 6.54 of the first volume of the \'AT Attachment with Packet Interface-7\' (ATA/ATAPI-7) specification Revision 4b. This documents the SMART functionality which the \fBsmartmontools\fP utilities provide access to. .fi The functioning of SMART was originally defined by the SFF-8035i revision 2 and the SFF-8055i revision 1.4 specifications. These are publications of the Small Form Factors (SFF) Committee. Links to these and other documents may be found on the Links page of the \fBsmartmontools\fP Wiki at \fBhttp://sourceforge.net/apps/trac/smartmontools/wiki/Links\fP . .SH SVN ID OF THIS PAGE: $Id: smartd.8.in 3799 2013-03-15 17:47:25Z chrfranke $ ���������������������smartmontools-6.2+svn3841.orig/cciss.h��������������������������������������������������������������0000644�0000000�0000000�00000000354�11227432427�016344� 0����������������������������������������������������������������������������������������������������ustar �root����������������������������root�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef CCISS_H_ #define CCISS_H_ #define CCISS_H_CVSID "$Id: cciss.h,v 1.1 2007/04/01 16:49:46 shattered Exp $\n" int cciss_io_interface(int device, int target, struct scsi_cmnd_io * iop, int report); #endif /* CCISS_H_ */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������